简介:这是一份面向深度学习部署工程师与算法开发者的Docker部署vLLM源码资源,围绕QwQ-32B系列模型给出了AWQ、GPTQ-Int4、GPTQ-Int8三种量化方式的容器化部署方案。包内共3个文件,以html说明页为主,辅以inscode配置与gitignore文件,整体仅6KB,轻量易用。已有146人学习。读者可快速掌握从启动容器、安装vLLM到加载已有镜像的完整流程,并了解多模态大模型的部署思路;关键量化测试数据涵盖显存占用、GPU利用率、最大请求数等指标,为不同硬件环境下的量化选型提供实证参考。另外,资源还演示了curl接口测试与本地图片测试方法,方便验证模型服务是否正常。整体内容针对实际部署痛点,适合希望缩短环境搭建周期、快速跑通vLLM推理服务的开发者直接使用。
1. Docker 部署 vLLM:为什么这是当下跑大模型最省心的方案
如果你在一台刚装好的 GPU 服务器上手动部署过 vLLM,大概率经历过这样的深夜:Python 版本对了,CUDA 环境又冲突;torch 装好了,vLLM 编译又报缺库;折腾到凌晨两点,模型还没加载起来。而换一条docker run,同样一张卡、同一个模型,几分钟就能把推理服务跑起来。这就是 Docker 部署 vLLM 的核心价值——把 CUDA 驱动、Python 依赖、算子编译这些最容易翻车的环境问题,全部隔离进镜像里,宿主机只需要提供显卡和驱动。
vLLM 是目前大模型推理落地里绕不开的开源引擎,它靠 PagedAttention 管理 KV cache,靠连续批处理提升吞吐,官方镜像已经把这两套核心机制编译好并做了优化。对需要快速上线、多机迁移、复现生产环境的团队来说,Docker 是让 vLLM 从"能跑"变成"好部署"的最后一环。这篇文章从镜像选型、模型挂载、启动参数、源码构建到踩坑排查,按一条完整落地路径讲透。适合两类人:一类是刚接触推理服务、想尽快把模型跑起来的开发者,另一类是把 vLLM 放进生产环境、需要控制版本和依赖的运维工程师。
2. 部署前准备:镜像选型、模型挂载与 GPU 透传一个都不能少
很多人第一次部署 vLLM 时只盯着docker run那一行命令,结果跑起来之后各种问题:容器里看不到显卡、模型下载失败、系统盘被镜像撑爆。这些坑大多不是出在 vLLM 本身,而是部署前的基本功没做扎实。镜像、模型、GPU 这三件事,是后续所有操作的地基,顺序不能乱。
2.1 选镜像:官方 tag 怎么看、什么情况才需要源码构建
vLLM 官方镜像按照使用方式分成两大类:一类是运行时镜像,拉下来直接跑推理服务;另一类是构建环境镜像,配合源码构建流程使用。运行时镜像又以vllm/vllm-openai为主,它内置了 OpenAI 兼容的 API 服务,也是大多数生产部署的选择。
先看镜像 tag 的规律。官方版本号对应的 tag 通常会标注基础硬件环境,早先的镜像直接以 CUDA 版本为后缀,新一些的版本会区分cuda和cpu平台。我的习惯是:生产环境尽量锁定一个具体版本号,不要用latest。原因很简单,latest会跟着上游更新跑,某次重新拉镜像之后行为变了,排查起来成本极高。选 tag 时还要留意它对应的 CUDA 版本,比如某个 vLLM 版本是基于 CUDA 12.1 构建的,宿主机驱动版本低于对应要求,镜像虽然拉下来了,但内部算子初始化会失败。
什么时候需要用源码构建而不是直接用官方镜像?常见场景有三类:第一,需要打上某个尚未发布的特性补丁;第二,要针对特定显卡架构做算子优化;第三,要往镜像里塞私有化的模型处理器或自定义采样逻辑。除此之外,我一般不建议一上来就源码构建,官方镜像已经针对常见 GPU 架构做过编译优化,自己编译很可能性能反而更差,还平白多出几小时的构建时间。
2.2 模型文件落地:挂载目录、目录结构与权限
模型文件是 vLLM 容器运行时的核心输入。常见做法是把模型下载到宿主机某个固定目录,然后通过-v参数挂载进容器。为什么不直接让容器内部下载?因为容器是临时的,一旦容器删除,下载在容器里的模型文件也会跟着消失,下次启动还得重新下。挂载到宿主机之后,模型只维护一份,多套容器可以复用,升级镜像时模型文件也不需要重新准备。
我习惯把模型目录规划成下面这样:
/opt/models/ ├── llama3-8b-instruct/ │ ├── config.json │ ├── model-00001-of-00002.safetensors │ ├── model-00002-of-00002.safetensors │ └── tokenizer.json ├── qwen2-7b-instruct/ │ └── ... └── ---临时下载目录/模型仓库里的文件通过 Hugging Face 的下载工具拉到宿主机后,目录结构是现成的。挂载时只需要把最外层模型目录映射到容器里的固定路径,我的做法是统一挂到/data/models,这样容器命令行里的--model参数永远指向一个稳定的内部路径,宿主机上换模型包时,不需要改启动脚本里的路径。
权限问题也值得说一句。如果你用非 root 账号拉模型,挂载进容器后,vLLM 进程如果以 root 身份跑,读文件通常没问题;但如果模型文件权限是 600,且只有某个宿主机用户可读,容器内 UID 不匹配就会报权限错误。最省心的方案是给模型目录设置 755 权限,或者让容器内的运行用户 UID 和宿主机一致。
2.3 GPU 透传:容器里看得到显卡才算第一步
Docker 默认不把宿主机显卡暴露给容器,这一步需要额外组件支持:宿主机要装好 GPU 驱动,再装 NVIDIA Container Toolkit,然后在启动容器时通过--gpus参数把显卡透传进去。很多新手翻车就翻在这里——驱动装了、镜像也拉好了,容器起来的瞬间闪退,日志里提示找不到 CUDA 设备。
先做透传前的检查,按这个顺序确认:
# 1. 确认宿主机能识别显卡 nvidia-smi # 2. 确认 toolkit 已安装,并且 docker 能识别 GPU runtime docker info | grep -i runtime # 3. 跑一个最小的验证容器 docker run --rm --gpus all <某个cuda镜像> nvidia-smi第三步能正常打印显卡信息,说明透传链路是通的。这里有个容易忽略的细节:docker info里看不到nvidiaruntime,不代表 toolkit 没装好,可能是 docker 服务没重启,常见做法是重启 dockerd 让 runtime 注册生效。另外,如果你用的是容器管理平台(比如某类 Kubernetes 集群)而不是本机裸 Docker,GPU 调度方式又不一样,本文下面的命令以单机 Docker 为准。
GPU 透传这点说它是玄学也不过分,因为宿主机驱动版本、容器内 CUDA 版本、镜像构建时的 CUDA runtime 三者必须匹配到能协同工作的程度。经验是:驱动尽量新,镜像尽量选和驱动发布周期接近的版本,很多"容器起不来"的问题本质上都是驱动旧、镜像新导致的兼容性断裂。
3. 跑起第一个 vLLM 推理服务:最小 Docker 命令与参数拆解
前置条件检查完之后,真正动手的环节反而比较快。这一章给出一条最小可用的启动命令,然后逐个拆解其中最影响推理行为的参数,最后用一次实际的接口调用来验证服务是真的活着,而不是容器起来了但模型没加载。
3.1 最小启动命令:一条 docker run 让模型开口说话
假设你已经把某个 7B 级别模型下载到了/opt/models下,并且宿主机 GPU 透传验证通过,那么最精简的启动命令长这样:
docker run -d \ --name vllm-server \ --gpus all \ --ipc=host \ -v /opt/models:/data/models \ -p 8000:8000 \ vllm/vllm-openai:对应版本 \ --model /data/models/某个模型目录 \ --served-model-name my-model-d让容器后台运行,--name给容器固定名字,方便后续docker logs和docker stop。--ipc=host这行很多人容易漏,它让容器共享宿主机进程间通信命名空间,否则 vLLM 在加载 tokenizer 和部分并行算子时可能遇到共享内存不足的问题。-v把宿主机模型目录挂载进容器,-p 8000:8000把容器内的 API 服务暴露到宿主机 8000 端口。
容器起来之后,第一件事是看日志而不是直接调接口。vLLM 冷启动过程里,模型权重要加载进显存、KV cache 要分配、算子要预热,这个过程在 7B 模型上通常需要几十秒到几分钟。看到日志出现类似 "Starting vLLM API server" 或 "Uvicorn running on" 的字样,才算真正就绪。
docker logs -f vllm-server启动期间要多关注有没有 CUDA error 或 OOM 相关报错。只要日志里出现 "OutOfMemory"、"CUDA error"、"Illegal instruction" 这类关键词,先停掉容器,不要反复重启,原因大概率在下一节的参数上。
3.2 参数从哪里调:max-model-len、gpu-memory-utilization、tensor-parallel-size
vLLM 启动参数里,最影响稳定性的是max-model-len和gpu-memory-utilization,最影响吞吐的是tensor-parallel-size,这三个参数是部署必调的,默认值往往不是最优解。
--max-model-len决定模型能接受的最大上下文长度,包括输入和输出加起来的 token 数。这个值设得过小,超出长度的请求会被直接拒掉;设得过大,KV cache 预留空间成倍上涨,可能直接导致显存不够。我的经验是:先看模型训练时的上下文长度,再结合业务场景决定,比如单轮问答场景设 4096 足够,长文档分析场景可能要到 32768,但显存占用完全不是一个量级。
--gpu-memory-utilization控制 vLLM 能用多少比例的显存来缓存和推理,默认值是 0.9。这个参数是显存管理的关键,设得太高,加载模型权重后没有余量给 KV cache,服务一启动就 OOM;设得太低,KV cache 空间不足,高并发时吞吐上不去。通用做法是从 0.9 起步,观察启动日志里的显存分配情况再下调。如果一张卡跑 7B 模型,0.85 到 0.9 通常是比较稳的区域。
--tensor-parallel-size是张量并行度,定义把模型切分到几张卡上。单卡能装下模型时不要动它,保持默认 1;模型权重超过单卡显存容量,才需要设成 2、4 等数字。这里有一个新手常犯的错误:以为设了这个参数就能加速推理,实际上小模型在多卡上的通信开销可能盖过并行收益,反而更慢。
下面是一个带常用参数的完整示例:
docker run -d \ --name vllm-server \ --gpus all \ --ipc=host \ -v /opt/models:/data/models \ -p 8000:8000 \ vllm/vllm-openai:对应版本 \ --model /data/models/某个模型目录 \ --served-model-name my-model \ --max-model-len 8192 \ --gpu-memory-utilization 0.88 \ --tensor-parallel-size 1 \ --dtype bfloat16--dtype bfloat16是精度设置,新一些的 GPU 架构上 bfloat16 是主流选择,显存占用比 fp16 略低且训练推理一致性好一些。如果你的显卡不支持 bfloat16,服务会在启动时报错,改成float16即可。这个参数没有绝对标准,按显卡能力和模型仓库里标注的精度来选。
3.3 验证推理:用 OpenAI 兼容接口做冒烟测试
vLLM 对外提供的是 OpenAI 兼容格式的 HTTP 接口,这意味着你可以用标准的 HTTP 工具直接验证服务,不需要额外安装客户端库。服务就绪后,先查模型列表:
curl http://127.0.0.1:8000/v1/models正常情况下会返回一个 JSON 数组,里面包含你通过--served-model-name指定的模型名。这一步主要确认服务已启动、路由正常。然后发一个真正的补全请求:
curl http://127.0.0.1:8000/v1/completions \ -H "Content-Type: application/json" \ -d '{ "model": "my-model", "prompt": "用一句话解释什么是KV cache。", "max_tokens": 128, "temperature": 0.7 }'返回里的choices[0].text就是模型生成的文本。如果你在跑对话模型,想用聊天格式验证,可以请求/v1/chat/completions,请求体里用messages数组传对话历史。这一步冒烟测试通过,说明模型加载、显存分配、推理链路全部正常,接下来才谈得上性能调优。
这里提醒一个细节:max_tokens是单次请求允许生成的最大 token 数,业务方如果总是触发这个上限,返回文本会被截断但不是报错,不要把它当成异常。真正需要关注的错误码是 400(参数不合法)和 429(并发超过服务容量),这两个后面会再提到。
4. 源码构建 vLLM Docker 镜像:定制 Dockerfile 的正确姿势
标题里带着 [源码],说明不少人需要的不是直接拉官方镜像,而是自己把 vLLM 构建成镜像。源码构建最大的价值是可定制——你可以锁死 Python 版本、torch 版本、CUDA 版本,往里加自己写的预处理逻辑,甚至修改 vLLM 源码后重新编译。代价是构建时间长、坑也多。这一章讲清楚两条构建路线:基于官方镜像二次构建,和从源码完整编译。
4.1 基于官方镜像二次构建:加依赖不重编译
如果你的目标只是额外装一些 Python 包、拷贝一些自有脚本,完全不需要从源码编译。官方镜像已经包含了编译好的 vLLM 和依赖,你只需要在它上面叠一层自己的内容。这种方式构建速度快、失败率低,是我最常用的定制手段。
FROM vllm/vllm-openai:对应版本 # 切换到非 root 用户,避免容器内以 root 运行时的文件权限隐患 USER root # 安装自有依赖,注意用 --no-cache-dir 控制镜像体积 RUN pip install --no-cache-dir \ pydantic-settings \ ...... # 拷贝自定义的推理前置处理脚本 COPY ./preprocess.py /workspace/preprocess.py # 恢复官方镜像默认的用户 USER vllmdocker build -t my-vllm:1.0 .这个 Dockerfile 的关键在于没有重复编译 vLLM,FROM之后的每一步都只是增量修改,构建一般几分钟就完成。USER root和USER vllm之间的切换不是形式主义,官方镜像通常有一个专用运行用户,如果在 root 下拷贝文件,文件属主可能变成 root,后续运行用户读不了,启动时容易出权限错误。
如果你的定制内容包含一些需要编译的 Python 包(比如某个数据库驱动),建议在 Dockerfile 里先装编译工具链、再装包、最后清理工具链,避免镜像里残留编译器,体积能小不少。这条路线唯一需要注意的是:基础镜像版本升级时,你的增量层可能不兼容,所以FROM里的版本 tag 要写死,不要用latest。
4.2 从源码编译:Dockerfile 骨架与多阶段构建
当需要修改 vLLM 自身源码时,就必须从源码完整构建。vLLM 的源码构建本质上是两件事:编译自定义的 CUDA 算子,以及安装 Python 包及其依赖。整个编译过程吃内存、吃时间,还依赖基础镜像里的 CUDA 工具链。
下面是一个可行的多阶段 Dockerfile 骨架:
# 第一阶段:编译环境 FROM vllm/vllm-openai:对应版本 AS builder USER root # 克隆源码,固定到具体 commit 或 tag,保证可复现 RUN git clone https://github.com/合法仓库地址 /workspace/vllm && \ cd /workspace/vllm && \ git checkout 某个稳定版本tag # 安装构建依赖并执行安装 RUN cd /workspace/vllm && \ pip install --no-cache-dir -e . # 第二阶段:精简运行时,只保留运行所需文件 FROM vllm/vllm-openai:对应版本 AS runtime USER root COPY --from=builder /usr/local/lib/python3.*/dist-packages/ /usr/local/lib/python3.*/dist-packages/ COPY --from=builder /workspace/vllm/vllm/ /workspace/vllm/vllm/ USER vllmdocker build -t my-vllm-source:1.0 .第一阶段完成源码编译和安装,第二阶段把编译产物拷贝到干净的基础镜像里,这样最终镜像不携带源码目录、git 历史、临时编译文件。这个骨架里有几个关键决策点。
第一,不要自己选一个裸 Python 镜像从零装 torch。因为 vLLM 对 torch 和 CUDA 的版本耦合很深,从零构建等于把官方镜像已经解决的问题重新踩一遍。第二,git checkout必须锁定到具体版本,否则哪天重新构建拉到的源码变了,镜像行为就变了。第三,多阶段里COPY --from的路径要和基础镜像的 Python 包目录匹配,Python 小版本一变这个路径就会不对,构建时报错时优先排查这里。
4.3 构建缓存、依赖锁定与镜像瘦身
源码构建存在两个最常见的后悔药:一是没利用构建缓存,改了一行代码就得全量重编几小时;二是没锁依赖版本,今天能构建成功的镜像,下周同一个 Dockerfile 可能因为某个依赖发新版而失败。
针对构建缓存,Dockerfile 里层的顺序很关键。把 git clone 和依赖安装放在前面,把自己改动的源码放在后面,这样只要上游源码没变,重新构建时 Docker 会命中前面层级的缓存。针对依赖锁定,创建虚拟环境时用 pip 的requirements.txt固定到具体版本号,而不是>=这种范围写法。一旦某个算子依赖升级导致行为变化,只有锁死的版本能保证你"几个月后重建出一样的镜像"。
# 把 vLLM 依赖导出成锁定文件,提交到代码仓库 pip freeze > requirements-lock.txt # 构建时带上 buildkit,能明显提升缓存命中率 DOCKER_BUILDKIT=1 docker build --build-arg BUILDKIT_INLINE_CACHE=1 -t my-vllm-source:1.0 .镜像体积是另一个常见问题。vLLM 源码构建后的镜像动辄 5GB 起步,主要是 torch、CUDA 动态库和编译中间产物占空间。体积优化的重点不是盲目删文件,而是确保最终运行时只包含必需的三类内容:Python 运行环境、torch 和 CUDA 库、vLLM 编译产物。上面多阶段构建的COPY方式已经把源码和编译缓存排除在外,如果还想更激进,可以考虑基于官方镜像的 CUDA 基础层做二次构建,但收益有限,我一般做到多阶段这步就够了。
5. Docker 部署 vLLM 的避坑清单:5 个高发翻车现场
部署 vLLM 的坑主要集中在这几个环节:GPU 透传、显存管理、上下文长度、并发控制、镜像体积。每一类我都实际踩过,下面按现象、原因、解决三个维度拆开说,方便你遇到问题时直接定位。
5.1 容器里执行 nvidia-smi 报错:GPU 没透传进来
现象:容器能启动,但进去执行nvidia-smi提示command not found,或者 vLLM 服务日志里报 "CUDA_VISIBLE_DEVICES is set to empty"。
原因:这类问题绝大多数不是 vLLM 镜像缺东西,而是容器运行时根本没有把 GPU 设备传进去。nvidia-smi命令是宿主机的,容器里没有很正常,关键在于 CUDA 库能否访问设备。如果docker run时缺了--gpus all,或者宿主机没装容器 toolkit,容器内 CUDA 初始化必然失败。
解决:先在宿主机确认nvidia-smi正常,再用docker run --rm --gpus all <镜像> nvidia-smi验证透传链路。注意后面这个命令里的镜像可以就用 vLLM 镜像,它本身带 CUDA 库,能打印出显卡信息就说明链路通了。还有一个细节:如果你是在某类远程开发环境里操作,确认 docker 守护进程确实重启过,toolkit 安装后不重启 docker 服务,runtime 不会自动注册。
5.2 显存没满却 OOM:KV cache 参数与碎片问题
现象:nvidia-smi看显存占用不到一半,但 vLLM 启动时报 CUDA OOM,或者运行一段时间后请求失败并提示CUDA out of memory。
原因:vLLM 在启动阶段会按gpu-memory-utilization预留显存给 KV cache 和模型权重,这个预留和你看到的瞬时占用不是一回事。更隐蔽的是,当max-model-len设得很大时,KV cache 预留空间按最大上下文长度一次性分配,即使实际请求只有几百 token,空间也已经占死了。另外,某些算子在显存碎片化之后也会触发假性 OOM。
解决:把--gpu-memory-utilization从 0.9 逐步往下调,0.85、0.8 逐个试,找到当前模型和上下文长度组合下的稳定值。同时检查--max-model-len是不是设得远超业务需求,如果业务最长输入输出是 2048,就不要设成 32768,因为那是拿显存换用不上的能力。必要时在启动命令里加--enforce-eager观察是否降低显存峰值,但这个参数会牺牲部分性能,只能临时定位用。
5.3 首 token 延迟高:模型加载、前缀缓存与预热
现象:接口调通了,但第一个 token 等了好几秒甚至十几秒,后续 token 速度正常。或者每次冷启动后第一次请求特别慢。
原因:首 token 延迟高的主因是模型权重冷加载和显存分配。容器刚重启时,模型权重要从磁盘读进显存,第一次请求还要触发算子的懒初始化。另一个常见原因是请求带了很长的系统提示词,vLLM 对相同前缀可以做 KV cache 复用,但前缀不一致时,前缀部分必须重新计算。
解决:生产环境要做预热,在服务就绪后主动发一个带固定前缀的请求,让权重和算子完成加载。业务侧尽量设计稳定的系统提示词前缀,vLLM 的前缀缓存对多轮对话收益非常大。如果首 token 延迟依然高,可以考虑把模型目录放到 SSD 上,机械盘读 7B 模型的权重是一个肉眼可见的瓶颈。
5.4 并发一上来吞吐就掉:max-num-seqs 与批处理窗口
现象:单请求验证时性能没问题,压力测试一上,延迟飙升、吞吐反而下降,显存占用也没到瓶颈。
原因:vLLM 的核心优势是连续批处理,它会把并发请求拼在一个 batch 里推理。但这个 batch 的最大规模受--max-num-seqs限制,默认值未必适合你部署的模型。并发超过这个值时,请求会排队,表现为吞吐上不去、尾部延迟变大。更隐蔽的是,如果每请求的max_tokens设得很大,单个请求占住 batch 的时间边长,其他请求就得等。
解决:观察监控里的排队请求数,逐步调大--max-num-seqs,同时观察显存余量。这个参数不是越大越好,batch 越大,单次迭代的显存占用越高,超出 KV cache 容量就会触发新的分配。通用做法是从默认值翻倍试探,配合上面讲到的gpu-memory-utilization一起调。业务侧的max_tokens也要约束,能用 128 解决的需求不要放成 2048。
5.5 源码构建的镜像 5GB+:把编译中间产物留在构建层
现象:源码构建出来的镜像体积超大,推送私有仓库耗时久,磁盘占用高,多台机器拉取时网络压力大。
原因:源码构建默认会在镜像里保留 torch 编译缓存、pip 下载缓存、git 历史甚至完整的源码目录。基础镜像本身已经不小,加上这些中间产物,体积轻松翻倍。很多人在最终运行时镜像里还留着pip install -e .生成的 egg-link 文件,指向源码目录,导致源码目录不能删,否则运行时报找不到模块。
解决:遵循前面第 4 章的多阶段构建思路,最终阶段只拷贝必要的运行文件。Dockerfile 里把pip install --no-cache-dir和git clone --depth 1用起来,这两个参数立竿见影。构建完成后用docker image history 镜像名查看每一层的大小,定位具体是哪一层引入了大文件,再做针对性优化,不要凭感觉删东西。
6. 最后一公里:让 vLLM 容器进入可观测、可编排的服务状态
模型能跑通只是第一步,真正投入生产前,还需要把容器纳入统一的健康检查、监控和编排体系。vLLM 本身暴露了 Prometheus 格式的监控指标,Docker 层可以配合健康检查和自动重启策略,让服务从"手工启动"升级为"无人值守也能自愈"。
先给容器加上健康检查和自动重启。健康检查用 Docker 的--health-cmd就行,vLLM 的/health接口就是为这个准备的,返回 200 表示模型已就绪。自动重启用--restart unless-stopped,只要宿主机 Docker 不手动停容器,服务崩溃或机器重启后都会自动拉起。注意,restart策略是兜底,不是万能的,如果是显存配置错误导致的持续崩溃,重启一百次也还是崩溃,健康检查的日志才是定位关键。
docker run -d \ --name vllm-server \ --gpus all \ --ipc=host \ --restart unless-stopped \ --health-cmd "curl -f http://127.0.0.1:8000/health || exit 1" \ --health-interval 30s \ --health-start-period 60s \ --health-retries 3 \ -v /opt/models:/data/models \ -p 8000:8000 \ vllm/vllm-openai:对应版本 \ --model /data/models/某个模型目录 \ --served-model-name my-model--health-start-period 60s是给模型加载留的启动宽限期,如果你的模型更大,加载时间超过 60 秒,这个值要相应调大,否则健康检查会在模型还没就绪时反复判定失败,触发多余的重启。这是第一类常见问题:健康检查把启动中的容器当成不健康,导致反复重启。
第二类常见问题是指标采集。vLLM 的 Prometheus 指标默认和 API 共用 8000 端口,路径是/metrics,里面有几个指标值得重点关注:vllm:num_requests_running反映当前正在推理的请求数,vllm:num_requests_waiting反映排队请求数,vllm:gpu_cache_usage_perc反映 KV cache 使用率。当gpu_cache_usage_perc长时间接近 1.0,且num_requests_waiting不断上涨,说明要么加容量,要么限制并发,和前面第 5 章说的参数调优是同一个问题的两条观察路径。把这些指标接到现有监控里,比出了问题再看docker logs要快得多。
第三类问题是版本升级的灰度策略。Docker 的优点在这里体现得最充分:新版本镜像构建好之后,先在另一个端口起一个同名模型的容器,用业务流量子集压测,确认延迟和吞吐正常,再切换流量。切换时不要直接删旧容器,先停掉旧的docker stop,再启动新的,这样即使新版本有问题,旧容器还留着,一条命令就能回滚,不用重新拉镜像、重新配参数。这个习惯我从上线第一个模型起一直保持到现在,救过大急。
vLLM 的 Docker 部署走到这一步,已经不是"能不能把模型跑起来"的问题,而是"跑了之后怎么持续稳定地服务"的问题。回顾这段时间的实践,我最大的教训是:所有看起来像玄学的问题,最后都查到了确切的配置原因——要么是驱动版本和镜像不匹配,要么是显存参数和上下文长度打架,要么是并发参数触到了上限。先把官方镜像跑通,再逐步改造,比一开始就源码构建、全套参数上满要靠谱得多。希望这篇笔记能帮你少走几段弯路,让 vLLM 在 Docker 里稳稳地跑起来。
本文还有配套的精品资源,点击获取