3、vLLM镜像构建:Dockerfile编写、多阶段构建、镜像优化与推送至私有仓库

镜像构建这事儿,说白了就是给模型搭个「家」。你想想看,vLLM 跑在 K8s 上,总不能每台节点都手动装一遍环境吧?镜像就是那个标准化的运行环境。我刚开始搞 vLLM 部署时,镜像动不动就 5、6 个 G,拉取慢、启动慢,后来踩了不少坑才摸到门道。

3.1 基础镜像选型:别在起点就输了

选基础镜像,我个人的习惯是「够用就好」。vLLM 官方推荐用 NVIDIA CUDA 镜像,但版本得对上。我遇到过有人用 CUDA 12.0 跑 vLLM 0.4.0,结果算子编译不过去——说白了就是版本不匹配。

这里给个参考表:

vLLM 版本 推荐 CUDA 版本 基础镜像
0.4.x 11.8 nvidia/cuda:11.8.0-cudnn8-devel-ubuntu22.04
0.5.x 12.1 nvidia/cuda:12.1.0-cudnn8-devel-ubuntu22.04
0.6.x 12.4 nvidia/cuda:12.4.0-cudnn9-devel-ubuntu22.04
注意:千万别用 runtime 镜像来构建!runtime 缺了编译工具链,vLLM 的 CUDA kernel 编译不过。我当初图省事用了 runtime,结果折腾了两天才发现是镜像的问题。

3.2 Dockerfile 编写:多阶段构建是王道

多阶段构建,说白了就是把「编译环境」和「运行环境」分开。你想想看,编译时需要 gcc、cmake、python-dev,运行时这些全用不上,留在镜像里就是浪费空间。

这是我常用的 Dockerfile 结构:

# ===== 第一阶段:编译阶段 =====
FROM nvidia/cuda:12.1.0-cudnn8-devel-ubuntu22.04 AS builder

# 设置工作目录
WORKDIR /app

# 安装系统依赖
RUN apt-get update && apt-get install -y \
    git \
    python3.10 \
    python3-pip \
    && rm -rf /var/lib/apt/lists/*

# 先拷贝依赖文件,利用 Docker 缓存
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 安装 vLLM(从源码编译)
COPY . .
RUN pip install --no-cache-dir -e .

# ===== 第二阶段:运行阶段 =====
FROM nvidia/cuda:12.1.0-cudnn8-runtime-ubuntu22.04 AS runtime

WORKDIR /app

# 只拷贝编译产物和必要文件
COPY --from=builder /usr/local/lib/python3.10 /usr/local/lib/python3.10
COPY --from=builder /usr/local/bin /usr/local/bin
COPY --from=builder /app/vllm /app/vllm

# 暴露端口
EXPOSE 8000

# 设置入口
ENTRYPOINT ["python3", "-m", "vllm.entrypoints.openai.api_server"]
小技巧:requirements.txt 单独拷贝并安装,能充分利用 Docker 的层缓存。只要依赖没变,这层就不会重新构建,能省不少时间。

3.3 镜像优化:从 5G 到 1.5G 的蜕变

我刚开始做的镜像,足足 5.2G。拉一次镜像要等 5 分钟,K8s 滚动更新时 Pod 半天起不来。后来我做了三件事,把镜像压到了 1.5G:

  1. 清理 pip 缓存pip install --no-cache-dir 能省 200-300MB
  2. 删除编译中间文件.o.pyc__pycache__ 这些全删掉
  3. 使用 --no-install-recommends:apt-get 安装时加上这个,能省掉一堆用不上的推荐包

优化后的 Dockerfile 片段:

# 清理编译产物
RUN find /app -type f -name "*.pyc" -delete && \
    find /app -type d -name "__pycache__" -delete && \
    rm -rf /root/.cache/pip

# 使用 --no-install-recommends
RUN apt-get update && apt-get install -y --no-install-recommends \
    python3.10 \
    python3-pip \
    && rm -rf /var/lib/apt/lists/*
核心思路:镜像里只留「运行时必须的」东西。模型文件?别放镜像里,用 PVC 挂载。日志?写到 stdout,别落盘。配置文件?用 ConfigMap 注入。

3.4 推送至私有仓库:安全又高效

镜像构建好了,得推到仓库里。我一般用 Harbor 做私有仓库,支持镜像扫描和复制,比 Docker Hub 靠谱多了。

推送步骤:

  1. 打标签docker tag vllm:latest harbor.example.com/library/vllm:0.6.0
  2. 登录仓库docker login harbor.example.com
  3. 推送镜像docker push harbor.example.com/library/vllm:0.6.0
避坑指南:我曾经因为没配置 Docker 的 insecure-registries,导致推送 HTTPS 证书验证失败。如果你用的是自签名证书,记得在 /etc/docker/daemon.json 里加上:{"insecure-registries": ["harbor.example.com"]}

3.5 自动化构建:CI/CD 集成

手动构建太累了,我习惯用 GitLab CI 或 GitHub Actions 自动化。这里给个 GitLab CI 的示例:

build-vllm:
  stage: build
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
  only:
    - tags

每次打 tag 就自动构建并推送,省心省力。

3.6 本章知识体系

我把整个镜像构建的流程画了张图,方便你理解:

vLLM 镜像构建流程 基础镜像选型 CUDA 版本匹配 多阶段构建 编译 + 运行分离 镜像优化 清理 + 瘦身 推送私有仓库 Harbor / Docker Registry CI/CD 自动化 GitLab CI / GitHub Actions 关键优化点 • 使用 --no-cache-dir • 删除 .pyc 文件 • 分离编译/运行环境 • 模型文件不打包 • 利用 Docker 缓存

这张图把整个流程串起来了。从选基础镜像开始,到多阶段构建、优化、推送,最后用 CI/CD 自动化。每一步都有坑,但走通了之后,你会发现镜像构建其实挺有章法的。

我的经验:镜像构建这事儿,别追求一步到位。先跑起来,再慢慢优化。我第一个 vLLM 镜像 5G 多,现在稳定在 1.5G 左右。每次迭代都做减法,慢慢就找到感觉了。

专注资料整理