很多人一说在 Rocky Linux 9.x 上跑大模型推理第一反应就是麻烦装 NVIDIA 驱动、配 CUDA、搞 Docker GPU 透传、再装 vLLM 0.16.0任何一步报错都能折腾半天。我在公有云英伟达 GPU 实例上完整踩过一遍之后发现只要把顺序和依赖理清楚从裸系统到跑起一个兼容 OpenAI 接口的推理服务15 分钟是真实可行的——前提是别踩那些我后来整理出来的坑。这篇就把我从云主机选型、网络配置、驱动安装到 vLLM 部署、模型加载、接口验证的完整过程写下来适合手里有一台 NVIDIA GPU 云主机、想快速把 Qwen 或 DeepSeek 这类模型通过 vLLM 提供出去的开发者参考新手也能照着操作。1. 为什么我选 Rocky Linux 9.x vLLM 这套组合先回答一个很多人问的问题云厂商 GPU 实例默认给的大多是 Ubuntu为什么我坚持用 Rocky Linux 9.x我的理由很实际。Ubuntu 的优势是包新但问题也出在新上NVIDIA 驱动模块是靠 DKMS 挂到内核上的Ubuntu 的 apt 一升级内核驱动模块经常失效nvidia-smi第二天就可能报couldnt communicate with the NVIDIA driver。对于要长期跑推理服务的生产环境这种不确定性很烦人。Rocky Linux 9.x 基于 RHEL 9 的稳定分支更新节奏保守配合 DKMS 编译的 NVIDIA 驱动跑几个月都不出问题。另外 RHEL 系自带 NetworkManager 和 firewalld这套网络和防火墙管理方式做运维的人都很熟不需要额外学习成本。再聊 vLLM 0.16.0。它是目前把大模型推理性能和易用性平衡得比较好的方案之一。核心优势有三个PagedAttention把 KV Cache 按页管理显存利用率比传统方案高很多同样一张卡能塞更大的模型、更长的上下文。Continuous Batching请求不用排队等上一批跑完而是动态插入当前 batch并发一高吞吐也不会直线掉。原生 OpenAI 兼容接口启动后直接提供/v1/chat/completions、/v1/embeddings等端点你之前写的 OpenAI SDK 代码几乎不用改就能对接。0.16.0 这个版本号不需要太纠结。vLLM 迭代很快旧教程里的核心启动参数基本延续本节的操作流程在 0.15.x 到 0.16.x 上都通用。我之所以锁定 0.16.0是因为部署时 Docker 镜像和 PyPI 包直接用对应版本标签方便复现和后期升级。云主机的选择直接影响后续部署的顺利程度。我按实际使用场景给一个参考显存档位推荐型号适合场景24GBNVIDIA L20 / A107B~14B 模型单卡推理开发测试48GBNVIDIA L40S / L2014B~32B 模型中等并发80GBNVIDIA A100 / H10070B 级模型高并发生产张量并行一个容易忽略的点购买实例时优先选预装 NVIDIA 驱动和 Docker的镜像。公有云平台通常提供这类GPU 基础镜像省掉最耗时的驱动编译环节。标题说的 15 分钟前提就是从这里开始的——如果从零装驱动光编译就要 5~10 分钟就不叫 15 分钟了。选不到预装镜像也没关系下面我会把手动安装的步骤也完整写出来多花 20 分钟而已。2. 基础环境一步不落的搭建过程2.1 网络配置先解决 IP 漂移和防火墙云主机拿到手先别急着装东西把网络和防火墙搞定后面少很多麻烦。Rocky Linux 9 的网络配置和 CentOS 7 时代不一样了/etc/sysconfig/network-scripts/ifcfg-eth0那套已经废弃现在统一走 NetworkManager配置文件在/etc/NetworkManager/system-connections/目录下。云平台上普通实例的内网 IP 一般重启不会变但如果你用的是按量付费的临时实例或者基于自定义模板克隆出来的机器IP 漂移是真实存在的。配合 Docker 容器固定端口监听时IP 一变很容易出现服务活着但连不上的诡异问题。如果需要手动配置静态 IP我建议用nmcli比手改配置文件直观很多# 先看当前网卡名和连接名一般是 enp0s3 / ens5 / System eth0 之类 nmcli con show # 修改连接配置IP 换成你实际的规划地址 nmcli con mod System eth0 \ ipv4.addresses 10.0.10.2/24 \ ipv4.gateway 10.0.10.1 \ ipv4.dns 223.5.5.5,8.8.8.8 \ ipv4.method manual # 重启连接生效 nmcli con up System eth0 # 验证 ip addr show这里有个经验改之前一定先确认云平台 VPC 网段和网关地址填错了直接 SSH 断开只能在控制台用 VNC 救回来。防火墙方面Rocky 9 默认 firewalld 是开启的vLLM 默认监听 8000 端口必须放行firewall-cmd --permanent --add-port8000/tcp firewall-cmd --reload还有一步经常被漏掉——云控制台的安全组规则。防火墙放行只解决系统内部安全组没放行 8000 端口外部仍然访问不了。买完实例后记得去控制台把入方向 8000/TCP 加上最好顺手把来源 IP 限定成你自己办公网段别裸奔到 0.0.0.0/0毕竟这是个可以执行任意模型推理的接口。2.2 NVIDIA 驱动装错一次排查半小时如果云厂商镜像里已经带 NVIDIA 驱动直接跳过这一步用nvidia-smi验证一下即可。需要手动装的话Rocky 9 上我最推荐的是 NVIDIA 官方 RHEL 9 仓库方式比下载.run脚本更干净也方便后续用dnf更新# 先安装内核开发包版本必须和当前内核完全一致 dnf install -y kernel-devel kernel-headers kernel-devel-uname-r $(uname -r) # 添加 NVIDIA 官方仓库 dnf install -y https://developer.download.nvidia.com/compute/cuda/repos/rhel9/x86_64/cuda-rhel9.repo # 安装驱动latest-dkms 会随内核自动重编模块 dnf module install -y nvidia-driver:latest-dkms # 验证 nvidia-smi看到类似这样的输出就代表驱动正常----------------------------------------------------------------------------- | NVIDIA-SMI 570.124.06 Driver Version: 570.124.06 CUDA Version: 12.8 | -----------------------------------------------------------------------------几个关键点我必须强调kernel-devel-uname-r $(uname -r)这种写法可以保证版本精确匹配。内核和开发包版本不一致DKMS 编译必失败装完nvidia-smi一定报错。如果之前手动跑过.run安装脚本建议先nvidia-uninstall卸载干净再走 dnf 路线避免两份驱动打架。UEFI Secure Boot 开启的机器DKMS 模块签名会失败。公有云 GPU 模板通常默认关闭如果你用的是自建虚拟化环境进 BIOS 关掉或者配置 MOK 签名否则驱动永远加载不上。如果启动时报nouveau模块冲突在/etc/modprobe.d/blacklist-nvidia.conf里写上blacklist nouveau然后重建 initramfs。安装完之后最好重启一次确认重启后nvidia-smi依然正常。这一步能过滤掉大量内核更新后驱动失效的隐患。2.3 Docker 和 NVIDIA Container Toolkit打通 GPU 透传vLLM 的 Docker 镜像自带完整 CUDA 运行库宿主机不需要装 CUDA Toolkit只需要两样东西Docker 和 NVIDIA Container Toolkit。前者提供容器运行环境后者负责把 GPU 设备透传给容器。安装 Dockerdnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin systemctl enable --now docker安装 NVIDIA Container Toolkitdnf install -y dnf-utils yum-config-manager --add-repo https://nvidia.github.io/libnvidia-container/stable/rpm/nvidia-container-toolkit.repo dnf install -y nvidia-container-toolkit # 关键一步把 nvidia 运行时注册到 Docker nvidia-ctk runtime configure --runtimedocker # 重启 Docker 生效 systemctl restart docker验证 GPU 透传是否打通用这个最直接的命令docker run --rm --gpus all nvidia/cuda:12.8.0-base-ubi9 nvidia-smi容器里能看到和宿主机一致的 GPU 信息说明透传成功。这里要提醒一句很多人装完 toolkit 忘了执行nvidia-ctk runtime configure --runtimedocker导致容器里永远看不到 GPU。这一步的本质是修改/etc/docker/daemon.json把nvidiaruntime 写进 Docker 配置。如果你看到容器报错could not select device driver with capabilities: [[gpu]]十有八九就是漏了这一步。3. vLLM 0.16.0 的两种部署路径3.1 路径一官方 Docker 镜像最快跑通Docker 方式是我的首选因为镜像里已经编译好所有 CUDA 依赖和 vLLM 本体宿主机只需要一个干净驱动整个部署过程就是拉镜像、起容器、加载模型三步。拉取镜像docker pull vllm/vllm-openai:v0.16.0启动容器这里我以 24GB 显存跑DeepSeek-R1-Distill-Qwen-7B为例docker run --gpus all \ --ipchost \ -p 8000:8000 \ -v /opt/models:/models \ --env HUGGINGFACE_HUB_CACHE/models/.cache \ vllm/vllm-openai:v0.16.0 \ --model /models/DeepSeek-R1-Distill-Qwen-7B \ --served-model-name deepseek-r1-7b \ --max-model-len 32768 \ --gpu-memory-utilization 0.9拆解一下几个关键点--ipchost多进程 IPC 共享不设的话在某些数据集分布式加载场景会报 shared memory 不足。这是 vLLM 官方推荐加的老教程经常漏。-v /opt/models:/models模型权重目录挂载。我习惯把大模型放独立数据盘路径统一放/opt/models避免重装系统或换实例时重新下载几十 GB 权重。--served-model-name对外暴露的模型名。起什么名都行客户端请求时model字段必须和它一致。--max-model-len 32768最大上下文长度。这个值直接影响 KV Cache 显存占用后面会单独讲。--gpu-memory-utilization 0.9允许 vLLM 使用单卡 90% 显存做模型权重和 KV Cache留 10% 给驱动显示和紧急情况。容器启动后日志会进入模型加载阶段看到Starting vLLM server和Uvicorn running on http://0.0.0.0:8000就说明服务起来了。3.2 路径二pip 虚拟环境方式便于二次开发如果你不只是想跑服务还要改 vLLM 源码、调试自定义模型或者公司网络不允许拉 Docker 镜像那走 pip 方式更合适。Rocky 9 默认 Python 是 3.9vLLM 对 Python 版本有下限要求我建议直接用 Python 3.11dnf install -y python3.11 python3.11-devel /usr/bin/python3.11 -m venv /opt/vllm-env source /opt/vllm-env/bin/activate # 升级 pip 并安装 vllm pip install --upgrade pip pip install vllm0.16.0安装完直接起服务python -m vllm.entrypoints.openai.api_server \ --model /models/DeepSeek-R1-Distill-Qwen-7B \ --served-model-name deepseek-r1-7b \ --max-model-len 32768 \ --gpu-memory-utilization 0.9 \ --port 8000用python -m方式比直接敲vllm serve更可控可以在前面加nohup或用 systemd 管理。两种方式怎么选我的判断标准很简单如果是纯部署交付选 Docker环境隔离好、回滚方便、团队成员拉起来就能跑如果要做模型适配、性能调优或二次开发选 pip 方式改代码和调试都更直接。很多公司是把 pip 方式调好后再封装成自己的镜像两条路径并不矛盾。3.3 关键启动参数逐项拆解vLLM 的启动参数很多但真正影响部署成败的就这几个我整理成表格方便对照参数作用我的建议--model模型路径或 HuggingFace 模型名优先用本地路径避免运行时下载--served-model-name对外暴露的模型名自定义短名方便客户端调用--max-model-len最大上下文长度按业务需求设置别一味求大--gpu-memory-utilizationvLLM 可用显存比例默认 0.9显存紧张可调 0.85--tensor-parallel-size张量并行卡数单卡默认 1多卡按实际卡数设置--dtype模型权重精度默认 auto显存不足可试 half--quantization量化方式配合 AWQ/GPTQ 量化模型使用--enforce-eager关闭 CUDA Graph显存紧张时开吞吐略降--max-model-len和显存的换算关系是新手最容易懵的地方。大模型推理时显存占用主要是两块模型权重 KV Cache。7B 模型 bf16 精度权重约 14GBKV Cache 则随max-model-len和并发数线性增长。假设 24GB 显存、权重占 14GB剩下的 10GB 里如果塞 32768 上下文单并发还好并发一高就会 OOM。所以部署前先想清楚业务场景聊天应用给 8192~16384 就够长文档分析再上 32768 甚至 65536。4. 第一次推理验证从模型下载到 API 响应4.1 模型权重的两种获取方式vLLM 启动时--model参数填模型名它会自动去 HuggingFace 下载但我强烈建议手动预下载到本地。原因很简单自动下载一旦中断要重来而且路径在容器和宿主机之间不好管理。我习惯用huggingface-cli先拉权重pip install -U huggingface_hub[cli] mkdir -p /opt/models huggingface-cli download deepseek-ai/DeepSeek-R1-Distill-Qwen-7B \ --local-dir /opt/models/DeepSeek-R1-Distill-Qwen-7B如果你的服务器访问 HuggingFace 速度不理想可以设置镜像环境变量加速这个在很多团队已经验证可用export HF_ENDPOINThttps://hf-mirror.com huggingface-cli download deepseek-ai/DeepSeek-R1-Distill-Qwen-7B \ --local-dir /opt/models/DeepSeek-R1-Distill-Qwen-7B下载前确认三件事磁盘空间、磁盘空间、还是磁盘空间。7B 模型 bf16 权重约 15GB70B 模型要 140GB 以上下载前df -h看一眼别把系统盘塞爆。另一个细节模型目录挂载进容器时注意目录属主和 SELinux 标签报Permission denied或failed to mount时在挂载参数后面加:Z让 Docker 自动调整标签或者chown -R 1000:1000 /opt/models容器内默认用户 UID 是 1000。4.2 用 OpenAI 兼容接口做一次真实请求服务起来后先用 curl 做一次最简单的请求验证链路是否真的通了curl http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: deepseek-r1-7b, messages: [{role: user, content: 用一句话解释 vLLM 是什么}], max_tokens: 256, temperature: 0.7 }正常会返回一段 JSON里面有choices、usage字段usage.completion_tokens显示实际生成了多少个 token。这一步如果通了整个部署链路基本没问题。如果你习惯用 PythonOpenAI SDK 直接就能接因为 vLLM 的接口就是照 OpenAI 格式做的from openai import OpenAI client OpenAI( base_urlhttp://localhost:8000/v1, api_keyEMPTY # vLLM 默认不校验 key随便填 ) resp client.chat.completions.create( modeldeepseek-r1-7b, messages[{role: user, content: 写一段 100 字的自我介绍}], max_tokens256 ) print(resp.choices[0].message.content)这里有个常被忽略的点请求里model字段必须等于启动参数里的--served-model-name。很多人直接填模型原始名比如deepseek-ai/DeepSeek-R1-Distill-Qwen-7B结果报model not found其实不是模型没加载而是名字对不上。4.3 性能预检显存、吞吐、延迟怎么看服务起来别急着上线先用几分钟做性能预检。预检分三块一看显存。另开一个终端跑watch -n 1 nvidia-smi观察Memory-Usage和Volatile GPU-Util。稳定的推理服务显存使用曲线应该接近一条平线因为 vLLM 启动时就把模型权重和 KV Cache 池分配好了。如果显存波动剧烈或频繁接近上限说明并发控制有问题。二看日志吞吐。vLLM 启动后日志里会持续输出类似这样的统计数据Avg prompt throughput: 18.2 tokens/s Avg generation throughput: 45.6 tokens/s Running: 3 reqs, Waiting: 2 reqs这里的信息量很大Avg generation throughput是每卡每秒生成 token 数Running和Waiting的比值能反映并发排队情况。如果Waiting一直很高说明请求已经超出单卡处理能力要么加卡做张量并行要么限流。三看单请求延迟。用上面那个 curl 命令配合time统计首 token 时间和总耗时。首 token 时间超过 3 秒、总耗时超过 20 秒业务侧体验就会明显变差这时候要检查是不是模型权重没有量化、max-model-len设太大导致 KV Cache 吃紧或者 GPU 利用率根本没跑上去。5. 高发坑位与排查链路5.1 nvidia-smi 连接失败驱动模块层面的排查这是露脸频率最高的问题报错一般是NVIDIA-SMI has failed because it couldnt communicate with the NVIDIA driver. Make sure that the NVIDIA driver is installed and running.注意出现这个报错不代表显卡坏了绝大多数时候是驱动模块没有加载进内核。我的排查顺序是固定的按步骤走能少走很多弯路看内核里有没有一个叫nvidia的模块lsmod | grep nvidia如果空说明模块没加载。看模块文件是否存在ls /usr/lib/modules/$(uname -r)/kernel/drivers/video/nvidia.ko.xz文件不存在说明当前内核根本没有编译对应驱动模块。查 DKMS 状态dkms status如果显示nvidia/570.124.06: installed就正常显示Unable to install或没有记录就是 DKMS 编译失败了。检查编译失败的日志cat /var/lib/dkms/nvidia/*/build/make.log | tail -50最常见的失败原因就是kernel-devel版本和uname -r不一致。解法非常简单——重新安装匹配版本的内核开发包然后强制重编模块dnf install -y kernel-devel-uname-r $(uname -r) dkms autoinstall重启前确认 secure boot 已关闭然后reboot。重启后如果nvidia-smi还是报同样错误继续查dmesg | grep -i nvidia看有没有具体的权限或签名报错。这个链路帮我救回过不止一台机器。很多时候大家一慌就重装驱动其实问题只是内核更新后 DKMS 模块没重建重装驱动反而把环境搞得更乱。5.2 容器内看不到 GPUruntime 配置的锅宿主机nvidia-smi正常但容器一启动就报0 GPU is visible, but the requested number of GPUs is 1. docker: Error response from daemon: could not select device driver with capabilities: [[gpu]].排查链路如下先确认 toolkit 是否安装成功nvidia-container-cli info如果这条命令本身报错按它提示的缺失库处理一般是libnvidia-container没装完整。看 Docker runtime 配置是否生效cat /etc/docker/daemon.json正常应该有一行runtimes: {nvidia: {path: nvidia-container-runtime, ...}}。没有就是漏了nvidia-ctk runtime configure --runtimedocker补上再重启 Dockernvidia-ctk runtime configure --runtimedocker systemctl restart docker检查nvidia-uvm模块lsmod | grep nvidia_uvmCUDA 依赖nvidia_uvm它没加载时容器能起来但无法做 GPU 计算。手动加载modprobe nvidia_uvm另外一个小坑如果你用的是 podman 或 containerd 而不是 Docker--gpus参数的行为不一样toolkit 的配置也要对应调整。文章里我默认 Docker因为它在云上最通用。5.3 端口通不了防火墙、安全组和 SELinux 三座山本机 curllocalhost:8000正常但外网访问超时这个问题通常不是 vLLM 的问题而是网络路径上有三重拦截firewalld前面已经放行了 8000 端口。检查当前状态用firewall-cmd --list-all看到ports: 8000/tcp才行。云安全组控制台里入方向规则必须允许 8000/TCP。常见情况是云厂商模板默认只放行 22 和 3389其他端口一律拒绝。SELinux容器映射端口时 SELinux 一般不放行。最简单且安全的做法是检查并仅针对容器服务放行。如果你测试环境图快可以临时setenforce 0但生产环境我建议用正确的方式ausearch -m avc -ts recent查看 SELinux 拦截记录再对应写 allow 规则。排查顺序建议从外到内先 telnet 云主机的公网 IP 8000 端口不通再查安全组安全组通了我们再进主机测firewall-cmd。一层层缩小范围比一次性在所有地方瞎改高效得多。5.4 显存不够不是模型太大是参数没算明白部署时最常见的实际错误是CUDA out of memory。很多时候模型明明装得下是参数设置把显存算爆了。一个 7B 模型的显存估算公式很简单模型权重7B × 2 字节bf16 约 14GBKV Cache粗略估算为 2 × 层数 × 头维度 × 最大长度 × batch实际运行起来 24GB 显卡上给 32768 上下文的 KV Cache 要预留 6~10GB中间激活值、CUDA context 等杂项约 1~2GB所以 24GB 卡跑 7B 模型max-model-len设 32768、并发 8 时已经很紧张。遇到 OOM 时按优先级调整把--max-model-len降到 16384 或 8192效果立竿见影。把--gpu-memory-utilization从 0.9 降到 0.85给系统留更多余量虽然 KV Cache 池会变小但更稳定。启用--enforce-eager关闭 CUDA Graph 以节省显存代价是吞吐略有下降。换用 AWQ/GPTQ 量化权重7B 模型从 bf16 的 14GB 降到 4bit 的约 4GB那 24GB 卡跑 32B 量化模型都游刃有余。还有一个我踩过的坑--tensor-parallel-size设成 2结果机器上只有一张卡vLLM 启动直接报错。多卡并行前一定先确认nvidia-smi里看到几张卡再设置并行度。最后分享一个小体会vLLM 部署这件事真正花时间的从来不是 vLLM 本身而是它底下的驱动、容器和网络环境。我在这台 Rocky Linux 9.x 机器上把所有流程记成了一套标准操作清单之后后续给新实例部署基本就是复制粘贴、换模型路径的事。这套链路里坑的位置几乎是固定的——DKMS 没编上、runtime 没注册、安全组没放行——你把这几个点提前验证一遍15 分钟真的够用。