基于Docker的ChatTTS文字转语音服务部署实战:指定端口8666的完整指南
摘要:把 ChatTTS 塞进容器里,再让它乖乖蹲在 8666 端口,省得跟本地 80、8080 抢地盘。本文用“AI 辅助开发”视角,把踩坑、调优、排错全过程拆成 7 个可复制的步骤,照着敲命令就能跑起来。
1. ChatTTS 是什么?能干嘛?
- 开源中英双语 TTS,音色自然,支持笑声、停顿、语气词,适合给 AI 客服、视频解说、无障碍朗读“张嘴说话”。
- 模型分两层:文本→语义 token(GPT)、token→梅尔谱(Vocoder),官方权重 1.2 GB,一张 6G 显存卡就能跑。
- 社区已封装好 gradio_demo.py,启动后默认监听 8080,但多人协作时端口冲突最闹心,于是有了本文“指定 8666”的容器化方案。
2. 传统裸机部署的 4 个痛点
- 依赖地狱:PyTorch、CUDA、espeak、phonemizer 版本对不上,分分钟“libcudart.so.11 找不到”。
- 端口抢占:本地已有 Jenkins、Node 服务,8080 被占,改端口得进代码搜
--server-port,升级后又还原。 - 资源裸奔:模型吃满 GPU,同事跑训练脚本直接 OOM,把系统拖带崩。
- 环境漂移:测试机 A 能跑,线上机 B 缺 ffmpeg,排错两小时,上线延期。
- Docker 化带来的 3 大爽点
- 一次构建,随处复现:把 3 GB 的依赖、权重、Python 版本全锁进镜像,CI/CD 拉下来就能跑。
- 端口映射自由:容器内依旧 8080,宿主机爱映射 8666、9666 随你,升级镜像端口配置不动。
- 资源可限:通过
--gpus device=0 --memory=4g --cpus=2直接给容器戴“紧箍”,再也不怕隔壁同事抢卡。
4. 完整 Dockerfile 逐行拆解
下面这份 Dockerfile 基于官方推荐镜像pytorch/pytorch:2.1.0-cuda11.8-cudnn8-runtime,把 ChatTTS 权重、依赖、启动脚本一次打包,镜像体积≈5.1 GB,GPU/CPU 双兼容。
# 基于官方 CUDA 镜像,省去自己装驱动 FROM pytorch/pytorch:2.1.0-cuda11.8-cudnn8-runtime # 换国内源,加速 apt & pip RUN sed -i 's@archive.ubuntu.com@mirrors.aliyun.com@g' /etc/apt/sources.list && \ apt-get update && apt-get install -y --no-install-recommends \ espeak espeak-data libespeak1 libespeak-dev \ ffmpeg git build-essential && \ rm -rf /var/lib/apt/lists/* # 工作目录 WORKDIR /app # 把 requirements 提前复制,利用缓存层 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple # 克隆官方仓库(也可 COPY 本地代码) RUN git clone https://github.com/2noise/ChatTTS.git . # 预下载权重,避免每次容器重启重新拉 RUN python -c "import ChatTTS; ChatTTS.ChatTTS().load(compile=False)" # 暴露容器内部端口,只是声明,实际映射在运行层 EXPOSE 8080 # 启动脚本:指定 --server_name=0.0.0.0 允许外部访问,--server_port 固定 8080 CMD ["python", "gradio_demo.py", "--server_name=0.0.0.0", "--server_port=8080"]关键解释
EXPOSE 8080只是文档化声明,真正决定宿主机端口的是docker run -p 8666:8080。- 权重提前
load(),首次构建会多花 3-5 min,但换来之后容器秒级启动。 - 把
requirements.txt提前复制,只要依赖不变,这一层缓存永久复用,节省构建时间。
5. 端口映射 & 网络最佳实践
- 启动命令模板
docker run -d --restart=unless-stopped \ --name chatts8666 \ --gpus device=0 \ -p 8666:8080 \ -v $(pwd)/logs:/app/logs \ -e TZ=Asia/Shanghai \ mychatts:1.0-p 8666:8080把容器 8080 映射到宿主机 8666,外部调用http://IP:8666即可。-v logs把 gradio 生成的 wav 缓存挂出来,方便调试和审计。--gpus device=0指定 GPU 0,若机器有多卡,可device=GPU-8f28d2fb用 UUID 更稳。
多实例负载均衡 如果要做并行扩容,再起一个容器把宿主机端口改成 8667,上游 Nginx 用
upstream轮询即可;容器内部依旧 8080,零改动。防火墙别忘放行 云服务器记得在安全组开 8666/TCP,本地 ufw 执行
sudo ufw allow 8666。
6. 性能调优与资源限制
- 显存占用:FP16 推理峰值 3.2 GB,给容器配 4 GB 足够;若用 CPU 版,加
--cpus=4 --memory=8g防止 OOM。 - 并发:gradio 默认单线程,压测 6 并发 RT 2 s;想提升可在入口加
gunicorn多 worker,但需改启动脚本,本文先保稳。 - I/O 限速:宿主机若跑多服务,给容器加
--device-read-bps /dev/nvme0n1:10mb避免读盘打爆。 - 日志轮转:gradio 的 wav 不清理,容器重启会重复写,挂外部卷后配合
logrotate每日压缩,防止 inode 耗尽。
7. 常见问题排查速查表
| 现象 | 最可能原因 | 定位命令 | 解决 |
|---|---|---|---|
| 容器秒退 | 权重没拉下来 | docker logs chatts8666 | 确认构建阶段能联网;或提前下载到本地挂卷 |
| 调用 8666 拒绝连接 | 端口映射错 | docker port chatts8666 | 检查-p 8666:8080是否写反 |
| 显存不足 | 批次太大 | nvidia-smi | 改代码batch=1或加--gpus device=1换卡 |
| 声音杂音 | 采样率不匹配 | 查看 wav 头 22 kHz | 前端播放强制 22 kHz,勿转 44.1 |
| 中文多音字读错 | 文本未分词 | 日志看 phoneme | 在输入文本加[uv_break]手动断句 |
8. 生产环境再迈一步
- 健康检查:在 Dockerfile 加
HEALTHCHECK --interval=30s CMD curl -f http://localhost:8080/ || exit 1,配合 K8s livenessProbe。 - 私有镜像库:构建完
docker tag && docker push harbor.xxx.com/mychatts:1.0,CI 节点拉取快,也避免 DockerHub 限流。 - 安全加固:容器内默认 root,加
USER 1000降权;-v挂卷时加:ro只读。 - 灰度发布:镜像 tag 用 git commit sha,滚动升级先跑 10% 流量,回滚只需
docker stop && docker run 旧镜像。
9. 下一步,你可以这样玩
- 自定义音色:用 15 分钟干声素材微调
Speaker Embedding,把.pt文件挂进-v myspeaker:/app/speakers,启动脚本加--speaker_pt /app/speakers/xiaoli.pt即可上线“专属主播”。 - 压测:拿
locust写 20 行脚本,每秒并发 10 请求,看 GPU 利用率与 RT 曲线,再决定是否上 TensorRT 加速。 - 边缘部署:树莓派 4 虽跑不动 GPT 层,可把模型拆成“云端推理 + 本地播放”两段,容器里只留 REST 客户端,一样用 8666 走音频流。
写完这篇,我把公司原来的 8080 冲突问题彻底解决了,测试小姐姐再也不用喊“谁占了我的端口”。如果你也准备让项目“开口说话”,不妨先docker build一把,让 ChatTTS 在 8666 安家。祝你部署顺利,下次分享见。