【阅读前提示】:本次vllm非Docker部署,而是使用python框架形式部署


0. 前言

0.1 背景

公司最近把推理框架从 Ollama 整体迁到 vLLM,原因很简单:吞吐翻 3 倍、延迟降一半、显存省 30 %。

整套流程踩坑无数,特地把「最小可复现步骤」整理成这篇 blog,希望能帮后来者快速跑通第一行 vllm serve

阅读对象:已经能把各类模型跑在 Ollama、现在想迁移到 vLLM 的运维 / 算法 / DevOps 同志。

0.2 天坑——安全启动问题

有一个非常大的坑:UEFI启动默认开启Secure Boot(安全启动),所以如果你是在虚拟机进行部署,建议使用Bios引导,不然后面容易掉坑里,使用 NVIDIA驱动 时可能遇到 Secure Boot 相关问题

当你 安装完 CUDA 后,系统尝试加载 NVIDIA 内核驱动(如 nvidia.ko)时,如果:

  • 你使用的是 官方 NVIDIA 驱动(非 Ubuntu 自带的开源 nouveau
  • 并且该驱动 未被签名未被你系统的 Secure Boot 密钥信任

那么恭喜你 内核会拒绝加载该驱动模块,导致:

  • nvidia-smi 报错(如 “NVIDIA-SMI has failed because it couldn’t communicate with the NVIDIA driver”)
  • CUDA 程序无法运行(因为没有 GPU 驱动支持)

【解决方案】(如果遇到驱动加载失败):

  1. 禁用 Secure Boot(最简单)
    进入 BIOS/UEFI 设置,关闭 Secure Boot。

  2. 为 NVIDIA 驱动签名并注册到 MOK(Machine Owner Key)
    Ubuntu 在安装 NVIDIA 驱动时,如果检测到 Secure Boot 开启,通常会提示你设置一个 MOK 密码,并引导你重启后在 MOK 管理界面注册自签名密钥。
    如果你跳过了这一步,可能需要手动操作(较复杂)(建议重开)

  3. 使用 Ubuntu 官方仓库中已签名的 NVIDIA 驱动
    例如通过 ubuntu-drivers 安装:

    sudo ubuntu-drivers autoinstall
    

    这些驱动通常已由 Canonical 签名,兼容 Secure Boot。


1. 环境准备:Ubuntu Server 24.04.03 LTS 安装

1.1 下载镜像

访问https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/24.04/,寻找所需版本,此处以ubuntu-24.04.3-live-server-amd64.iso为例

# 国内推荐清华镜像站,速度 50 MB/s+
wget https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/24.04/ubuntu-24.04.3-live-server-amd64.iso

1.2 安装选项

  • 【SSH:勾选 Install OpenSSH server,装完就能 ssh 进去,省得接显示器】
  • 其余看个人需求

2. NVIDIA 驱动 + CUDA安装

2.1 禁用 nouveau(必须)

echo "blacklist nouveau" | sudo tee /etc/modprobe.d/blacklist-nouveau.conf
echo "options nouveau modeset=0" | sudo tee -a /etc/modprobe.d/blacklist-nouveau.conf
sudo update-initramfs -u && reboot

2.2 NVIDIA 驱动安装

⚠️ 注意:以下方法适用于通过官方 .run 文件安装 NVIDIA 专有驱动。若你计划使用 Ubuntu 官方仓库或 CUDA 仓库中的驱动,也即使用apt-get进行安装(如 nvidia-driver-535nvidia-open),请勿混合使用 .run 驱动与包管理器驱动,否则可能导致系统不稳定。

2.2.1 清理现有 NVIDIA 驱动
sudo apt --purge remove '*nvidia*'
sudo apt autoremove
sudo apt autoclean
2.2.2 重启系统以确保旧驱动完全卸载:
sudo reboot
2.2.2 下载 NVIDIA 驱动

访问 NVIDIA 驱动下载页面,在“手动搜索驱动程序”中选择你的显卡型号,下载类型选择 Production Branch,获取对应 .run 文件的下载链接。

NVIDIA-Linux-x86_64-580.82.09 为例:

wget https://cn.download.nvidia.com/XFree86/Linux-x86_64/580.82.09/NVIDIA-Linux-x86_64-580.82.09.run
2.2.3 安装驱动

⚠️ 安装前请确保已停止图形界面(如 GNOME),建议在 文本模式(TTY) 下运行。尤其注意:使用SSH连接Ubuntu≠系统没有运行图形界面(GUI)! SSH与桌面进程二者是完全独立的

sudo chmod +x NVIDIA-Linux-x86_64-580.82.09.run
sudo bash NVIDIA-Linux-x86_64-580.82.09.run

按照提示完成安装,安装完成后重启系统:

sudo reboot

2.3 CUDA 安装

前提:已正确安装兼容版本的 NVIDIA 驱动

2.3.1 通过 APT 安装 CUDA Toolkit 13.0.1

访问CUDA Download页面,根据页面指示进行安装,此处注意:【不要执行以下命令】

# 不要安装 nvidia-open!
# sudo apt install -y nvidia-open❌

原因:你已通过 .run 文件安装了 NVIDIA 专有驱动。nvidia-open 是另一个独立的开源驱动包,与 .run 驱动不兼容,强行安装会导致驱动冲突、黑屏或无法启动图形界面。

以下以CUDA Toolkit 13.0.1安装为例

# 添加仓库优先级配置
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64/cuda-ubuntu2404.pin
sudo mv cuda-ubuntu2404.pin /etc/apt/preferences.d/cuda-repository-pin-600

# 下载并安装本地仓库包
wget https://developer.download.nvidia.com/compute/cuda/13.0.1/local_installers/cuda-repo-ubuntu2404-13-0-local_13.0.1-580.82.07-1_amd64.deb
sudo dpkg -i cuda-repo-ubuntu2404-13-0-local_13.0.1-580.82.07-1_amd64.deb

# 导入 GPG 密钥
sudo cp /var/cuda-repo-ubuntu2404-13-0-local/cuda-*-keyring.gpg /usr/share/keyrings/

# 更新并安装 CUDA Toolkit
sudo apt update
sudo apt install -y cuda-toolkit-13-0
2.3.2 安装完成后,建议将 CUDA 加入环境变量
echo 'export PATH=/usr/local/cuda-13.0/bin:$PATH' >> ~/.bashrc
echo 'export LD_LIBRARY_PATH=/usr/local/cuda-13.0/lib64:$LD_LIBRARY_PATH' >> ~/.bashrc
source ~/.bashrc

3. Python 环境

3.1 安装 uv

安装uv的方法多种多样,这里讲一个网上用得少但挺方便的方法:使用Snap进行安装

sudo snap install astral-uv --classic

3.2 新建虚拟环境

据说 python3.11编译性能最好,但是我选3.12 (看各自需求吧)

uv venv --python 3.12 vllm-env
source vllm-env/bin/activate

3.3 换清华 PyPI 镜像,下载速度 100 MB/s+

mkdir -p ~/.config/uv
cat > ~/.config/uv/config.toml <<'EOF'
index-url = "https://pypi.tuna.tsinghua.edu.cn/simple"
EOF

4. 模型下载

目标:用 ModelScope Hub 走国内网络,把 Qwen2-7B-Instruct 高速下载到 /data/models,供 vLLM 直接读取。

# 安装官方 CLI(比 huggingface-hub 快 5 倍)
uv pip install modelscope

# 设置缓存目录(避免放 home 爆根分区)
export MODELSCOPE_CACHE=/data/models
modelscope download \
  --model qwen/Qwen2-7B-Instruct \
  --local_dir /data/models/qwen2-7b-instruct \
  --revision v1.0.5

下载完结构如下:

/data/models/qwen2-7b-instruct
├── config.json
├── tokenizer.json
├── *.safetensors  # 8 个文件,共 14 GB
└── ...

以下是将你提供的安装方式修改为使用 pip install vllm --torch-backend=auto 的版本。该方式使用官方预编译 wheel(自动选择 Torch 后端),无需从源码编译,适合快速部署,但会失去 CUTLASS、AWQ、GPTQ 等高级优化(如你注释中所述)。


5. 安装 vLLM(使用官方 wheel)

使用 --torch-backend=auto 自动匹配 PyTorch 后端,安装更快,但默认关闭 CUTLASS fp8AWQGPTQ 等优化。如需极致性能,请参考源码编译方式。

# 安装 vLLM 官方 wheel(自动选择 Torch 后端)
pip install vllm --torch-backend=auto

验证安装:

python -c "import vllm; print(vllm.__version__)"

若命令行能正常输出0.10.2或其余版本号即可


6. 启动模型

注意:使用官方 wheel 时,部分高级功能(如 --quantization fp8)可能不可用,取决于 wheel 编译时是否启用。若需 FP8,请确认你的 GPU(如 H100)和 wheel 支持,或改回源码编译

创建启动脚本并运行vLLM

cat > start-vllm.sh <<'EOF'
#!/usr/bin/env bash
# 端口、并发、显存占用全可调
export CUDA_VISIBLE_DEVICES=0
exec vllm serve /data/models/qwen2-7b-instruct \
  --quantization awq_marlin \
  --max-model-len 14400 \
  --max-num-seqs 1 \
  --tensor-parallel-size 1 \
  --gpu-memory-utilization 0.95 \
  --enforce-eager \
  --enable-chunked-prefill \
  --port 8848 \
  --host 0.0.0.0
EOF

chmod +x start-vllm.sh
bash start-vllm.sh

其中有关vllm serve的具体参数文档见引擎参数-vLLM文档

若模型运行正常,应有如下反馈

(APIServer pid=111865) INFO 09-30 02:33:17 [api_server.py:1971] Starting vLLM API server 0 on http://0.0.0.0:8848
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:36] Available routes are:
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /openapi.json, Methods: GET, HEAD
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /docs, Methods: GET, HEAD
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /docs/oauth2-redirect, Methods: GET, HEAD
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /redoc, Methods: GET, HEAD
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /health, Methods: GET
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /load, Methods: GET
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /ping, Methods: POST
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /ping, Methods: GET
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /tokenize, Methods: POST
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /detokenize, Methods: POST
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /v1/models, Methods: GET
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /version, Methods: GET
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /v1/responses, Methods: POST
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /v1/responses/{response_id}, Methods: GET
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /v1/responses/{response_id}/cancel, Methods: POST
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /v1/chat/completions, Methods: POST
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /v1/completions, Methods: POST
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /v1/embeddings, Methods: POST
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /pooling, Methods: POST
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /classify, Methods: POST
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /score, Methods: POST
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /v1/score, Methods: POST
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /v1/audio/transcriptions, Methods: POST
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /v1/audio/translations, Methods: POST
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /rerank, Methods: POST
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /v1/rerank, Methods: POST
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /v2/rerank, Methods: POST
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /scale_elastic_ep, Methods: POST
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /is_scaling_elastic_ep, Methods: POST
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /invocations, Methods: POST
(APIServer pid=111865) INFO 09-30 02:33:17 [launcher.py:44] Route: /metrics, Methods: GET
(APIServer pid=111865) INFO:     Started server process [111865]
(APIServer pid=111865) INFO:     Waiting for application startup.
(APIServer pid=111865) INFO:     Application startup complete.

