使用 MLflow Docker 镜像托管模型并启用 GPU 推理

解读

在国内互联网/金融/制造企业的实际面试中,这道题常被用来快速验证候选人是否能把“模型交付”与“容器化+GPU调度”打通
面试官想听的不是“跑通官方 demo”,而是:

  1. 你能否基于国内镜像源(阿里云、腾讯云、DaoCloud)构建最小可维护的 GPU 镜像;
  2. 能否在 Swarm/K8s 双栈环境下把 NVIDIA Device Plugin、CUDA 驱动版本、MLflow 版本、模型依赖一次性对齐;
  3. 能否在 10 分钟内让面试官相信你解决了国内网络、驱动版本、安全加固、CI/CD 回滚四大痛点。
    回答时务必先给结论再给推导,用“镜像尺寸从 8.6 GB 压到 1.9 GB,冷启动 28 s→9 s”这类量化数据镇场。

知识点

  • 国内 GPU 基础镜像选型:nvidia/cuda:11.8.0-cudnn8-runtime-ubuntu22.04(阿里云同步频次高,CVE 低)。
  • MLflow 1.30+ 对 CUDA 11.8 的预编译 wheel 依赖,避免 pip 自行编译 500 s 超时。
  • 多阶段构建:builder 阶段用 nvidia/cuda-devel 装 gcc、python-dev;runtime 阶段仅保留 cuda-runtime、libgomp1、miniconda 与模型venv,把层数压到 7 层以内
  • 国内 apt/pip 镜像:/etc/apt/sources.list.d/aliyun.list、~/.pip/pip.conf 设置 trusted-host,防止构建机因 GFW 断流
  • 非 root 运行时:创建 uid=1000 的 mlflow 用户,把 /opt/mlflow 权限置 755,满足金融类客户“容器内禁止 root”基线。
  • GPU 隔离NVIDIA_VISIBLE_DEVICES=UUID 白名单 而非 all,避免同卡被多副本抢占导致 OOM。
  • MLflow 模型打包:使用 mlflow models build-docker -m runs:/xxx/model --enable-mlserver --name myrepo/mlflow-gpu:1.0.0 生成默认 CPU 镜像后,手动插入 nvidia-runtime 依赖层,再 docker commit 为 gpu 版本,保证与 CI 流水线解耦
  • 推理入口MLServer 1.3+ 自带 grpc 与 REST 双协议,通过环境变量 MLSERVER_MODEL_GPU_ENABLED=true 开启 GPU 调度,无需改代码
  • 健康探针:在 Dockerfile 里加入 HEALTHCHECK --interval=15s --timeout=3s CMD python -c "import mlflow, torch; torch.cuda.init(); exit(0)"防止驱动版本不匹配导致静默失败
  • 镜像签名:使用 cosign + 阿里云 ACR 的**“镜像加签”策略**,阻断“投毒”模型镜像流入生产
  • Swarm 下发docker service create --generic-resource "gpu=1" --env NVIDIA_VISIBLE_DEVICES=GPU-4dc3c9f2 实现节点级 GPU 绑定;K8s 侧则声明 nvidia.com/gpu: 1,并在 limits 与 requests 同时写,否则调度器会 pending。
  • 日志规范统一输出到 stdout/stderr,避免写文件造成 overlay2 膨胀;使用阿里云 SLS 插件 0.3 版本以下需关闭 partial_log,防止多行 stacktrace 被截断。
  • 回滚策略:镜像 tag 采用 git-commit-sha-gpu 格式,蓝绿发布时只需修改 service 的 --image 参数,30 s 内完成切换。

答案

核心思路:先让镜像“能跑到 GPU”,再让“GPU 跑得稳”,最后让“稳得快”。

  1. 基础镜像与驱动对齐
    nvidia/cuda:11.8.0-cudnn8-runtime-ubuntu22.04 作为 runtime 阶段,宿主机驱动≥520.61.05,提前在裸金属或 ACK 节点上通过 nvidia-fabricmanager 统一版本,避免 R470 与 R520 混用导致 cudaGetDeviceCount 失败

  2. 多阶段 Dockerfile(可直接背诵)

# 1) builder 阶段
FROM nvidia/cuda:11.8.0-cudnn8-devel-ubuntu22.04 as builder
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 python3.10-dev python3-pip git
COPY requirements.txt /tmp/
RUN pip3 install --no-cache-dir -i https://mirrors.aliyun.com/pypi/simple -r /tmp/requirements.txt

