Files
audio2text/docs/DOCKER.md
audio2text dev 1e355e6138 docs: 新增离线部署导入镜像说明 + 更新功能特性
README:
- 新增「离线部署(导入预构建镜像)」章节:docker load + 启动命令
- 功能特性更新:设置页、任务删除、进度细分、离线运行、/docs 公开

docs/DOCKER.md:
- 新增「导入预构建镜像(离线部署)」完整章节:
  前置要求、导出步骤、需拷贝文件清单、导入启动命令、离线说明、后续更新代码

.gitignore:
- 排除 *.tar(导出的镜像文件不入库)
2026-07-11 11:37:52 +08:00

10 KiB
Raw Permalink Blame History

返回主页

Docker 说明

一份 Dockerfile 出 CPU / GPU 两个镜像,依赖层缓存复用,改代码秒级重建。本文档覆盖 构建、重建、缓存管理与 Volume 挂载。部署流程见 部署指南


一份 Dockerfile两个镜像

ARG VARIANT=cpu|gpu 控制基础镜像与 torch 轮子:

VARIANT 基础镜像 torch
cpu(默认) python:3.12-slim CPU 版(--index-url .../whl/cpu
gpu nvidia/cuda:12.1.0-runtime-ubuntu22.04 CUDA 版

两个镜像的 Python 依赖列表(requirements.txt)完全一致,仅 torch 不同。镜像内 apt 装 ffmpeg + patchelf

安全约束PyTorch CPU wheel 与 GPU(CUDA) wheel 是两个不兼容二进制包CPU 版 torch.cuda.is_available()=FalseGPU 版 =True。torch 必须按 VARIANT 分叉装不同 wheel 绝不能跨 variant 共享依赖层。deps 阶段用 FROM base-${VARIANT}CPU/GPU 是两条独立 构建链,各自装对应 torch。


新建 / 重建容器

项目提供 setup.sh / start.sh / stop.sh 包装脚本,也可直接用 docker / docker compose

首次新建(新机器 / 全新拉取代码后)

# 1. 构建镜像 + 生成 config.yamlCPU 默认)
./setup.sh
# GPUAUDIO2TEXT_VARIANT=gpu ./setup.sh

# 2. 启动容器
./start.sh
# GPUstart.sh 检测到 audio2text:gpu 镜像 + nvidia-smi 自动加 --gpus all

setup.sh 做三件事:检查 docker → 构建 audio2text:{variant} 镜像 → 把 config.{variant}.yaml 复制为 config.yaml(运行时实际读取的文件)。

重建镜像(改了 app 代码或 requirements 后)

依赖层apt + pip + torch由 BuildKit 缓存挂载复用,只有 COPY app 层重建,通常 30 秒内完成。重建不会动运行时数据./data / ./models 是挂载的 volume

# CPU直接重跑 setup.sh幂等会复用缓存层
./setup.sh
# 或显式构建:
docker build --build-arg VARIANT=cpu -t audio2text:cpu .

# GPU
AUDIO2TEXT_VARIANT=gpu ./setup.sh
# 或:
docker build --build-arg VARIANT=gpu -t audio2text:gpu .

# 重建后重启容器(替换运行中的旧镜像):
./stop.sh && ./start.sh

改配置(不重建镜像)

config.yaml 是只读挂载,改完重启容器即生效,无需重建镜像

cp config.gpu.yaml config.yaml   # 切换配置(或直接编辑 config.yaml
./stop.sh && ./start.sh

改依赖requirements.txt / torch 版本)

会触发 deps 层重建,耗时较长(重装 torch + 全部依赖CPU ~3 分钟GPU ~5 分钟)。 BuildKit 的 pip 缓存挂载(/root/.cache/pip)跨构建复用已下载的 wheel二次构建会快 很多。

# 编辑 requirements.txt 后
./setup.sh   # 或 docker build --build-arg VARIANT=gpu -t audio2text:gpu .
./stop.sh && ./start.sh