7. 常见坑汇总

现象 根本原因 解决方案
RuntimeError: CUDA error: invalid device function 编译时未在 TORCH_CUDA_ARCH_LIST 中包含当前 GPU 的计算能力(Compute Capability) 1. 运行 nvidia-smi 查看 GPU 型号
2. 查询对应 Compute Capability(如 A100 为 8.0,RTX 4090 为 8.9)
3. 重新编译时设置:TORCH_CUDA_ARCH_LIST="8.0;8.9"
启动时报错 libnvinfer.so not found 安装了 CUDA Toolkit,但未安装 TensorRT(尤其启用 --quantization fp8 时依赖) - 使用 uv pip install tensorrt 安装 TensorRT
- 或移除 --quantization fp8 参数以避免依赖
中文输出乱码 tokenizer.json 文件缺失或路径不正确 确保模型目录中包含 tokenizer.json;vLLM 启动时会自动加载该文件用于正确解码
显存暴涨导致 OOM(Out-Of-Memory) --gpu-memory-utilization 默认值 0.9 过高,预留显存不足 - 将参数调低至 0.75
--gpu-memory-utilization 0.75
- 同时启用交换空间:
--swap-space 4(单位:GB)
升级 NVIDIA 驱动后 vLLM 无法启动 内核态驱动(kernel module)与用户态驱动(user-space libraries)版本不一致 重装驱动以确保版本同步,例如:
sudo apt install --reinstall nvidia-driver-550-server
(请根据实际驱动版本调整包名)

💡 建议:在部署 vLLM 前,统一检查 CUDA、cuDNN、TensorRT 和 NVIDIA 驱动的版本兼容性,可显著减少运行时错误。


8. Systemd 托管 & 日志 & Docker & 编译安装vLLM等

网上教程一堆,不再重复造轮子了


9. 结语

至此,Ollama → vLLM 迁移全部完成。
项目完成至本文撰写已有一段时间,记忆难免存在疏漏,有误之处敬请指出

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