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