玛卡巴卡的blog 玛卡巴卡的blog
首页
提问箱
自传
植物分类
关于

玛卡巴卡

短暂的休息,是为了更好的再出发 有我爱和爱我的人,便什么都不会怕——
首页
提问箱
自传
植物分类
关于
  • 技术分享
玛卡巴卡
2026-03-27
目录

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。它会:

  1. 拉取 PyTorch 官方镜像(这里用的是 pytorch/pytorch:2.10.0-cuda12.8-cudnn9-devel)
  2. 在镜像里用 pip download 把 wheel/sdist 拉到本地目录(下面单独展开,和脚本一一对应)
  3. (可选,默认开启)在宿主机用 git 克隆 CMake 需要的源码到 vllm_offline_cmake_src/
  4. 用只读 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 到一个目录里,离线时只认这个目录。

  1. docker pull "$IMAGE",保证本机有目标镜像。

  2. 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 失败。
  3. 容器内先升级打包三件套:python -m pip install -U pip setuptools wheel。

  4. 为 PyTorch CUDA 12.8 轮子加额外索引:export PIP_EXTRA_INDEX_URL="https://download.pytorch.org/whl/cu128"(脚本里与下面 pip download 的 --extra-index-url 一致)。

  5. 第一轮 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.txt
    
    1
    2
    3
    4

    其中 cuda.txt 已经 -r common.txt,所以 common 里的东西也会一起被解析进来。

  6. 第二轮 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
  7. 最后脚本会数一下 /out 里文件个数,心里有个底。

这里有个容易忽略的点:wheel 文件名里的 cp312 之类标签必须和离线安装时的 Python 小版本一致。脚本坚持用「同一镜像」拉包、离线也用「同一镜像」装,就是为了避免「联网机 Python 3.11、离线机 3.12」这种阴间错配。

# 拉完 wheel 之后的三轮「离线 dry-run」

脚本不会只下载就跑路,它还会再起三次容器,全程 PIP_NO_INDEX=1,wheelhouse 只读挂载到 /out,用 --find-links=/out 做解析:

  1. pip install --dry-run:只解析 requirements/build.txt + requirements/cuda.txt,看离线能不能把运行/构建依赖算干净。
  2. pip install --dry-run -e /src:对可编辑安装本身做依赖闭包校验(不真正编译)。
  3. 先真装 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"
1
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
1
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/
1
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
1
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。

二选一解决:

  1. 安装 git(推荐,能得到与仓库一致的版本号):

    apt-get update && apt-get install -y git
    
    1
  2. 伪装版本(不装 git 时必设):

    export SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0+offline
    
    1

# 第四步:执行安装

在容器内、已 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 .
1
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 ...
1

这是因为 .deps/cutlass-subbuild 里记着旧路径(比如 /workspace/.deps),但你现在却在 /workspace/vllm/.deps。

解决:删缓存重编

rm -rf "$ROOT/vllm/.deps"
rm -rf /workspace/.deps  # 若存在历史遗留
1
2

.deps 只是 CMake/FetchContent 缓存,不会删除你在 vllm_offline_cmake_src 里的离线源码,放心删。

# 坑 2:pip 仍然尝试联网

如果看到 pip 还在尝试访问 pypi.org:

  1. 检查 PIP_NO_INDEX=1 是否设置
  2. 检查 PIP_FIND_LINKS 路径是否正确(能否 ls 到 wheel 文件)
  3. 检查环境变量是否 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
1
2

# 坑 4:源码目录只读挂载

如果你用 Docker -v 挂载时加了 :ro(只读),安装会失败。因为 pip install -e . 会写入 vllm/_version.py,只读挂载会报错。

解决:去掉 :ro,或确保源码目录对当前用户可写。

# 验证安装

安装完成后验证一下:

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

如果能正常输出版本号,恭喜你,离线安装成功了!

# 总结:离线安装核对清单

检查项 说明
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 要匹配你的显卡

最后,愿天下再无离线安装的痛——虽然这是不可能的(悲)

上次更新: 2026/04/30, 17:04:36
最近更新
01
快乐小狗狂喜!(小声版)
05-01
02
乌黑的眼睛
04-30
03
人总在接近幸福时倍感幸福
04-29
更多文章>
Theme by Vdoing | Copyright © 2026-2026 玛卡巴卡 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式