Files
teaching-feedback-assistant/DEPLOY_5700U.md

245 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 5700U 局域网服务器部署执行单
本文用于让 Codex 在已经拉取本仓库的 Ryzen 7 5700U Linux 主机上,完成 Rust API 与中文 FunASR 的 Docker 化部署。它既是部署约束,也是验收清单。
## 使用方式
在 5700U 主机的仓库根目录更新代码:
```bash
git pull --ff-only
```
然后在仓库根目录启动 Codex 新会话,发送:
```text
请完整阅读 DEPLOY_5700U.md把它作为本次任务的执行约束。请实际完成部署、测试和验收不要只返回操作步骤。遇到可自行诊断的问题请继续排查只有缺少数据库凭据、sudo 权限或会改变既有数据的决定时才停下来问我。
```
## 固定部署目标
目标主机资源:
- CPUAMD Ryzen 7 5700U8 核 16 线程。
- GPUAMD Lucienne 集显,本方案不使用 GPU、不安装 ROCm。
- 内存64 GB。
- 网络Mac mini、小程序测试手机和 5700U 主机位于可信局域网。
服务拓扑:
```text
Mac mini / 测试手机
-> http://<5700U局域网IP>:39180
-> Rust API 容器(容器内 0.0.0.0:8080
-> 现有远程 PostgreSQL
-> http://funasr:10095仅 Docker 内部网络)
-> FunASR CPU 容器
```
必须满足:
1. Rust API 和 FunASR 都使用 Docker 部署,由同一份生产 Compose 文件管理。
2. 宿主机只向可信局域网开放 TCP `39180`,映射到 Rust API 容器的 `8080`
3. FunASR 的 `10095` 不发布到宿主机,只允许 Compose 内部网络访问。
4. PostgreSQL 继续使用已有的远程 `DATABASE_URL`,不得新增 PostgreSQL 容器。
5. 使用 CPU 版 PyTorch、Paraformer 中文模型、FSMN-VAD 和中文标点模型。
6. 模型缓存和录音文件使用持久化卷,重建容器不得丢失。
7. 所有业务容器设置 `restart: unless-stopped`Docker 服务设置为开机启动。
8. 不再为 Rust API 创建 systemd 单元;进程生命周期统一由 Docker 管理。
9. 不把 `.env`、数据库密码、模型、录音、Docker 卷或构建产物提交到 Git。
10. 局域网调试使用 HTTP正式接入微信合法域名时仍必须另行配置 HTTPS。
## 并发策略
当前 Python 服务在一个进程中共享一个 FunASR `AutoModel`。FunASR 官方没有承诺同一个 Python `AutoModel` 实例可以被多个线程安全地同时调用,因此不能只把 `ASR_MAX_CONCURRENCY``1` 改为更大的值。
初次部署使用以下安全配置:
```text
Uvicorn worker 数量1
ASR_MAX_CONCURRENCY=1
ASR_WORKER_CONCURRENCY=1
DATABASE_MAX_CONNECTIONS=5
```
一条 8 分钟录音在现有 CPU 实测中约 45 秒完成,单 worker 已明显快于录音产生速度。单教师或少量并发时通常不会形成队列积压。
需要提高吞吐时,使用独立模型进程,而不是并发调用同一个模型实例:
```text
Uvicorn worker 数量2
每个进程 ASR_MAX_CONCURRENCY=1
ASR_WORKER_CONCURRENCY=2
DATABASE_MAX_CONNECTIONS=10
```
每个 Uvicorn worker 会加载自己的模型副本。按照现有实测估算,两个模型进程可能占用约 6 GB 常驻内存,并在推理时出现接近 10 GB 的合计峰值64 GB 主机有足够余量,但仍需实测。
并发升级规则:
1. 首次启动必须先用一个 Uvicorn worker 完成模型下载和健康检查。
2. 使用真实的 8 分钟课堂录音验证单进程结果。
3. 只有队列持续积压时,才切换为两个 Uvicorn worker并同步把 Rust worker 调为 `2`
4. 对相同录音比较转写内容、耗时、失败率,并观察 `docker stats`、系统负载和容器重启次数。
5. 如果出现随机推理错误、转写质量变化、持续交换或整体耗时反而增加,立即退回 `1/1`
6. 不得直接升到 `3``4`。只有两个独立模型进程稳定压测后,才逐级增加进程和 Rust worker。
参考FunASR 普通 Python 示例按顺序调用 `AutoModel.generate()`;明确提供多线程和动态批处理能力的是专用 runtime而不是当前 Python `AutoModel` 服务。
- <https://github.com/modelscope/FunASR/blob/main/docs/tutorial/README.md>
- <https://github.com/modelscope/FunASR/blob/main/docs/tutorial/Tables.md>
- <https://github.com/modelscope/FunASR/blob/main/runtime/readme.md>
## Codex 执行约束
### 1. 先检查,不覆盖
开始时必须:
1. 阅读 `README.md``DEBUG_GUIDE.md``server/.env.example``server/API.md``asr-service/README.md``compose.asr.yml` 和相关源码。
2. 检查 `git status`。保留并兼容用户已有改动,不得重置或覆盖。
3. 检查 Linux 发行版、`x86_64` 架构、CPU、内存、磁盘、局域网 IP、时区和时间同步。
4. 检查 Docker Engine、Docker Compose 插件、Docker 服务自启动和当前用户权限。
5. 检查 TCP `39180` 是否空闲,确认远程 PostgreSQL 地址可达。
6. 至少保留 20 GB 可用磁盘空间供镜像、Rust 构建层、约 2.1 GB 模型缓存和录音使用。
7. 宿主机不需要安装 Rust、Python、PyTorch、FunASR 或 ffmpeg这些依赖应全部位于镜像内。
如果缺少 `DATABASE_URL``WECHAT_APP_ID``WECHAT_APP_SECRET`,停止并让用户在主机本地安全填写。不得要求用户在聊天中粘贴密码或 AppSecret也不得在日志或最终报告中输出敏感值。
### 2. 创建生产部署文件
检查现有文件后,按仓库模式创建最少且清晰的部署文件。预期至少包括:
- `server/Dockerfile`Rust 多阶段 release 构建。
- `server/.dockerignore`:排除 `.env``target/``data/` 和无关文件。
- `compose.deploy.yml`统一管理迁移、Rust API 和 FunASR。
不要把本地开发用的 `compose.asr.yml` 改造成生产文件,避免破坏 Mac mini 的现有调试方式。
Rust 镜像要求:
1. builder 阶段使用与 `server/Cargo.toml``rust-version` 兼容的 Rust 工具链。
2. 构建 `teaching-feedback-api``migrate``migrate-user-owner` 三个 release 二进制。
3. runtime 阶段只包含运行所需 CA 证书、健康检查工具和二进制,不携带编译器与源码。
4. 尽可能使用非 root 用户运行 API并确保录音卷目录可写。
5. 不把 `server/.env` 复制进镜像。
生产 Compose 至少包含:
- `funasr`:复用 `asr-service/Dockerfile`CPU 模式,模型缓存卷,内部健康检查,不设置宿主机 `ports`
- `migrate`:复用 Rust API 镜像,运行迁移二进制,成功后正常退出;迁移必须可重复执行。
- `api`:等待迁移成功和 FunASR 健康后启动,发布 `39180:8080`,挂载录音持久化卷。
容器环境覆盖值:
```env
HOST=0.0.0.0
PORT=8080
AUDIO_STORAGE_DIR=/data/audio
ASR_PROVIDER=local
LOCAL_ASR_URL=http://funasr:10095
ASR_REQUEST_TIMEOUT_SECONDS=1800
ASR_WORKER_CONCURRENCY=1
ASR_JOB_LEASE_SECONDS=3600
DATABASE_MAX_CONNECTIONS=5
AUTH_SESSION_TTL_DAYS=30
ALLOW_DEVELOPMENT_USER_HEADER=false
```
FunASR 初始配置:
```env
ASR_MODEL=paraformer-zh
ASR_VAD_MODEL=fsmn-vad
ASR_PUNC_MODEL=ct-punc
ASR_DEVICE=cpu
ASR_MAX_CONCURRENCY=1
ASR_BATCH_SIZE_SECONDS=300
MODELSCOPE_CACHE=/models
```
`DATABASE_URL``WECHAT_APP_SECRET` 只从未提交的 `server/.env` 或同等安全的 Compose secret/env 文件注入。设置文件权限为仅部署用户可读,并确认 `git check-ignore` 能匹配该文件。
### 3. 构建和启动
实际执行以下工作,不要只打印命令:
1. 对新建的 Dockerfile 和 Compose 文件执行语法及配置校验。
2. 在容器或临时构建阶段运行 Rust 格式检查、测试和严格 Clippy。
3. 构建生产镜像。
4. 首次以单 FunASR worker 启动,等待模型下载完成;网络较慢时应继续观察日志,不要因等待时间长提前判定失败。
5. 执行数据库迁移,确认输出 `PostgreSQL migrations completed`
6. 启动 Rust API并检查容器健康状态和重启次数。
7. 确保 Docker daemon 开机启动;不要通过 systemd 重复管理单个 API 进程。
部署命令最终应收敛为类似:
```bash
docker compose -f compose.deploy.yml build
docker compose -f compose.deploy.yml up -d
docker compose -f compose.deploy.yml ps
```
具体命令应以最终创建的 Compose 文件为准。
### 4. 网络和防火墙
1. FunASR 不得出现在 `docker ps` 的宿主机端口映射中。
2. Rust API 只映射宿主机 `39180`,容器内继续使用 `8080`
3. 如果主机启用了防火墙,只允许当前可信局域网 CIDR 访问 TCP `39180`
4. 修改防火墙前必须识别当前 SSH 来源和规则,不能导致 SSH 连接中断。
5. 不向公网开放 PostgreSQL、`10095``39180`
### 5. 验收
必须完成以下验证:
```bash
curl http://127.0.0.1:39180/health
curl http://<5700U局域网IP>:39180/health
```
Rust 健康检查应包含:
```json
{
"status": "ok",
"database_configured": true,
"speech_configured": true,
"speech_available": true,
"speech_provider": "local-funasr",
"wechat_auth_configured": true,
"development_auth_enabled": false
}
```
还要验证:
1. 从 FunASR 容器内部访问 `/health` 成功。
2. 从 Rust API 容器访问 `http://funasr:10095/health` 成功。
3. 宿主机和另一台局域网设备都无法直接访问 `10095`
4. 使用一段真实中文音频调用转录链路,确认文字可写入数据库。
5. 重启容器组后健康检查恢复,模型不重复下载,录音文件仍存在。
6. `docker stats` 中内存、CPU 和磁盘无异常,容器没有重启循环。
7. 小程序“我的”页面可保存 `http://<5700U局域网IP>:39180` 并通过服务检查。
如果没有可用测试音频,应明确报告这一项未验证,不能用健康检查代替真实转录验收。
### 6. 完成报告
完成后向用户报告:
- 实际局域网 IP 和小程序 API 地址。
- 新增或修改的部署文件及 `git diff --stat`
- 三个 Compose 服务的状态和镜像版本。
- 数据库迁移结果。
- Rust API 与 FunASR 健康检查结果。
- 微信登录是否已配置,以及生产开发身份兼容是否关闭。
- 实际并发配置,以及是否完成真实录音压测。
- 模型缓存卷和录音卷名称、占用空间及备份方式。
- 查看日志、启动、停止、重启、更新代码和重新部署的准确命令。
- 防火墙规则是否修改。
- 尚未完成的验证或残余风险。
不得在报告中输出数据库密码、完整 `DATABASE_URL`、API 密钥或其他敏感信息。部署文件验证通过后保留改动供用户审查,不要自行提交或推送,除非用户在该会话中明确要求。