4、Docker镜像制作:编写vLLM的Dockerfile、构建镜像并推送至仓库、优化镜像大小与启动速度、镜像安全扫描

说实话,Docker镜像制作这块,我见过太多人踩坑了。有人直接把整个Python环境打包进去,镜像几个G;有人图省事用latest标签,结果生产环境出了事都查不到版本。今天咱们就聊聊vLLM镜像怎么做才专业。

4.1 编写vLLM的Dockerfile

先说说我的习惯。我一般会从官方镜像开始,而不是从零搭建。为什么呢?因为vLLM依赖的CUDA、PyTorch版本组合很讲究,自己配容易出问题。

下面这个Dockerfile是我在项目中常用的,你可以直接拿来用:

# 基础镜像选择
FROM nvidia/cuda:12.1.0-runtime-ubuntu22.04 AS base

# 设置环境变量
ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    PIP_NO_CACHE_DIR=1 \
    PIP_DISABLE_PIP_VERSION_CHECK=1

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

# 安装vLLM
RUN pip install vllm==0.4.0

# 设置工作目录
WORKDIR /app

# 复制入口脚本
COPY entrypoint.sh /app/
RUN chmod +x /app/entrypoint.sh

# 暴露端口
EXPOSE 8000

# 启动命令
ENTRYPOINT ["/app/entrypoint.sh"]
小提示:我建议把版本号写死,别用latest。有一次我在测试环境用了latest,结果第二天镜像更新了,模型推理结果全变了,排查了半天才发现是版本问题。

4.2 构建镜像并推送至仓库

构建镜像其实就一条命令,但这里有几个细节要注意:

# 构建镜像
docker build -t registry.example.com/vllm-server:0.4.0 .

# 打标签
docker tag registry.example.com/vllm-server:0.4.0 registry.example.com/vllm-server:latest

# 推送至仓库
docker push registry.example.com/vllm-server:0.4.0
docker push registry.example.com/vllm-server:latest

我个人习惯用docker buildx做多架构构建,特别是当你的K8s集群里有ARM节点时:

# 创建构建器
docker buildx create --name mybuilder --use

# 多架构构建并推送
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t registry.example.com/vllm-server:0.4.0 \
  --push .
注意:推送镜像前,记得先登录仓库。我曾经因为忘记登录,构建了半小时的镜像白白浪费了。建议在CI/CD脚本里加上登录检查。

4.3 优化镜像大小与启动速度

镜像大小直接影响部署速度。你想想看,一个5G的镜像传到K8s节点上,那得等多久?

我常用的优化手段有这几个:

  • 多阶段构建:把编译环境和运行环境分开
  • 清理缓存:apt和pip的缓存能省不少空间
  • 选择轻量基础镜像:比如用slim版本

来看一个优化后的Dockerfile:

# 第一阶段:构建
FROM python:3.10-slim AS builder

RUN pip install --user vllm==0.4.0

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

COPY --from=builder /root/.local /root/.local
ENV PATH=/root/.local/bin:$PATH

# 其他配置...

这样做的好处是,最终镜像只包含运行时需要的文件,构建时的中间产物全被丢弃了。我试过,镜像能从3.2G降到1.8G,效果很明显。

启动速度方面,我建议:

  • 预加载模型权重到镜像里(如果模型不大)
  • 使用--shm-size参数设置共享内存
  • 在K8s里设置startupProbe,避免健康检查过早失败
经验之谈:我曾经遇到一个情况,镜像启动要5分钟,K8s一直重启Pod。后来发现是livenessProbe设置得太早了。改成startupProbe后,问题就解决了。

4.4 镜像安全扫描

安全扫描这事,说白了就是给镜像做个体检。我一般用Trivy,开源免费,扫描速度也快。

# 安装Trivy
sudo apt-get install trivy

# 扫描镜像
trivy image registry.example.com/vllm-server:0.4.0

# 输出为JSON格式,方便集成到CI/CD
trivy image --format json --output result.json registry.example.com/vllm-server:0.4.0

扫描结果一般分几个等级:

严重级别 说明 我的处理方式
CRITICAL 可远程利用的漏洞 必须修复,否则不上线
HIGH 本地可利用的漏洞 尽量修复,评估风险
MEDIUM 需要特定条件 记录跟踪,定期复查
LOW 影响较小 忽略或后续处理
避坑指南:我曾经因为一个CRITICAL漏洞没修复,被安全团队卡了三天。从那以后,我都在CI/CD里加了扫描步骤,一旦发现高危漏洞就阻断构建。

另外,我建议把安全扫描集成到GitLab CI或Jenkins里,每次提交代码自动扫描。这样能尽早发现问题,而不是等到部署前才手忙脚乱。

嗯,镜像制作这块就聊到这儿。记住一个原则:镜像要小、启动要快、安全要过关。做到这三点,你的vLLM服务在K8s上就能跑得稳了。


专注资料整理