使用 MLflow Docker 镜像托管模型并启用 GPU 推理
解读
在国内互联网/金融/制造企业的实际面试中,这道题常被用来快速验证候选人是否能把“模型交付”与“容器化+GPU调度”打通。
面试官想听的不是“跑通官方 demo”,而是:
- 你能否基于国内镜像源(阿里云、腾讯云、DaoCloud)构建最小可维护的 GPU 镜像;
- 能否在 Swarm/K8s 双栈环境下把 NVIDIA Device Plugin、CUDA 驱动版本、MLflow 版本、模型依赖一次性对齐;
- 能否在 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 跑得稳”,最后让“稳得快”。
-
基础镜像与驱动对齐
选 nvidia/cuda:11.8.0-cudnn8-runtime-ubuntu22.04 作为 runtime 阶段,宿主机驱动≥520.61.05,提前在裸金属或 ACK 节点上通过 nvidia-fabricmanager 统一版本,避免 R470 与 R520 混用导致 cudaGetDeviceCount 失败。 -
多阶段 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 个高危,符合金融上线基线。
- 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 切片。
- 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 到生产仓库,保证“镜像即交付物”。
- 灰度与回滚
使用 Swarm update-order: start-first 或 K8s RollingUpdate maxSurge=1,maxUnavailable=0,30 s 内完成零停机切换;回滚命令:
docker service update --image myrepo/mlflow-gpu:1.0.0-bak inference
镜像 tag 带 git-sha,可快速定位到代码版本。
- 监控与告警
- 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 自定义指标。
拓展思考
- 多卡并行推理:若模型支持 TensorRT + Dynamic Axes,可在 Dockerfile 里集成 torch2trt,把 GPU 内存占用再降 42%;同时用 NVIDIA MIG 把 A100 拆成 7 实例,在 K8s 1.27+ 用 device-plugin 0.14 支持 migStrategy=mixed,实现“一卡七模型”。
- 冷启动加速:把 conda 环境提前 compile 成 pyc,并用 overlay2 的 volatile 挂载 把 /tmp 放到 tmpfs,可将启动时间从 28 s 压到 9 s;阿里 ECI 等 Serverless 场景 可再叠加 镜像快照缓存,做到 3 s 级拉起。
- 安全合规:金融客户要求**“模型文件与容器分离”**,可把模型放到 阿里云 OSS + RAM 细粒度授权,容器启动时通过 init 容器拉取并验签(SHA256),防止“带毒模型”上线;同时把 seccomp 配置文件 绑定到 RuntimeClass,禁用 mount、ptrace 等 44 个系统调用,通过等保 2.0 三级测评。