4、Docker镜像制作:编写Dockerfile(基于CUDA基础镜像)、安装vLLM依赖、模型文件打包策略、镜像构建与推送。

好,咱们进入第四章节。镜像制作这块,说白了就是把你的推理服务“打包”成一个标准化的运输箱。不管你是用K8s调度,还是用Docker Compose跑,最终都得靠这个镜像来承载vLLM进程。我见过不少团队,代码写得挺好,结果镜像一塌糊涂——要么太大(十几个G),要么跑起来缺库,要么模型文件路径写死。嗯,今天咱们就把这些坑都填上。

4.1 基于CUDA基础镜像:选对“地基”

Dockerfile的第一行,就是FROM。这个基础镜像选错了,后面全白搭。我个人习惯,生产环境首选nvidia/cuda:12.1.0-runtime-ubuntu22.04

为什么不用devel版本?因为devel包含了完整的CUDA工具链,体积大了一倍不止。而vLLM在运行时只需要CUDA runtime库和cuBLAS、cuDNN这些动态库。你想想看,一个镜像多出2-3个G,每次拉取、传输都是成本。

我曾经在客户现场遇到过,他们用了nvidia/cuda:12.1.0-devel-ubuntu22.04,镜像打包完接近8G。结果内网带宽只有100Mbps,光拉镜像就花了十几分钟。后来换成runtime版本,直接降到4.5G,部署效率翻倍。

核心原则:生产环境用runtime,开发调试用devel。别混用。

4.2 安装vLLM依赖:pip install 背后的门道

基础镜像选好了,接下来就是安装vLLM。这里有个关键点:vLLM对PyTorch和CUDA的版本匹配非常敏感。我建议直接用vLLM官方推荐的版本组合。

先看一个典型的Dockerfile片段:

FROM nvidia/cuda:12.1.0-runtime-ubuntu22.04

# 设置非交互模式,避免tzdata等包卡住
ENV DEBIAN_FRONTEND=noninteractive

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

# 升级pip
RUN pip3 install --upgrade pip setuptools wheel

# 安装PyTorch(必须与CUDA 12.1匹配)
RUN pip3 install torch==2.1.2 torchvision==0.16.2 --index-url https://download.pytorch.org/whl/cu121

# 安装vLLM
RUN pip3 install vllm==0.4.0

# 清理pip缓存,减小镜像体积
RUN rm -rf /root/.cache/pip

这里有个小技巧:apt-get updateinstall写在同一行。为什么?因为Docker的layer缓存机制。如果你分开写,apt-get update会被缓存,后面再添加新包时,可能用的是过期的源列表。我踩过这个坑,当时加了一个libcudnn的包,结果因为缓存了旧的源列表,装了个不兼容的版本,vLLM启动直接报错。

个人经验:vLLM的依赖安装顺序很重要。先装PyTorch,再装vLLM。因为vLLM在安装时会检测PyTorch版本,如果版本不对,它会尝试降级或报错。先装PyTorch可以确保版本可控。

4.3 模型文件打包策略:大文件的“瘦身”艺术

模型文件怎么放?这是个大问题。一个7B的模型,光权重文件就14G左右(FP16)。如果直接COPY进镜像,镜像体积会暴涨,而且每次更新模型都要重新构建镜像。

我推荐三种策略,按场景选:

策略 适用场景 优点 缺点
策略A:镜像内嵌 模型固定、镜像不常更新 部署简单,无需额外存储 镜像体积大,构建慢
策略B:挂载外部卷 模型频繁更新、多环境共享 镜像小,模型独立管理 依赖外部存储(如NFS、PVC)
策略C:启动时下载 模型来自HuggingFace等远程源 镜像最小,模型版本灵活 启动慢,依赖网络

我个人习惯,生产环境用策略B。镜像只包含vLLM和依赖,模型文件通过K8s的PersistentVolumeClaim挂载进去。这样模型更新时,只需要更新PVC里的文件,镜像完全不用动。

如果你非要用策略A,记得用.dockerignore排除掉不需要的文件:

# .dockerignore
.git/
__pycache__/
*.pyc
*.md
*.log
model_cache/

还有一点:模型文件不要直接放在/根目录下。我建议统一放在/models目录,然后在Dockerfile里创建软链或环境变量指向它:

ENV MODEL_PATH=/models/llama-7b

4.4 镜像构建与推送:自动化才是王道

构建镜像的命令很简单,但生产环境里,我建议用docker buildx来做多架构构建(虽然vLLM目前只支持x86_64,但未来ARM架构可能会支持)。

先看基本命令:

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

# 打标签(如果构建时没指定完整tag)
docker tag vllm-server:latest registry.example.com/vllm-server:1.0.0

# 推送镜像
docker push registry.example.com/vllm-server:1.0.0

这里有个坑:镜像标签一定要语义化。我见过有人用v1v2这种标签,结果过了一个月,谁也分不清v1对应的是哪个commit。我建议用<项目名>:<主版本>.<次版本>.<补丁版本>,比如vllm-server:1.0.0。同时,每次构建都打一个latest标签,方便开发环境快速拉取。

避坑指南:我曾经在CI/CD流水线里,直接用docker build --no-cache来避免缓存问题。结果每次构建都重新下载PyTorch,耗时从3分钟变成了15分钟。后来我改成:只在关键步骤(如安装vLLM)用--no-cache,基础层保留缓存。这样既保证了依赖最新,又不会太慢。

对于推送,如果你的镜像仓库需要认证,记得先docker login。我建议在CI/CD里用docker login -u $USERNAME -p $PASSWORD的方式,但密码不要硬编码,用密钥管理服务(如GitHub Secrets、GitLab CI Variables)。

4.5 本章知识体系:一张图看懂

下面这张SVG图,把镜像制作的整个流程串起来了。从基础镜像选择,到依赖安装,再到模型打包,最后构建推送。你可以把它当作一个检查清单。

Docker镜像制作流程 1. 选择基础镜像 nvidia/cuda:12.1-runtime 2. 安装系统依赖 Python3、pip、git 3. 安装vLLM pip install vllm 4. 模型文件策略 内嵌/挂载/下载 5. 构建镜像 docker build -t ... 6. 推送镜像 docker push ... 关键检查点 ✅ 基础镜像:使用runtime版本,避免devel ✅ 依赖安装:先PyTorch后vLLM,版本严格匹配 ✅ 模型策略:生产环境推荐挂载外部卷 ✅ 构建推送:语义化标签,CI/CD自动化

嗯,镜像制作这块,说白了就是“地基”和“打包”两个核心。地基选对了(CUDA runtime),依赖装对了(版本匹配),模型放对了(挂载策略),剩下的就是自动化构建推送。下一章咱们会聊K8s的部署配置,到时候这个镜像就会派上用场。

专注资料整理