docker compose替代脚本

docker compose --profile dev up -d --build   # 开发:源码挂载 + uvicorn reload改代码零重建
docker compose --profile cpu up -d --build   # CPU 生产
docker compose --profile gpu up -d --build   # GPU 生产(需 nvidia runtime

导入预构建镜像(离线部署)

当目标机器无法访问 Docker Hub或构建太慢可在已构建好镜像的机器上导出 tar 拷到新机器导入,跳过整个构建过程。

前置要求(新机器)

  • NVIDIA GPU 驱动(宿主机)
  • nvidia container runtimenvidia-container-toolkit
  • Docker
  • config.gpu.yaml 配置文件(从项目仓库取,或自行编写)
  • 模型缓存 ./models 目录(约 5.5GB,从源机器拷贝或联网预拉)

验证 GPU 可用:

nvidia-smi   # 宿主能看到 GPU
docker run --rm --gpus all nvidia/cuda:12.1.0-runtime-ubuntu22.04 nvidia-smi

步骤 1源机器导出镜像

# 在已构建好 audio2text:gpu 镜像的机器上
docker save -o audio2text-gpu.tar audio2text:gpu
ls -lh audio2text-gpu.tar   # ~4.3GB

步骤 2拷贝到新机器

需要拷贝的文件:

文件/目录 大小 说明
audio2text-gpu.tar ~4.3GB Docker 镜像(含 ffmpeg + torch + faster-whisper + transformers + app 代码)
config.gpu.yaml <1KB GPU 配置文件
models/ ~5.5GB 模型缓存Whisper large-v3-turbo + NLLB distilled-1.3B 权重)

models/ 可不拷贝,新机器联网时用 prefetch_models.sh 预拉。但离线部署必须拷贝。

# 用 scp / rsync / U盘 等方式拷贝
scp audio2text-gpu.tar config.gpu.yaml user@newhost:~/audio2text/
rsync -avP models/ user@newhost:~/audio2text/models/

步骤 3新机器导入并启动

cd ~/audio2text

# 1. 导入镜像
docker load -i audio2text-gpu.tar
# 输出Loaded image: audio2text:gpu

# 2. 准备数据目录
mkdir -p data-gpu/uploads data-gpu/.work data-gpu/outputs

# 3. 启动容器
docker run -d --name audio2text-gpu \
    --gpus all \
    -p 8001:8000 \
    -v "$(pwd)/data-gpu:/data" \
    -v "$(pwd)/models:/models" \
    -v "$(pwd)/config.gpu.yaml:/app/config.yaml:ro" \
    --restart unless-stopped \
    audio2text:gpu

# 4. 验证
curl -s http://127.0.0.1:8001/health | python -m json.tool
# 应见 cuda_available=true, gpu="NVIDIA GeForce RTX 3090"

打开 http://127.0.0.1:8001/ 即可使用。

离线运行说明

镜像内置 HF_HUB_OFFLINE=1 + TRANSFORMERS_OFFLINE=1 环境变量,模型缓存就位后 完全离线运行,不会尝试访问 HuggingFace。这避免了离线环境下 transformers pipeline 因网络请求超时导致的翻译失败。

后续更新代码

导入的镜像包含导出时的 app 代码。如需更新代码,有两个选择:

  1. 重新构建:把项目代码拷到新机器,docker build --build-arg VARIANT=gpu -t audio2text:gpu .
  2. 挂载源码(临时调试):启动时加 -v "$(pwd)/app:/app/app" 覆盖镜像内代码

缓存分层与删除边界

这套构建涉及三类缓存,删除策略截然不同,乱删会导致全量重建:

