vLLM Docker 部署实战指南:官方镜像运行、编译缓存持久化与非 Root 容器实践
本文基于 vLLM 仓库的 Docker 部署文档,完整讲解 vllm/vllm-openai 官方镜像的拉取与运行方式、vLLM Recipes 配置在容器中的挂载方法、跨容器复用 torch.compile 编译缓存的机制,以及非 root 用户(含 OpenShift 任意 UID 场景)的运行时配置。读完本文,你可以直接复制可运行的 docker run / docker build 命令完成 vLLM 容器化部署,并能从 docker/Dockerfile 源码层面理解镜像的阶段划分与非 root 用户的设计依据。
官方预构建镜像 vllm/vllm-openai
vLLM 提供官方 Docker 镜像,可直接用于运行 OpenAI 兼容推理服务,镜像名为 vllm/vllm-openai(见 docs/getting_started/installation/gpu.md 的 "Pre-built images" 一节,该节通过片段包含方式同时被 docs/deployment/docker.md 与安装文档复用)。镜像按硬件平台分为 NVIDIA CUDA、AMD ROCm、Intel XPU、Apple Silicon 多个变体,下面以最常见的 NVIDIA CUDA 变体为例。
基本运行命令
docker run --runtime nvidia --gpus all \
-v ~/.cache/huggingface:/root/.cache/huggingface \
--env "HF_TOKEN=$HF_TOKEN" \
-p 8000:8000 \
--ipc=host \
vllm/vllm-openai:latest \
--model Qwen/Qwen3-0.6B
各参数要点:
-v ~/.cache/huggingface:/root/.cache/huggingface:挂载宿主机 Hugging Face 缓存目录,使模型权重在多次启动间复用,避免重复下载;--env "HF_TOKEN=$HF_TOKEN":传递 Hugging Face 访问令牌,用于拉取受限模型;--ipc=host:允许容器访问宿主机的共享内存。vLLM 基于 PyTorch,后者在进程间(尤其是张量并行推理)通过共享内存传递数据,缺少该参数或等价的--shm-size可能导致 OOM 或通信错误;- 镜像标签
vllm/vllm-openai:latest之后可以直接追加任意引擎参数(如--tensor-parallel-size 2),因为它们会作为vllm serve的命令行参数透传——从源码看,docker/Dockerfile 中vllm-openai目标设置了ENTRYPOINT ["vllm", "serve"],docker run尾部参数即被拼接为vllm serve <args...>。
该镜像同样兼容其他容器引擎,例如 Podman:
podman run --device nvidia.com/gpu=all \
-v ~/.cache/huggingface:/root/.cache/huggingface \
--env "HF_TOKEN=$HF_TOKEN" \
-p 8000:8000 \
--ipc=host \
docker.io/vllm/vllm-openai:latest \
--model Qwen/Qwen3-0.6B
镜像内不包含可选依赖
官方镜像出于许可证考虑不打包可选依赖(optional dependencies)。如需使用例如 audio 类可选依赖(在确认接受其许可证条款后),应基于官方镜像叠加一层安装,且注意版本与基础镜像一致:
FROM vllm/vllm-openai:v0.11.0
# 例如安装 audio 可选依赖
# 注意:vLLM 版本必须与基础镜像一致!
RUN uv pip install --system vllm[audio]==0.11.0
类似的,某些新模型可能只存在于 transformers 主分支,可以通过叠加一层安装开发版 transformers 解决:
FROM vllm/vllm-openai:latest
RUN uv pip install --system git+https://github.com/huggingface/transformers.git
旧 CUDA 驱动主机的前向兼容
vLLM 镜像预装了 CUDA 前向兼容库,允许在驱动版本低于镜像内 CUDA Toolkit 版本的主机上运行,但仅支持部分专业级/数据中心级 NVIDIA GPU。针对 CUDA 13 镜像:正常运行时最低主机内核为 Linux 4.15(CUDA 13 要求 R580 及以上驱动);兼容模式支持 R535 与 R570 主机驱动,其中 R535 可将最低内核要求降至 Linux 3.10,R570 仍需 Linux 4.15。开启方式是运行时设置环境变量:
docker run --runtime nvidia --gpus all \
-v ~/.cache/huggingface:/root/.cache/huggingface \
-p 8000:8000 \
--env "HF_TOKEN=<secret>" \
--env "VLLM_ENABLE_CUDA_COMPATIBILITY=1" \
vllm/vllm-openai <args...>
该特性会自动在加载 PyTorch 之前把 LD_LIBRARY_PATH 指向兼容库。从源码看,docker/Dockerfile 与 vllm-runtime-base 阶段(第 898~901 行)分别声明了 ENV VLLM_ENABLE_CUDA_COMPATIBILITY=0 作为默认关闭值,运行时用 -e 覆盖为 1 即可启用。
在容器中运行 vLLM Recipes 配置
vLLM Recipes 是官方的模型部署配方库,仓库提供了转换工具把它渲染成 vllm serve 可直接使用的 config.yaml 与 env.sh 两个文件,用法详见 tools/recipes/README.md。其流程为:Recipe(或 Recipe JSON)经 tools/recipes/recipe_json_to_vllm_config.py 转换,可选地结合 --detect-hardware(硬件检测)与工作负载参数(--input-tokens、--concurrency、--ttft-sla-ms 等)细化 tensor-parallel-size、gpu-memory-utilization 等部署敏感值,最终生成 config.yaml + env.sh。
在 Docker 中的做法是同时挂载这两个文件,并在容器启动时先 source env.sh 再启动 vLLM:
docker run --rm --gpus all \
-v ~/.cache/huggingface:/root/.cache/huggingface \
-v "$PWD/config.yaml:/recipe/config.yaml:ro" \
-v "$PWD/env.sh:/recipe/env.sh:ro" \
-p 8000:8000 \
--ipc=host \
--entrypoint /bin/bash \
vllm/vllm-openai:latest \
-lc 'source /recipe/env.sh && exec vllm serve --config /recipe/config.yaml'
注意这里通过 --entrypoint /bin/bash 覆盖了镜像默认的 ["vllm", "serve"] 入口,因为需要先加载环境变量文件;-lc 让 bash 以 login shell 方式执行单行脚本。两个文件均以 :ro 只读挂载,容器内路径统一放在 /recipe 下,便于与镜像内路径解耦。
跨容器持久化编译缓存
挂载 Hugging Face 缓存目录解决了模型权重复用问题,但每个新容器的 VLLM_CACHE_ROOT(默认 ~/.cache/vllm)仍然是空的——从源码看,vllm/envs.py 中定义了 VLLM_CACHE_ROOT: str = os.path.expanduser("~/.cache/vllm"),并且 VLLM_XLA_CACHE_PATH、VLLM_ASSETS_CACHE 等变量都以其为前缀派生。这意味着每次新建容器都要重新编译模型的 torch.compile 产物(inductor、Triton、AOT 编译缓存),显著拖慢冷启动。
解决办法是把命名卷挂到该路径,从第二个容器起复用编译缓存:
docker run --rm --gpus all \
-v ~/.cache/huggingface:/root/.cache/huggingface \
-v vllm-cache:/root/.cache/vllm \
-p 8000:8000 \
vllm/vllm-openai:latest \
meta-llama/Llama-3.1-8B-Instruct
关于缓存命中与失效机制,参见 docs/configuration/optimization.md 的 "Faster Startup" 一节:vLLM 会把 torch.compile 产物持久化在 VLLM_CACHE_ROOT 下,缓存目录可以跨机器拷贝或烤进容器镜像;任意模型变更、配置变更、相关 VLLM_* 环境变量变更、torch 构建或 GPU 型号变化都会使缓存失效并触发重编译。若希望缓存未命中时直接报错而不是静默重编译,可设置 VLLM_FORCE_AOT_LOAD=1。同一节还介绍了两个与之配合的加速手段:用 --kv-cache-memory 跳过启动时的显存 profiling(注意它把 KV cache 固定为给定值,仅在相同 GPU 与初始空闲显存下有效),以及用 --enforce-eager 完全跳过编译与 CUDA graph 捕获以换取最快启动。
以非 root 用户运行容器
CUDA 版 vllm/vllm-openai 镜像出于向后兼容默认以 root 运行,但镜像已经预置了一个内建 vllm 用户(UID 2000,GID 0),可直接用于非 root 场景:
docker run --rm --gpus all \
--user 2000:0 \
-p 8000:8000 \
vllm/vllm-openai:latest \
meta-llama/Llama-3.1-8B-Instruct
挂载路径必须跟着改:非 root 容器挂载模型或缓存卷时,应挂到 /home/vllm 之下而不是 /root,并且挂载目录需要对 group 0 可写。例如 Hugging Face 缓存应挂在 /home/vllm/.cache/huggingface:
docker run --rm --gpus all \
--user 2000:0 \
-v ~/.cache/huggingface:/home/vllm/.cache/huggingface \
-p 8000:8000 \
vllm/vllm-openai:latest \
meta-llama/Llama-3.1-8B-Instruct
从源码可以确认这一设计:docker/Dockerfile 的 vllm-runtime-base 阶段通过 useradd --uid 2000 --gid 0 --create-home --home-dir /home/vllm 创建用户,并执行 chown -R 2000:0 /home/vllm && chmod -R g+rwX /home/vllm,即 home 目录对 group 0 整体可写;同一阶段还把 uv 的 Python 安装目录与缓存(/opt/uv)设置为 group 0 可写(chgrp -R 0 /opt/uv + chmod -R g+rwX),保证非 root 进程能读取和执行构建期安装的 uv 与托管 Python 解释器。
构建默认非 root 的 vllm-openai-nonroot 镜像
如果希望构建出的镜像默认就以非 root vllm 用户运行,使用 opt-in 的 vllm-openai-nonroot 构建目标:
docker build --target vllm-openai-nonroot \
-t vllm-openai-nonroot:local \
-f docker/Dockerfile .
docker run --rm --gpus all \
-p 8000:8000 \
vllm-openai-nonroot:local \
meta-llama/Llama-3.1-8B-Instruct
对照 docker/Dockerfile,该目标在 vllm-openai 之上叠加了 USER vllm、WORKDIR /home/vllm,并把入口替换为 /usr/local/bin/vllm-nonroot-entrypoint.sh。
OpenShift 风格任意 UID 的入口脚本机制
vllm-openai-nonroot 目标还支持 OpenShift 风格任意 UID(例如 Restricted Pod Security Standard 下发的 runAsUser: 1000540000),前提是运行时 UID 是 group 0 的成员。此时 UID 在 /etc/passwd 中根本没有对应条目,$HOME 可能未设置或指向不可写的 /,getpass.getuser() 会因查不到 pwd 而失败。入口包装脚本 docker/entrypoints/vllm-nonroot-entrypoint.sh 负责兜底,其行为为:
- 若
$HOME未设置或不可写,依次回退到/home/vllm(可写时)、mktemp -d /tmp/vllm-home.XXXXXX(创建失败则最终回退/tmp); - 若调用方设置了非空的
HOME/USER/LOGNAME则原样保留,未设置时USER/LOGNAME默认为vllm,使getpass.getuser()不触发 pwd 查询; - 若
/etc/passwd对 group 0 可写(构建期已通过chgrp 0 /etc/passwd && chmod g=u打开该权限)且当前 UID 无条目,则追加一条合成 passwd 记录,使whoami、id -un等直接调用getpwuid()的工具也能得到一致的vllm身份; - 保留调用方 cwd(含只读挂载的 cwd,保证
--model ./xxx这类相对路径参数可解析),仅当 cwd 完全不可访问时才回退到$HOME; - 最后
exec vllm serve "$@"透传全部参数。
这些行为都有 shell 级单元测试覆盖:docker/entrypoints/test_vllm_nonroot_entrypoint.sh 用 stub 掉的 vllm 命令验证了 HOME/USER 保留、HOME 不可写回退、passwd 条目追加与去重、只读 cwd 保留、mktemp 失败回退 /tmp 等十余个用例,且无需 Docker 与 GPU 即可在宿主机直接运行 bash docker/entrypoints/test_vllm_nonroot_entrypoint.sh。
Kubernetes 安全上下文配置
在 Kubernetes 清单中,容器安全上下文按如下方式设置,并保持挂载的缓存/模型路径对 group 0 可写:
securityContext:
runAsNonRoot: true
runAsUser: 1000540000
runAsGroup: 0
fsGroup: 0
注意支持矩阵边界:运行时 UID 不在 group 0 中的场景不属于文档化的支持范围,因为其可能无法写入 /home/vllm 或 /opt/uv/cache。
从源码构建镜像
官方镜像基于仓库根目录的 docker/Dockerfile 构建。从源码看,文件头部的 ARG 默认值即各依赖的固定版本:CUDA_VERSION=13.0.3、PYTHON_VERSION=3.12、UBUNTU_VERSION=24.04、NCCL_VERSION=2.30.7(DeepEPv2 要求 NCCL >= 2.30.4)。构建命令为:
# 可选编译并发参数:--build-arg max_jobs=8 --build-arg nvcc_threads=2
DOCKER_BUILDKIT=1 docker build . \
--target vllm-openai \
--tag vllm/vllm-openai \
--file docker/Dockerfile
关键构建参数与说明:
--build-arg torch_cuda_arch_list="":默认构建面向全部 GPU 架构以最大化分发兼容;若只为当前 GPU 构建,可置空该参数把架构选择委托给 PyTorch。此时需要 GPU 对容器构建可见——标准 Docker BuildKit 构建默认不暴露 GPU,PyTorch 会退回到其常见架构列表;- Podman 用户如遇 SELinux 标签问题,可在
podman build时加--security-opt label=disable; - 使用预编译 wheel 加速构建:若未改动任何 C++/CUDA 内核代码,可加
--build-arg VLLM_USE_PRECOMPILED="1",构建系统会自动基于与上游main分支的 merge-base commit 找到已发布的预编译 wheel;用--build-arg VLLM_PRECOMPILED_WHEEL_COMMIT=<commit_hash>可指定具体 commit。从源码看,csrc-build阶段(docker/Dockerfile 中的VLLM_USE_PRECOMPILED/VLLM_MERGE_BASE_COMMITARG)把编译产物 wheel 打进/precompiled-wheels,最终build阶段仅提取其中的.so文件并跳过本地 CUDA 编译; max_jobs/nvcc_threads:控制 Ninja 并行任务数与 nvcc 线程数,两者配比影响内存占用,建议max_jobs明显大于nvcc_threads。
构建 Arm64/aarch64 镜像(Grace-Hopper / Grace-Blackwell)
使用 --platform "linux/arm64" 为 aarch64 系统构建,例如 GH200 上的参考命令:
# 示例:Nvidia GH200 服务器上构建(内存占用约 15GB,构建约 1475s,镜像约 6.93GB)
DOCKER_BUILDKIT=1 docker build . \
--file docker/Dockerfile \
--target vllm-openai \
--platform "linux/arm64" \
-t vllm/vllm-gh200-openai:latest \
--build-arg max_jobs=66 \
--build-arg nvcc_threads=2 \
--build-arg BUILD_BASE_IMAGE=pytorch/manylinuxaarch64-builder:cuda13.0-78e737ad29420ffc4800e677c51e2a852caf8359 \
--build-arg torch_cuda_arch_list="9.0 10.0+PTX"
对 (G)B300,建议改用 CUDA 13(--build-arg CUDA_VERSION=13.0.2 并同步 BUILD_BASE_IMAGE)。若在 x86_64 主机上交叉构建 arm64 镜像,需要先注册 QEMU user static 处理器:
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
此外,Dockerfile 还包含面向 NVIDIA Rubin 架构的预发布构建路径(Preview,仅限可获取 NVIDIA 内部前置条件的场景):通过 --build-arg INSTALL_RUBIN_PRERELEASE=true 启用,需配套 requirements/rubin-prerelease.txt 与 NVIDIA 内部 CUDA 13.4/13.5 开发镜像,且 Triton 必须从源码安装(TRITON_INSTALL_FROM_SOURCE_REPO/TRITON_INSTALL_FROM_SOURCE_REVISION 指定仓库与修订版本);其完整命令与驱动验证结果(如 CUDA 13.5 编译模式在 615.62.03 / 620.05 驱动上通过验证)可查阅安装文档中 "Building vLLM's Docker Image from Source for NVIDIA Rubin GPU Architecture" 一节的两个 docker buildx build 示例。
使用自建镜像
构建完成后,把运行命令中的镜像名替换为 -t 指定的标签即可:
docker run --runtime nvidia --gpus all \
-v ~/.cache/huggingface:/root/.cache/huggingface \
-p 8000:8000 \
--env "HF_TOKEN=<secret>" \
vllm/vllm-openai <args...>
小结
vLLM 的容器化部署围绕 vllm/vllm-openai 镜像展开:常规场景用 --gpus all、HF 缓存挂载与 --ipc=host 三条即可启动 OpenAI 兼容服务;生产场景建议通过命名卷持久化 VLLM_CACHE_ROOT 编译缓存以减少冷启动开销;安全敏感环境可用 --user 2000:0 或 vllm-openai-nonroot 目标运行非 root 容器,并配合 OpenShift 风格的 group 0 可写挂载策略;需要定制内核、依赖或架构(arm64)时,则以 docker/Dockerfile 为入口自建镜像,并善用 VLLM_USE_PRECOMPILED 预编译 wheel 机制缩短构建时间。所有关键行为均可在 docker/Dockerfile、docker/entrypoints/vllm-nonroot-entrypoint.sh 及其配套测试 docker/entrypoints/test_vllm_nonroot_entrypoint.sh 中查证。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00