520 lines
16 KiB
Markdown
520 lines
16 KiB
Markdown
# 剧核工厂生产环境部署文档
|
||
|
||
本文档适用于在 Windows 本地构建项目,并一键部署到 Linux AMD64 服务器。
|
||
这里的“一键部署”是指服务器上的 `one_click_deployment.sh` 会一次完成环境初始化、数据库迁移、服务注册、Nginx 和 HTTPS 配置。
|
||
完整发布分为两个明确阶段:本地构建并上传、服务器执行一键部署。`push.bat` 只上传文件,不会自动修改数据库或重启线上服务。
|
||
|
||
## 1. 最短操作流程
|
||
|
||
首次部署,在 Windows 项目根目录执行:
|
||
|
||
```powershell
|
||
.\API\deploy\push.bat root@服务器IP with-env
|
||
ssh root@服务器IP
|
||
sudo bash /opt/juyou_ai/deploy/one_click_deployment.sh
|
||
```
|
||
|
||
日常更新,在 Windows 项目根目录执行:
|
||
|
||
```powershell
|
||
.\API\deploy\push.bat root@服务器IP
|
||
ssh root@服务器IP
|
||
sudo bash /opt/juyou_ai/deploy/one_click_deployment.sh
|
||
```
|
||
|
||
首次部署使用 `with-env`,将本地正式环境配置送到服务器;日常更新不使用 `with-env`,继续保留服务器已有的生产配置。
|
||
上传和服务器部署是两个独立步骤,便于在执行数据库迁移和重启前安排备份与维护窗口。
|
||
|
||
## 2. 固定路径与服务
|
||
|
||
| 项目 | 固定值 |
|
||
| --- | --- |
|
||
| 服务器项目目录 | `/opt/juyou_ai` |
|
||
| API 二进制 | `/opt/juyou_ai/bin/jcf-api` |
|
||
| 部署脚本 | `/opt/juyou_ai/deploy/one_click_deployment.sh` |
|
||
| WEB 静态目录 | `/opt/juyou_ai/static/web` |
|
||
| ADMIN 静态目录 | `/opt/juyou_ai/static/admin` |
|
||
| 数据库迁移目录 | `/opt/juyou_ai/migrations` |
|
||
| systemd 服务名 | `juyou_ai` |
|
||
| API 内部监听地址 | `127.0.0.1:8123` |
|
||
| 生产环境文件 | `/etc/juyou_ai/juyou_ai.env` |
|
||
| 临时环境文件 | `/tmp/juyou_ai.env` |
|
||
| Whisper 离线模型 | `/opt/juyou_ai/models/faster-whisper-small` |
|
||
| Whisper 运行缓存 | `/var/cache/juyou_ai/huggingface` |
|
||
| Nginx 配置 | `/etc/nginx/conf.d/juyou_ai.conf` |
|
||
| SSL 证书目录 | `/etc/nginx/ssl` |
|
||
|
||
API 仅监听服务器本机地址,公网请求统一通过 Nginx 进入。
|
||
|
||
## 3. 首次部署
|
||
|
||
### 3.1 准备本地环境
|
||
|
||
本地需要安装:
|
||
|
||
- Node.js 和 npm
|
||
- Go
|
||
- Python 3;服务器缺少离线模型时,本机还需要 `faster-whisper`
|
||
- tar
|
||
- OpenSSH Client(`ssh`、`scp`)
|
||
|
||
在终端确认命令可用:
|
||
|
||
```powershell
|
||
npm --version
|
||
go version
|
||
python --version
|
||
tar --version
|
||
ssh -V
|
||
```
|
||
|
||
首次在本机下载 Whisper 模型前安装 Python 依赖:
|
||
|
||
```powershell
|
||
python -m pip install faster-whisper==1.2.1
|
||
```
|
||
|
||
`push.bat` 不会自动安装前端依赖。首次构建或 `package-lock.json` 发生变化后,先执行:
|
||
|
||
```powershell
|
||
npm --prefix WEB ci
|
||
npm --prefix ADMIN ci
|
||
```
|
||
|
||
首次部署使用的正式环境配置保存在本地:
|
||
|
||
```text
|
||
API/.env
|
||
```
|
||
|
||
至少确认以下字段使用正式值,不能保留 `replace-with`、`change-me`、`example.com` 或开发环境默认值:
|
||
|
||
```env
|
||
DATABASE_NAME=juchuang_factory
|
||
DATABASE_USER=jcf
|
||
DATABASE_PASSWORD=数据库强密码
|
||
|
||
JWT_SECRET_KEY=随机长密钥
|
||
ADMIN_BOOTSTRAP_USERNAME=admin
|
||
ADMIN_BOOTSTRAP_PASSWORD=管理员初始强密码
|
||
|
||
CONFIG_ENCRYPTION_KEY_VERSION=v1
|
||
CONFIG_ENCRYPTION_KEY=正式加密密钥
|
||
|
||
COS_SECRET_ID=腾讯云子账号SecretId
|
||
COS_SECRET_KEY=腾讯云子账号SecretKey
|
||
COS_BUCKET=juyouai-1451538162
|
||
COS_REGION=ap-chengdu
|
||
COS_ENDPOINT=https://cos.ap-chengdu.myqcloud.com
|
||
COS_PUBLIC_BASE_URL=https://cos.youjuhui.xyz
|
||
```
|
||
|
||
COS 媒体使用独立域名时,还必须在腾讯云控制台进入 **对象存储 COS → 对应存储桶 → 安全管理 → 跨域访问 CORS 设置**,添加以下规则。将域名替换为实际访问 WEB 的域名;多个 WEB 域名需要全部列出。
|
||
|
||
```json
|
||
[
|
||
{
|
||
"AllowedOrigins": [
|
||
"https://juhefactory.com",
|
||
"https://www.juhefactory.com"
|
||
],
|
||
"AllowedMethods": [
|
||
"GET",
|
||
"HEAD"
|
||
],
|
||
"AllowedHeaders": [
|
||
"*"
|
||
],
|
||
"ExposeHeaders": [
|
||
"Accept-Ranges",
|
||
"Content-Length",
|
||
"Content-Range",
|
||
"Content-Type",
|
||
"ETag"
|
||
],
|
||
"MaxAgeSeconds": 3600
|
||
}
|
||
]
|
||
```
|
||
|
||
保存策略后,确认媒体响应包含与当前 WEB 域名一致的 `Access-Control-Allow-Origin`。否则视频可以播放,但浏览器会禁止导出静帧和通过 Blob 直接下载。
|
||
|
||
可以使用以下命令生成随机密钥:
|
||
|
||
```bash
|
||
openssl rand -hex 32
|
||
```
|
||
|
||
### 3.2 准备服务器
|
||
|
||
目标服务器需要满足:
|
||
|
||
- Linux AMD64/x86_64,使用 Debian 或 Ubuntu 最稳妥
|
||
- 使用 systemd
|
||
- SSH 登录用户具备 sudo 权限,推荐使用 root
|
||
- 云安全组及防火墙已放行 TCP 80、443
|
||
- 启用 HTTPS 时,域名已经解析到服务器公网 IP
|
||
|
||
脚本虽然包含 `apt-get`、`dnf` 和 `yum` 的安装分支,但服务账户固定使用 `www-data`。使用非 Debian/Ubuntu 发行版前,需要先确认系统存在 `www-data` 用户和用户组,并确认 PostgreSQL、Redis 的 systemd 服务名与脚本兼容。
|
||
|
||
### 3.3 本地构建并上传
|
||
|
||
在 Windows 项目根目录执行:
|
||
|
||
```powershell
|
||
.\API\deploy\push.bat root@服务器IP with-env
|
||
```
|
||
|
||
示例:
|
||
|
||
```powershell
|
||
.\API\deploy\push.bat root@192.168.1.1 with-env
|
||
```
|
||
|
||
命令完成并显示以下内容后,才进入服务器执行部署:
|
||
|
||
```text
|
||
Deployment push complete.
|
||
```
|
||
|
||
本地上传完成只表示文件已经同步到 `/opt/juyou_ai`,此时不会自动安装依赖、迁移数据库或重启服务。
|
||
|
||
### 3.4 登录服务器并执行首次部署
|
||
|
||
本地另行登录服务器:
|
||
|
||
```powershell
|
||
ssh root@服务器IP
|
||
```
|
||
|
||
服务器上执行:
|
||
|
||
```bash
|
||
bash /opt/juyou_ai/deploy/one_click_deployment.sh
|
||
```
|
||
|
||
如果当前不是 root 用户,执行:
|
||
|
||
```bash
|
||
sudo bash /opt/juyou_ai/deploy/one_click_deployment.sh
|
||
```
|
||
|
||
首次运行会询问两项配置。
|
||
|
||
域名:
|
||
|
||
```text
|
||
juhefactory.com
|
||
```
|
||
|
||
多个域名使用空格分隔:
|
||
|
||
```text
|
||
juhefactory.com www.juhefactory.com
|
||
```
|
||
|
||
不申请 SSL 时输入:
|
||
|
||
```text
|
||
_
|
||
```
|
||
|
||
然后输入 SSL 证书邮箱;不申请 SSL 时直接回车。域名和邮箱会保存到:
|
||
|
||
```text
|
||
/opt/juyou_ai/deploy/.deploy.conf
|
||
```
|
||
|
||
首次部署完成后,将该文件复制到本地:
|
||
|
||
```powershell
|
||
scp root@服务器IP:/opt/juyou_ai/deploy/.deploy.conf .\API\deploy\.deploy.conf
|
||
```
|
||
|
||
后续上传不会携带本地 `.deploy.conf`;服务器会继续使用 `/opt/juyou_ai/deploy/.deploy.conf`,不会被本地文件覆盖。
|
||
|
||
### 3.5 验证首次部署
|
||
|
||
查看服务状态:
|
||
|
||
```bash
|
||
systemctl status juyou_ai --no-pager
|
||
systemctl status nginx --no-pager
|
||
systemctl status postgresql --no-pager
|
||
systemctl status redis-server --no-pager
|
||
```
|
||
|
||
检查 API:
|
||
|
||
```bash
|
||
curl -i http://127.0.0.1:8123/health
|
||
```
|
||
|
||
启用 HTTPS 后检查公网入口:
|
||
|
||
```bash
|
||
curl -i https://你的域名/health
|
||
```
|
||
|
||
页面地址:
|
||
|
||
```text
|
||
https://你的域名/
|
||
https://你的域名/admin/
|
||
```
|
||
|
||
## 4. 更新部署
|
||
|
||
每次更新都分为本地上传和服务器部署两步,不能只执行其中一步。
|
||
|
||
### 4.1 本地重新构建并上传
|
||
|
||
在 Windows 项目根目录执行:
|
||
|
||
```powershell
|
||
.\API\deploy\push.bat root@服务器IP
|
||
```
|
||
|
||
等待出现:
|
||
|
||
```text
|
||
Deployment push complete.
|
||
```
|
||
|
||
### 4.2 服务器应用更新
|
||
|
||
登录服务器:
|
||
|
||
```powershell
|
||
ssh root@服务器IP
|
||
```
|
||
|
||
执行:
|
||
|
||
```bash
|
||
bash /opt/juyou_ai/deploy/one_click_deployment.sh
|
||
```
|
||
|
||
更新部署会:
|
||
|
||
- 继续使用服务器现有的 `/etc/juyou_ai/juyou_ai.env`
|
||
- 执行尚未执行的数据库迁移
|
||
- 更新 systemd 与 Nginx 配置
|
||
- 重启 systemd 服务 `juyou_ai`
|
||
|
||
### 4.3 只更新已上传文件但暂不部署
|
||
|
||
只执行本地 `push.bat` 即可。上传完成后不要在服务器运行 `one_click_deployment.sh`。
|
||
|
||
此时:
|
||
|
||
- `/opt/juyou_ai` 中已经是新文件
|
||
- `/etc/juyou_ai/juyou_ai.env` 保持不变
|
||
- 当前运行中的 API 进程仍可能使用旧二进制
|
||
- 数据库迁移、Nginx 更新和服务重启均未执行
|
||
|
||
需要正式应用更新时,再执行服务器部署命令。
|
||
|
||
## 5. 推送参数说明
|
||
|
||
| 命令 | 是否上传 `API/.env` | 是否自动执行服务器部署 | 使用场景 |
|
||
| --- | --- | --- | --- |
|
||
| `push.bat root@服务器IP` | 否 | 否 | 日常增量更新 |
|
||
| `push.bat root@服务器IP stage-only` | 否 | 否 | 与默认推送行为相同,用于明确表达“只暂存” |
|
||
| `push.bat root@服务器IP with-env` | 是 | 否 | 首次部署或明确替换整套生产环境配置 |
|
||
|
||
三种命令都只负责构建、打包和上传。`stage-only` 当前是语义标记,执行行为与不传第二个参数相同。只有随后在服务器运行 `one_click_deployment.sh`,才会执行迁移、更新服务配置并重启应用。
|
||
|
||
## 6. 常用维护命令
|
||
|
||
服务管理:
|
||
|
||
```bash
|
||
systemctl restart juyou_ai
|
||
systemctl stop juyou_ai
|
||
systemctl start juyou_ai
|
||
systemctl reload nginx
|
||
nginx -t
|
||
```
|
||
|
||
查看 API 日志:
|
||
|
||
```bash
|
||
journalctl -u juyou_ai -f
|
||
journalctl -u juyou_ai -n 200 --no-pager
|
||
```
|
||
|
||
修改域名或证书邮箱:
|
||
|
||
```bash
|
||
nano /opt/juyou_ai/deploy/.deploy.conf
|
||
```
|
||
|
||
也可以删除配置,让下次部署重新询问:
|
||
|
||
```bash
|
||
rm /opt/juyou_ai/deploy/.deploy.conf
|
||
```
|
||
|
||
更新 acme.sh:
|
||
|
||
```bash
|
||
bash /opt/juyou_ai/deploy/update_acme.sh
|
||
```
|
||
|
||
## 7. 备份与故障排查
|
||
|
||
正式执行数据库迁移前应先备份数据库。以下示例中的数据库名必须替换为生产环境 `DATABASE_NAME` 的实际值:
|
||
|
||
```bash
|
||
mkdir -p /opt/juyou_ai/backups
|
||
sudo -u postgres pg_dump -Fc juchuang_factory | tee /opt/juyou_ai/backups/juchuang_factory.dump >/dev/null
|
||
```
|
||
|
||
PostgreSQL:
|
||
|
||
```bash
|
||
systemctl status postgresql --no-pager
|
||
journalctl -u postgresql -n 200 --no-pager
|
||
```
|
||
|
||
Redis:
|
||
|
||
```bash
|
||
systemctl status redis-server --no-pager
|
||
redis-cli ping
|
||
```
|
||
|
||
Nginx:
|
||
|
||
```bash
|
||
nginx -t
|
||
journalctl -u nginx -n 200 --no-pager
|
||
```
|
||
|
||
API:
|
||
|
||
```bash
|
||
systemctl status juyou_ai --no-pager
|
||
journalctl -u juyou_ai -n 200 --no-pager
|
||
ls -l /etc/juyou_ai/juyou_ai.env
|
||
ls -l /opt/juyou_ai/bin/jcf-api
|
||
```
|
||
|
||
如果部署提示环境字段缺失、格式错误或仍为示例值,修改本地 `API/.env`,重新执行 `push.bat`,然后再次在服务器运行部署脚本。
|
||
|
||
如果数据库迁移失败,应先核对数据库实际结构和 `jcf_schema_migrations`,不得通过手工插入迁移记录直接绕过错误。数据库迁移不会自动回滚。
|
||
|
||
## 8. 自动化部署流程说明
|
||
|
||
本节用于解释脚本内部做了什么。日常操作只需要按“首次部署”或“更新部署”章节执行命令。
|
||
|
||
### 8.1 `push.bat` 的本地流程
|
||
|
||
1. 检查目标 SSH 地址;仅在使用 `with-env` 时检查本地 `API/.env` 是否存在。
|
||
2. 通过 SSH 检查服务器是否已有完整的 Whisper `small` 模型。缺少时,本机运行 `download_whisper_model.py` 下载模型,并把 `models/` 加入本次上传包。
|
||
3. 执行 `npm --prefix WEB run build`,类型检查通过后将 WEB 输出到 `API/static/web`。
|
||
4. 执行 `npm --prefix ADMIN run build`,类型检查通过后将 ADMIN 输出到 `API/static/admin`。
|
||
5. 使用 `GOOS=linux`、`GOARCH=amd64`、`-trimpath` 和裁剪调试信息的链接参数,编译 `API/bin/jcf-api`。
|
||
6. 创建本机临时压缩包,包含:
|
||
|
||
```text
|
||
bin/
|
||
static/
|
||
deploy/
|
||
migrations/
|
||
acme/
|
||
workers/
|
||
models/ # 仅服务器缺少离线模型时包含
|
||
.env # 仅使用 with-env 时包含
|
||
```
|
||
|
||
7. 使用 SCP 将压缩包上传到 `/tmp/juyou-deploy.tar.gz`。
|
||
8. 使用 SSH 在服务器的 `/tmp/juyou-deploy-work` 临时目录解包。
|
||
9. 默认删除可能残留的 `/tmp/juyou_ai.env`;使用 `with-env` 时才将 `.env` 安装为权限 `600` 的 `/tmp/juyou_ai.env`,并从项目文件中删除 `.env`。
|
||
10. 服务器存在 `rsync` 时,以 `--delete` 将发布文件同步到 `/opt/juyou_ai`;不存在时使用 `cp -a` 覆盖复制。
|
||
11. 删除服务器临时解包目录和压缩包。
|
||
12. 删除本机临时压缩包。
|
||
|
||
同步时保留以下服务器内容:
|
||
|
||
```text
|
||
/opt/juyou_ai/media/
|
||
/opt/juyou_ai/backups/
|
||
/opt/juyou_ai/models/
|
||
```
|
||
|
||
`models/` 默认不会被 `rsync --delete` 清理;仅当服务器缺少完整模型且本次压缩包含有模型时,才会单独同步模型内容。
|
||
|
||
`/opt/juyou_ai/deploy/.deploy.conf` 仅在服务器首次运行部署脚本时生成;上传包会排除本地 `.deploy.conf`,后续部署不会覆盖服务器配置。
|
||
|
||
`.go` 源码、测试代码、`cmd`、`internal`、`tools`、`media` 和 `backups` 不会进入上传包;运行时需要的 `workers` 会进入上传包。
|
||
|
||
### 8.2 `one_click_deployment.sh` 的服务器流程
|
||
|
||
1. 首次运行时只从 JuYouAI 自己的 Nginx 配置恢复域名;没有该配置时询问域名。仅复用输入域名对应的证书和私钥,不扫描其他项目的证书,并保存 `.deploy.conf`。
|
||
2. 使用 `with-env` 时检测 `/tmp/juyou_ai.env` 并将其作为本次环境配置来源,否则继续使用服务器生产环境文件。
|
||
3. 调用 `deploy_with_ssl.sh` 执行正式部署。
|
||
|
||
### 8.3 `deploy_with_ssl.sh` 和 `prepare_server.sh` 的服务器流程
|
||
|
||
1. 本机执行 `push.bat` 时检查服务器是否已有 Whisper 模型;首次部署会在本机下载并上传到 `/opt/juyou_ai/models/faster-whisper-small`。服务器不访问 Hugging Face。
|
||
2. 安装 sudo、Nginx、PostgreSQL、Redis、FFmpeg、curl、socat、ca-certificates、openssl、Python 3 和 pip;缺少时安装 `faster-whisper 1.2.1`。
|
||
3. 启用并启动 PostgreSQL、Redis 和 Nginx。
|
||
4. 存在 `/tmp/juyou_ai.env` 时将其安装到 `/etc/juyou_ai/juyou_ai.env`;否则保留现有生产环境文件,权限保持 `root:root`、`600`。
|
||
5. 将生产环境标准化为:
|
||
|
||
```env
|
||
APP_ENV=production
|
||
DEBUG=false
|
||
SERVER_ADDRESS=127.0.0.1:8123
|
||
DATABASE_HOST=127.0.0.1
|
||
DATABASE_PORT=5432
|
||
DATABASE_URL=
|
||
REDIS_HOST=127.0.0.1
|
||
REDIS_PORT=6379
|
||
CORS_ORIGINS=根据部署域名生成
|
||
FFMPEG_PATH=ffmpeg
|
||
FFPROBE_PATH=ffprobe
|
||
PYTHON_PATH=python3
|
||
ASR_SCRIPT_PATH=/opt/juyou_ai/workers/transcribe.py
|
||
JCF_ASR_CACHE_DIR=/var/cache/juyou_ai
|
||
HF_HOME=/var/cache/juyou_ai/huggingface
|
||
FASTER_WHISPER_MODEL_PATH=/opt/juyou_ai/models/faster-whisper-small
|
||
```
|
||
|
||
6. 校验离线 Whisper 模型、数据库、JWT、管理员、配置加密和 COS 等必填配置。
|
||
7. 创建或更新 PostgreSQL 用户和数据库,配置本机认证。
|
||
8. 按文件名顺序执行 `/opt/juyou_ai/migrations/*.up.sql`,并记录到 `jcf_schema_migrations`。
|
||
9. 创建或更新 `/etc/systemd/system/juyou_ai.service`:
|
||
|
||
```ini
|
||
[Service]
|
||
User=www-data
|
||
Group=www-data
|
||
WorkingDirectory=/opt/juyou_ai
|
||
EnvironmentFile=/etc/juyou_ai/juyou_ai.env
|
||
CacheDirectory=juyou_ai
|
||
ExecStart=/opt/juyou_ai/bin/jcf-api
|
||
Restart=always
|
||
RestartSec=3
|
||
```
|
||
|
||
10. 配置 Nginx:`/api/` 和健康检查路径代理到 `127.0.0.1:8123`,`/admin/` 提供 ADMIN 静态文件,其他路径提供 WEB 静态文件,上传体积上限为 2 GiB。
|
||
11. 配置域名且已有该域名的证书时直接复用;没有证书但填写邮箱时,先创建 HTTP 验证站点,再使用 acme.sh 通过 HTTP-01 申请并安装 HTTPS 证书;域名填 `_`,或没有证书且未填写邮箱时使用 HTTP。
|
||
12. 启用 HTTPS 时把 80 端口请求重定向到 HTTPS,并允许 TLS 1.2、TLS 1.3。
|
||
13. 执行 `nginx -t`,配置检查成功后重载 Nginx。
|
||
14. 重启 systemd 服务 `juyou_ai`。
|
||
15. 部署成功后删除 `/tmp/juyou_ai.env`。
|
||
|
||
如果部署中途失败,临时环境文件可能保留,以便排查并重新执行部署;问题解决并部署成功后会自动清理。
|
||
|
||
### 8.4 重复执行与失败边界
|
||
|
||
- 脚本使用 `set -euo pipefail`,关键命令失败时会立即退出。
|
||
- 已有 PostgreSQL 用户会更新密码,已有数据库不会重复创建。
|
||
- 已记录在 `jcf_schema_migrations` 的迁移会跳过,未记录迁移按文件名顺序执行。
|
||
- systemd 和 Nginx 配置每次都会按当前发布内容重新生成。
|
||
- 已保存的域名、证书邮箱和匹配域名的现有证书会复用。
|
||
- 部署脚本不会自动恢复旧二进制,也不会自动回滚已经成功执行的数据库迁移。发布前必须自行完成数据库备份;需要应用级回滚时,应重新上传兼容当前数据库结构的旧版本并再次部署。
|