# 5700U 局域网服务器部署执行单 本文用于让 Codex 在已经拉取本仓库的 Ryzen 7 5700U Linux 主机上,完成 Rust API 与中文 FunASR 的 Docker 化部署。它既是部署约束,也是验收清单。 ## 使用方式 在 5700U 主机的仓库根目录更新代码: ```bash git pull --ff-only ``` 然后在仓库根目录启动 Codex 新会话,发送: ```text 请完整阅读 DEPLOY_5700U.md,把它作为本次任务的执行约束。请实际完成部署、测试和验收,不要只返回操作步骤。遇到可自行诊断的问题请继续排查;只有缺少数据库凭据、sudo 权限或会改变既有数据的决定时才停下来问我。 ``` ## 固定部署目标 目标主机资源: - CPU:AMD Ryzen 7 5700U,8 核 16 线程。 - GPU:AMD 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` 服务。 - - - ## 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`,停止并让用户在主机本地安全填写。不得要求用户在聊天中粘贴密码,也不得在日志或最终报告中输出完整连接串。 ### 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` 两个 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 ``` 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` 只从未提交的 `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" } ``` 还要验证: 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 密钥或其他敏感信息。部署文件验证通过后保留改动供用户审查,不要自行提交或推送,除非用户在该会话中明确要求。