3. Docker基础回顾:Dockerfile编写、构建vLLM镜像、推送镜像到仓库、镜像优化技巧
说实话,很多搞Kubernetes的朋友,最后翻车都翻在Docker镜像上。镜像太大、层数太多、构建太慢,这些问题我在生产环境里见得多了。今天咱们就把vLLM的Docker镜像这件事彻底聊透。
3.1 为什么还要折腾Docker镜像?
你可能会问:「vLLM官方不是提供了镜像吗?直接用不行吗?」
行,当然行。但我在实际项目中遇到过几次这样的情况:官方镜像里带的CUDA版本跟咱们集群的驱动不匹配,或者我们需要集成一些自定义的tokenizer、量化算法。这时候,自己动手写Dockerfile就成了刚需。
说白了,掌握镜像构建能力,你才能真正掌控vLLM的部署。
3.2 Dockerfile编写:从零开始
先看一个我常用的vLLM Dockerfile模板。这个版本我优化过好几轮,兼顾了构建速度和镜像体积。
# 多阶段构建 - 第一阶段:编译环境
FROM nvidia/cuda:12.1.0-devel-ubuntu22.04 AS builder
# 我个人习惯把工作目录放在 /app
WORKDIR /app
# 安装系统依赖
RUN apt-get update && apt-get install -y \
python3.10 \
python3-pip \
git \
&& rm -rf /var/lib/apt/lists/*
# 先复制依赖文件,利用Docker缓存
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 第二阶段:运行环境
FROM nvidia/cuda:12.1.0-runtime-ubuntu22.04
WORKDIR /app
# 只从builder阶段复制需要的文件
COPY --from=builder /usr/local/lib/python3.10 /usr/local/lib/python3.10
COPY --from=builder /usr/local/bin /usr/local/bin
# 复制vLLM源码
COPY . .
# 暴露端口
EXPOSE 8000
# 启动命令
CMD ["python3", "-m", "vllm.entrypoints.openai.api_server"]
关键点解析:
- 多阶段构建:第一阶段装编译工具,第二阶段只留运行时。镜像体积能小30%-40%
- 先复制requirements.txt再装依赖:利用Docker的层缓存机制,不改依赖就不重装
- 用devel镜像编译,用runtime镜像运行:这是CUDA镜像的经典用法
3.3 构建vLLM镜像:那些坑我替你踩过了
构建命令其实很简单:
docker build -t vllm-server:1.0 .
但这里有几个坑,我曾经都踩过:
- CUDA版本必须匹配:我遇到过用12.2的驱动跑12.1的镜像,结果vLLM直接报错。检查驱动版本用
nvidia-smi,检查镜像CUDA版本看Dockerfile里的tag - 内存不够:vLLM编译时挺吃内存的,至少16GB。我有一台8GB的笔记本,编译到一半直接OOM killed
- 网络问题:pip下载PyTorch这种大包,建议加个国内镜像源。在Dockerfile里加一行
RUN pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
小技巧:构建时加个 --progress=plain 参数,能看到每一步的详细输出。排查问题特别好用。
docker build --progress=plain -t vllm-server:1.0 .
3.4 推送镜像到仓库:别等到部署时才手忙脚乱
镜像构建好了,得推到仓库里,Kubernetes才能拉取。流程不复杂:
# 登录你的镜像仓库
docker login registry.example.com
# 给镜像打标签
docker tag vllm-server:1.0 registry.example.com/vllm-server:1.0
# 推送
docker push registry.example.com/vllm-server:1.0
这里我建议你养成一个好习惯:标签语义化。别用 latest,用 v1.0.0、v1.1.0 这种。为什么?因为 latest 指向谁你根本记不住,回滚的时候你就知道后悔了。
| 标签策略 | 示例 | 适用场景 |
|---|---|---|
| 语义化版本 | v1.0.0, v1.1.0 | 正式发布 |
| Git Commit | git-a1b2c3d | 开发测试 |
| 时间戳 | 20240101-1200 | 每日构建 |
3.5 镜像优化技巧:把体积从5GB降到1.5GB
嗯,这里要重点说说优化。我第一次构建vLLM镜像,体积直奔5GB。在Kubernetes上拉取这种镜像,那叫一个慢。后来我总结了几招:
3.5.1 多阶段构建(最有效)
前面已经展示过了。把编译环境和运行环境分开,能砍掉一半体积。
3.5.2 清理缓存和临时文件
在Dockerfile里加一行:
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/*
3.5.3 使用更小的基础镜像
如果不需要完整的CUDA工具链,试试 nvidia/cuda:12.1.0-runtime-ubuntu22.04 而不是 devel 版本。runtime版本只有1.5GB,devel版本有3.5GB。
3.5.4 合并RUN指令
每一条RUN指令都会产生一个新层。层越多,镜像越大。把相关的命令合并到一条RUN里:
RUN apt-get update && \
apt-get install -y python3 python3-pip && \
pip install --no-cache-dir torch && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
注意:合并RUN指令虽然能减小体积,但会破坏Docker的缓存机制。如果你经常改某一步,建议单独写一条RUN,利用缓存加速构建。
3.6 本章知识体系
下面这张图,是我梳理的Docker镜像构建全流程。你可以把它当作一个检查清单:
这张图把整个流程串起来了。从编写Dockerfile开始,到构建、推送,再到优化技巧和常见问题。你照着这个流程走一遍,基本不会出大问题。
最后说一句:镜像构建这件事,看起来简单,但细节决定成败。我见过太多人因为镜像没搞好,在Kubernetes上部署vLLM时各种翻车。花点时间把基础打牢,后面会省很多事。
公众号:蓝海资料掘金营,微信deep3321