# 2) runtime 阶段
FROM nvidia/cuda:11.8.0-cudnn8-runtime-ubuntu22.04
RUN groupadd -r mlflow && useradd -r -g mlflow -u 1000 mlflow
COPY --from=builder /usr/local/lib/python3.10/dist-packages /usr/local/lib/python3.10/dist-packages
COPY --from=builder /usr/local/bin/mlflow /usr/local/bin/mlserver /usr/local/bin/
COPY model /opt/mlflow/model
RUN chown -R mlflow:mlflow /opt/mlflow
USER mlflow
ENV MLSERVER_MODEL_GPU_ENABLED=true
ENV MLSERVER_MODEL_NAME=my_model
ENV MLSERVER_MODEL_URI=/opt/mlflow/model
EXPOSE 8080
HEALTHCHECK --interval=15s --timeout=3s \
  CMD python3 -c "import torch; torch.cuda.init(); exit(0)"
ENTRYPOINT ["mlserver", "start", "/opt/mlflow/model"]

构建命令:

docker build -t myrepo/mlflow-gpu:1.0.0 . \
  --build-arg http_proxy=http://your-ci-proxy:3128 \
  --build-arg https_proxy=http://your-ci-proxy:3128

镜像尺寸 1.9 GB,扫描 CVE≤3 个高危,符合金融上线基线。

  1. GPU 调度与资源绑定
    Swarm 场景:
docker service create \
  --name inference \
  --generic-resource "gpu=1" \
  --env NVIDIA_VISIBLE_DEVICES=GPU-4dc3c9f2 \
  --env NVIDIA_DRIVER_CAPABILITIES=compute,utility \
  --publish 8080:8080 \
  --limit-memory 4G \
  --with-registry-auth \
  myrepo/mlflow-gpu:1.0.0

K8s 场景:

resources:
  limits:
    nvidia.com/gpu: 1
    memory: 4Gi
  requests:
    nvidia.com/gpu: 1
    memory: 4Gi
nodeSelector:
  accelerator/nvidia-gpu: "true"

禁止写 nvidia.com/gpu: "0.5",国内主流版本还不支持 vGPU 切片。

  1. CI/CD 集成
    GitLab CI 中增加 gpu-test 阶段:
gpu-test:
  stage: test
  image: nvidia/cuda:11.8.0-base-ubuntu22.04
  tags: [gpu-runner]
  script:
    - docker run --rm --gpus all myrepo/mlflow-gpu:$CI_COMMIT_SHA \
        mlserver --help
    - curl -sf http://localhost:8080/v2/health/ready
  only:
    - master

通过后再推 tag 到生产仓库,保证“镜像即交付物”。

  1. 灰度与回滚
    使用 Swarm update-order: start-first 或 K8s RollingUpdate maxSurge=1,maxUnavailable=030 s 内完成零停机切换;回滚命令:
docker service update --image myrepo/mlflow-gpu:1.0.0-bak inference

镜像 tag 带 git-sha,可快速定位到代码版本。

  1. 监控与告警
  • GPU 利用率:通过 dcgm-exporter 暴露 DCGM_FI_DEV_GPU_UTIL在阿里云 ARMS 设置≥90% 持续 5 min 则告警
  • 显存 OOM:利用 DCGM_FI_DEV_MEM_COPY_UTIL 结合 container_last_seen 指标,30 s 内触发短信
  • 模型延迟P99>800 ms 即自动扩容副本,Swarm 用 docker service scale,K8s 用 HPA 自定义指标。

拓展思考

  1. 多卡并行推理:若模型支持 TensorRT + Dynamic Axes,可在 Dockerfile 里集成 torch2trt把 GPU 内存占用再降 42%;同时用 NVIDIA MIG 把 A100 拆成 7 实例,在 K8s 1.27+ 用 device-plugin 0.14 支持 migStrategy=mixed,实现“一卡七模型”。
  2. 冷启动加速:把 conda 环境提前 compile 成 pyc,并用 overlay2 的 volatile 挂载 把 /tmp 放到 tmpfs,可将启动时间从 28 s 压到 9 s阿里 ECI 等 Serverless 场景 可再叠加 镜像快照缓存,做到 3 s 级拉起。
  3. 安全合规:金融客户要求**“模型文件与容器分离”**,可把模型放到 阿里云 OSS + RAM 细粒度授权,容器启动时通过 init 容器拉取并验签(SHA256)防止“带毒模型”上线;同时把 seccomp 配置文件 绑定到 RuntimeClass,禁用 mount、ptrace 等 44 个系统调用通过等保 2.0 三级测评