vllm离线安装小记
vllm我和你没完!!!!
好的今天来写一点关于在完全断网的环境下安装 vLLM 的事情。在之前的十天里,博主在5080和H100上多次尝试运行vllm但是均失败🥹🥹🥹好在今天,终于成功了!
于是就有了这篇文章,记录一下怎么在联网机器上准备好所有依赖,然后打包搬到离线机去,狠狠安装🤤
离线拉包用的脚本在站点里可以直接点开下载(来自 docs/.vuepress/public/scripts/,构建后挂在站点根路径):vllm_offline_fetch.sh。
# 先搞明白:vLLM 离线安装需要准备啥?
很多人(包括之前的我)以为离线安装就是把 Python 的 wheel 包下载下来就完事了。但对于 vLLM 来说,远远不够!因为 vLLM 的编译过程会触发 CMake 的 FetchContent,它会尝试从 GitHub 克隆以下仓库:
- CUTLASS:NVIDIA 的高性能 CUDA 内核库
- flash-attention: FlashAttention 内核(你没看错,vLLM 要单独拉一份)
- QuTLASS:量化相关的 CUTLASS 扩展
- triton:Triton 内核
- FlashMLA:MLA 注意力机制实现
所以你需要准备两大类资源:
| 资源类型 | 内容 | 存放目录 |
|---|---|---|
| Python 依赖 | wheel/sdist 格式的包 | vllm_wheelhouse_pytorch210_cu128/ |
| CMake 源码 | Git 仓库源码 | vllm_offline_cmake_src/ |
| vLLM 本体 | 源码(建议保留 .git) | vllm/ |
下文假设这三个目录都放在同一个叫 ROOT 的目录下(或者其他的随你便略略略)
# 第一步:在联网机上准备依赖
完整流程见脚本:vllm_offline_fetch.sh。它会:
- 拉取 PyTorch 官方镜像(这里用的是
pytorch/pytorch:2.10.0-cuda12.8-cudnn9-devel) - 在镜像里用
pip download把 wheel/sdist 拉到本地目录(下面单独展开,和脚本一一对应) - (可选,默认开启)在宿主机用
git克隆 CMake 需要的源码到vllm_offline_cmake_src/ - 用只读 wheelhouse 连跑三轮
pip install --dry-run,确认离线环境下依赖闭包真的齐活
# 脚本默认路径(和 vllm_offline_fetch.sh 一致)
| 变量 | 默认含义 |
|---|---|
IMAGE | pytorch/pytorch:2.10.0-cuda12.8-cudnn9-devel(与离线安装目标镜像对齐) |
VLLM_SRC | 脚本所在目录旁的 vllm/(需含 pyproject.toml);可用 export VLLM_SRC=... 覆盖 |
OUT | vllm_wheelhouse_pytorch210_cu128/,所有 wheel 落盘目录 |
CMAKE_SRC_DIR | vllm_offline_cmake_src/ |
SETUPTOOLS_SCM_PRETEND_VERSION | 默认 0.0.0+wheelfetch:pip 解析本地 vLLM 时会起 PEP 517 隔离环境,镜像里往往没 git,不设的话 setuptools-scm 容易直接炸 |
OFFLINE_DRY_RUN_ONLY=1 | 不 docker pull、不克隆、不 pip download,只跑后面的离线校验(要求 OUT 已存在且非空) |
# wheel 是怎么下来的(对照脚本里的 docker run)
思路很朴素:用和未来离线安装同一套镜像当「下载机」,把依赖全部 pip download 到一个目录里,离线时只认这个目录。
docker pull "$IMAGE",保证本机有目标镜像。docker run --rm,把本机的 vLLM 源码挂到容器里的/src,把 wheel 输出目录挂到/out:-v "$VLLM_SRC:/src"-v "$OUT:/out"- 传入
-e PIP_BREAK_SYSTEM_PACKAGES=1(官方 PyTorch 镜像是 PEP 668「受管环境」,不打破装不进包) - 传入
-e SETUPTOOLS_SCM_PRETEND_VERSION=...,避免 pip 在隔离环境里解析/src时因缺git失败。
容器内先升级打包三件套:
python -m pip install -U pip setuptools wheel。为 PyTorch CUDA 12.8 轮子加额外索引:
export PIP_EXTRA_INDEX_URL="https://download.pytorch.org/whl/cu128"(脚本里与下面pip download的--extra-index-url一致)。第一轮
pip download(构建期 + 运行期依赖):python -m pip download -d /out \ --extra-index-url https://download.pytorch.org/whl/cu128 \ -r /src/requirements/build.txt \ -r /src/requirements/cuda.txt1
2
3
4其中
cuda.txt已经-r common.txt,所以 common 里的东西也会一起被解析进来。第二轮
pip download:在 vLLM 根目录再对当前源码树拉一层,把pyproject.toml/ 动态元数据里多出来的依赖也打进 wheelhouse:cd /src python -m pip download -d /out \ --extra-index-url https://download.pytorch.org/whl/cu128 \ .1
2
3
4最后脚本会数一下
/out里文件个数,心里有个底。
这里有个容易忽略的点:wheel 文件名里的 cp312 之类标签必须和离线安装时的 Python 小版本一致。脚本坚持用「同一镜像」拉包、离线也用「同一镜像」装,就是为了避免「联网机 Python 3.11、离线机 3.12」这种阴间错配。
# 拉完 wheel 之后的三轮「离线 dry-run」
脚本不会只下载就跑路,它还会再起三次容器,全程 PIP_NO_INDEX=1,wheelhouse 只读挂载到 /out,用 --find-links=/out 做解析:
pip install --dry-run:只解析requirements/build.txt+requirements/cuda.txt,看离线能不能把运行/构建依赖算干净。pip install --dry-run -e /src:对可编辑安装本身做依赖闭包校验(不真正编译)。- 先真装
build.txt,再pip install --dry-run --no-build-isolation -e /src:这一步更贴近你离线真机上的顺序(先有 grpc 等构建工具,再-e .)。
如果这三步里还有任意一步想去访问 PyPI,说明 wheelhouse 缺包或 PIP_FIND_LINKS 路径不对,别急着拷去内网,先在联网环境补齐。
# 核心配置说明
脚本里有几个版本号需要和你要安装的 vLLM 版本保持一致(我这里挑选的是vllm的v0.17.1版本)
CUTLASS_TAG="v4.2.1"
FLASH_ATTN_REV="140c00c0241bb60cc6e44e7c1be9998d4b20d8d2"
QUTLASS_REV="830d2c4537c7396e14a02a46fbddd18b5d107c65"
TRITON_KERNELS_TAG="v3.6.0"
FLASH_MLA_REV="692917b1cda61b93ac9ee2d846ec54e75afe87b1"
2
3
4
5
这些版本号来自 vLLM 源码里的
CMakeLists.txt和cmake/external_projects/*.cmake。升级 vLLM 后记得重新核对!
# 特别注意:子模块!
flash-attention 和 FlashMLA 都依赖 CUTLASS 的头文件,但它们不是直接引用外部的 CUTLASS,而是通过子模块放在 csrc/cutlass 目录下。所以克隆后必须初始化子模块:
git -C "$CMAKE_SRC_DIR/flash-attention" submodule update --init --depth 1 csrc/cutlass
git -C "$CMAKE_SRC_DIR/FlashMLA" submodule update --init --depth 1 csrc/cutlass
2
如果你忘了这一步,编译时会报找不到 cute/tensor.hpp 之类的错误,然后一脸懵逼(别问我怎么知道的哈哈他吗的)
# 第二步:打包搬到离线机
把这三个目录 rsync 到离线机上(随便你怎么打包都行,反正我喜欢rsync -avP嘻嘻,香香香):
rsync -avz vllm/ offline_machine:/path/to/bundle/vllm/
rsync -avz vllm_wheelhouse_pytorch210_cu128/ offline_machine:/path/to/bundle/vllm_wheelhouse_pytorch210_cu128/
rsync -avz vllm_offline_cmake_src/ offline_machine:/path/to/bundle/vllm_offline_cmake_src/
2
3
# 第三步:离线机上配置环境变量
这是最容易踩坑的地方!在离线机的容器里执行安装前,必须设置这些环境变量:
export ROOT=/path/to/your/bundle # 你存放那三个目录的地方
# 指向 CMake 依赖的本地源码
export VLLM_CUTLASS_SRC_DIR="$ROOT/vllm_offline_cmake_src/cutlass"
export VLLM_FLASH_ATTN_SRC_DIR="$ROOT/vllm_offline_cmake_src/flash-attention"
export QUTLASS_SRC_DIR="$ROOT/vllm_offline_cmake_src/qutlass"
export TRITON_KERNELS_SRC_DIR="$ROOT/vllm_offline_cmake_src/triton/python/triton_kernels/triton_kernels"
export FLASH_MLA_SRC_DIR="$ROOT/vllm_offline_cmake_src/FlashMLA"
# pip 离线安装配置
export PIP_NO_INDEX=1
export PIP_FIND_LINKS="$ROOT/vllm_wheelhouse_pytorch210_cu128"
export PIP_BREAK_SYSTEM_PACKAGES=1
# 指定 GPU 架构(H100 是 9.0,A100 是 8.0,3090/4090 是 8.9)
export TORCH_CUDA_ARCH_LIST=9.0
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
重点:
TRITON_KERNELS_SRC_DIR必须指向triton_kernels包目录(含__init__.py的那一层),不是 Triton 仓库根目录!FLASH_MLA_SRC_DIR指向仓库根目录即可(目录名区分大小写FlashMLA)。
# 坑点 1:setuptools-scm 版本检测
PyTorch 的 devel 镜像默认没有安装 git!而 vLLM 的 setup.py 用 setuptools-scm 来算版本号,它会执行 git 命令。没 git 就会报错:metadata-generation-failed 或 LookupError: setuptools-scm was unable to detect version。
二选一解决:
安装 git(推荐,能得到与仓库一致的版本号):
apt-get update && apt-get install -y git1伪装版本(不装 git 时必设):
export SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0+offline1
# 第四步:执行安装
在容器内、已 export 上述变量后:
cd "$ROOT/vllm"
# 1. 升级构建工具
python -m pip install -U pip setuptools wheel
# 2. 安装构建依赖(含 ninja、grpcio-tools 等)
python -m pip install --no-index --find-links="$PIP_FIND_LINKS" -r requirements/build.txt
# 3. 安装 vLLM(--no-build-isolation 确保使用已装的构建依赖)
python -m pip install --no-build-isolation --no-index --find-links="$PIP_FIND_LINKS" -e .
2
3
4
5
6
7
8
9
10
注意顺序!一定要先装
build.txt(含grpcio-tools)再-e .,否则可能跳过 proto 生成,削弱 gRPC 相关能力。
# 坑点合集
# 坑 1:CMake 缓存路径不一致
如果你曾经换过 vLLM 源码路径、工作目录或重复编译,可能出现这个错误:
CMakeCache.txt directory ... is different than ...
这是因为 .deps/cutlass-subbuild 里记着旧路径(比如 /workspace/.deps),但你现在却在 /workspace/vllm/.deps。
解决:删缓存重编
rm -rf "$ROOT/vllm/.deps"
rm -rf /workspace/.deps # 若存在历史遗留
2
.deps 只是 CMake/FetchContent 缓存,不会删除你在 vllm_offline_cmake_src 里的离线源码,放心删。
# 坑 2:pip 仍然尝试联网
如果看到 pip 还在尝试访问 pypi.org:
- 检查
PIP_NO_INDEX=1是否设置 - 检查
PIP_FIND_LINKS路径是否正确(能否ls到 wheel 文件) - 检查环境变量是否 export 到了当前 shell(用
env | grep PIP确认)
# 坑 3:编译时找不到 CUTLASS 头文件
错误信息类似 cute/tensor.hpp: No such file or directory。
原因:flash-attention 或 FlashMLA 的子模块 csrc/cutlass 为空。
解决:回到联网机重新运行脚本(它会初始化子模块),或手动执行:
git -C "$VLLM_FLASH_ATTN_SRC_DIR" submodule update --init --depth 1 csrc/cutlass
git -C "$FLASH_MLA_SRC_DIR" submodule update --init --depth 1 csrc/cutlass
2
# 坑 4:源码目录只读挂载
如果你用 Docker -v 挂载时加了 :ro(只读),安装会失败。因为 pip install -e . 会写入 vllm/_version.py,只读挂载会报错。
解决:去掉 :ro,或确保源码目录对当前用户可写。
# 验证安装
安装完成后验证一下:
python -c "import vllm; print(vllm.__version__)"
如果能正常输出版本号,恭喜你,离线安装成功了!
# 总结:离线安装核对清单
| 检查项 | 说明 |
|---|---|
| wheelhouse 非空 | 包含所有 Python 依赖的 wheel/sdist |
| cmake_src 子模块已初始化 | flash-attention 和 FlashMLA 的 csrc/cutlass 不能是空目录 |
| 环境变量已 export | 所有 *_SRC_DIR、PIP_NO_INDEX、PIP_FIND_LINKS |
| git 已安装或伪装版本 | 要么装 git,要么设 SETUPTOOLS_SCM_PRETEND_VERSION |
| 源码目录可写 | 不能是只读挂载 |
| GPU 架构正确 | TORCH_CUDA_ARCH_LIST 要匹配你的显卡 |
最后,愿天下再无离线安装的痛——虽然这是不可能的(悲)