使用 Triton Docker 镜像部署 FP16 与 INT8 多模型

解读

在国内云原生面试场景里,这道题考察的是“把 GPU 推理服务器装进容器并跑起来”的端到端能力。
Triton Inference Server 是 NVIDIA 官方推理框架,天然支持 FP16/INT8 混合精度、并发多模型、动态批处理。
Docker 化部署 的核心诉求是:镜像体积 < 5 GB、启动时间 < 30 s、GPU 驱动与 CUDA 版本对齐、国内网络可拉取、安全合规(非 root、最小权限、Secrets 不落盘)。
题目隐含三个得分点:

  1. 镜像选型与多阶段构建
  2. 模型仓库目录规范与配置文件写法
  3. 同一容器内同时服务 FP16 与 INT8 模型,且能热更新

知识点

  • nvcr.io/nvidia/tritonserver:24.05-py3-min 国内加速拉取方案(阿里云 ACR 缓存或自建 Harbor proxy)
  • 多阶段构建tritonserver 二进制与模型文件分离,最终镜像只保留 /opt/tritonserver/binLD_LIBRARY_PATH 所需 so,体积可压缩 40 %
  • 模型仓库目录树 必须严格遵循
    model_repository/
    ├── resnet50_fp16/
    │   ├── 1/
    │   │   └── model.pt
    │   └── config.pbtxt
    └── yolov5_int8/
        ├── 1/
        │   └── model.plan
        └── config.pbtxt
    
    其中 config.pbtxt 需显式指定 platform: "tensorrt_plan"precision_mode: INT8,并挂载校准表
  • 同一进程加载多模型 依赖 --model-control-mode=poll--load-model=* 参数,避免启动顺序耦合
  • GPU 显存隔离 使用 CUDA_VISIBLE_DEVICESTRITON_SERVER_GPU_DEVICE 环境变量,防止 FP16 模型抢占 INT8 模型显存
  • 国内合规:镜像内禁止 root,USER 1001:1001;敏感 License 文件通过 Kubernetes Secrets 以 tmpfs 挂载,不落容器可写层
  • CI/CD:在 GitLab-Runner 或 GitHub Actions 国内节点做 docker buildx --cache-to type=registry 缓存,加速后续构建

答案

  1. 准备最小 Dockerfile
# 第一阶段:拉取官方镜像作为构建缓存
FROM nvcr.io/nvidia/tritonserver:24.05-py3-min as builder
# 国内加速
RUN sed -i 's@http://.*.ubuntu.com@http://mirrors.aliyun.com@g' /etc/apt/sources.list
# 预装国内 pip 源
COPY pip.conf /etc/pip.conf

# 第二阶段:运行时镜像
FROM nvcr.io/nvidia/tritonserver:24.05-py3-min
COPY --from=builder /opt/tritonserver /opt/tritonserver
COPY model_repository /models
RUN groupadd -g 1001 triton && useradd -u 1001 -g triton -s /bin/false triton
USER 1001:1001
ENV LD_LIBRARY_PATH=/opt/tritonserver/lib:$LD_LIBRARY_PATH
ENTRYPOINT ["/opt/tritonserver/bin/tritonserver"]
CMD ["--model-repository=/models", "--model-control-mode=poll", "--load-model=*", "--strict-model-config=false"]
  1. 构建与推送
docker buildx build --platform linux/amd64 -t reg.xxx.cn/triton:fp16-int8-v1 \
  --cache-to type=registry,ref=reg.xxx.cn/cache:triton \
  --cache-from type=registry,ref=reg.xxx.cn/cache:triton --push .
  1. 运行验证
docker run --gpus all --rm -p 8000:8000 -p 8001:8001 -p 8002:8002 \
  -e CUDA_VISIBLE_DEVICES=0,1 \
  reg.xxx.cn/triton:fp16-int8-v1

使用 curl -X POST localhost:8000/v2/models/resnet50_fp16/readyyolov5_int8/ready 返回 200,即表示多模型同时加载成功。
4. INT8 校准表热更新
*.calib 文件放在 yolov5_int8/1/ 目录,config.pbtxt 中增加

parameters: {
  key: "INT8_CALIBRATION_TABLE"
  value: { string_value: "/models/yolov5_int8/1/calib_yolov5.bin" }
}

Triton 轮询到文件变化会自动重载,无需重启容器

拓展思考

  • 动态批处理:在 config.pbtxt 里打开 dynamic_batching { max_queue_delay_microseconds: 500 }FP16 与 INT8 模型可共享同一调度器,但需评估 INT8 校准后的精度损失是否满足 SLA。
  • A/B 灰度:利用 Triton 的 model_version_policy: { specific { versions: 2 } } 与 Kubernetes Ingress 按 Header 分流,实现国内业务常见的“灰度 5 % 流量”需求
  • 国产化 GPU:在 Hygon、MTT 或 Moore Threads 环境,需把底层 libcuda.so 替换为厂商提供的兼容库,重新编译 TensorRT plan,否则 INT8 校准阶段会报 cudaErrorNotSupported
  • 镜像安全扫描:使用 trivy 对最终镜像做 CVE 检测,国内银行客户要求 HIGH 级别漏洞为 0,可通过 distrolessapko 进一步裁剪系统库。