缓存类型 位置 存什么 能删吗 删了会怎样
BuildKit 构建缓存 Docker 内部(docker builder 管理) Dockerfile 各层base / deps / final的构建产物 ⚠️ 谨慎,见下方 命中失效 → 该层及下游全量重建
pip wheel 缓存 BuildKit cache mount /root/.cache/pip 下载过的 .whl 文件 可删 下次构建重新下载 wheel不重编译
模型缓存 ./models volume容器内 /models Whisper / NLLB 权重HF + ctranslate2 可删 下次启动重新下载模型(~5.5GB GPU
运行时数据 ./data volume容器内 /data 上传视频 / 中间音频 / 输出字幕 / SQLite ⚠️ 视情况 删了任务历史和产物全没

⚠️ 不要用 docker builder prune --filter until

这是踩过的坑。BuildKit 的 --filter "until=30m"(或任意时长)会清除"最近 N 分钟未 访问"的缓存层。问题在于:稳定的基础层(如 base-gpu 的 apt 装 python3.12)只在 首次构建时执行一次,之后每次构建都直接 CACHED 跳过——它的"最后访问时间"一直停在首次 构建那一刻,永远不会更新。于是 --filter "until=..." 会把这些仍然在用的稳定层当成 "很久没访问"清掉,导致下一次构建从 base 层开始全量重来GPU 镜像 ~10 分钟 + 重新下载 torch ~2.5GB)。

正确做法:

# ✅ 想清理磁盘、释放 BuildKit 缓存:用不带 filter 的 prune清全部未引用缓存
docker builder prune -f
# 或只清 dangling悬挂的、无引用的中间层
docker builder prune -f --filter "type=regular"

# ✅ 清旧镜像(不影响构建缓存)
docker image prune -a      # 删所有未被容器使用的镜像
docker image prune          # 只删 dangling 镜像

# ✅ 清 pip wheel 缓存BuildKit cache mount安全
docker builder prune -f --filter "type=exec.cachemount"

# ❌ 永远不要这样用——会清掉仍在用的稳定 base 层
docker builder prune -f --filter "until=30m"
docker builder prune -f --filter "until=24h"

根因BuildKit 的 until filter 按"最后访问时间"判定,而非"是否仍在被引用"。CACHED 跳过的层不会刷新访问时间,于是被误判为可回收。这是 BuildKit 的已知行为,不是 bug 但对"稳定 base + 频繁改代码"的构建模式特别致命。详见 moby/buildkit#2414

什么时候需要主动清缓存

  • 磁盘紧张docker builder prune -f + docker image prune 释放空间
  • 依赖换了 torch / CUDA 大版本BuildKit 可能复用了不兼容的旧 wheel清 pip 缓存 mount 强制重下:docker builder prune -f --filter "type=exec.cachemount"
  • 换 VARIANTcpu↔gpu:不需要清——两条构建链独立,缓存互不干扰
  • 想从零验证构建docker builder prune -af 清全部,模拟新机器首次构建

模型缓存(./models

模型权重在 ./models volume容器内 HF_HOME=/models/huggingfaceCT2_CACHE=/models/ctranslate2),跨容器复用。首次启动下载,之后秒起。

# 查看模型缓存大小
du -sh ./models

# 删了强制重下GPU 大模型 ~5.5GB,建议用 prefetch 脚本提前下好)
rm -rf ./models
./scripts/prefetch_models.sh config.gpu.yaml

Volume 挂载

容器路径 宿主路径 用途 删除影响
/data ./dataCPU/ ./data-gpuGPU 上传视频、中间音频、输出字幕、SQLite 任务历史和产物全没
/models ./models 模型缓存HF + ctranslate2跨容器复用 下次启动重下模型
/app/config.yaml ./config.yaml(只读) 配置文件 改配置需重启容器

镜像本身无状态、无敏感数据。


ctranslate2 可执行栈修复

ctranslate2 的 .so(在 ctranslate2.libs/ 隐藏目录)带 PT_GNU_STACK 可执行栈标志, 在某些内核 + Docker 组合下会报 cannot enable executable stack as shared object requires。 Dockerfile 在构建时用 patchelf --clear-execstack 清掉该标志,无需放宽容器安全策略。 构建末尾有 python -c "import ctranslate2" 验证。