跳到内容

vLLM 轮式夜间构建

vLLM 在 https://wheels.vllm.ai 维护一个每个提交的轮式文件仓库(通常称为“夜间构建”),该仓库提供自 v0.5.3 以来 main 分支上每个提交的预构建轮式文件。本文档解释了夜间构建轮式文件索引机制的工作原理。

CI 上的构建和上传流程

轮式构建

轮式文件在 PR 合并到 main 分支后,在 Release 管道(.buildkite/release-pipeline.yaml)中构建,并包含多个变体。

  • 后端变体cpucuXXX(例如 cu129cu130)。
  • 架构变体x86_64aarch64

每个构建步骤

  1. 在 Docker 容器中构建轮式文件。
  2. 重命名轮式文件名,使用正确的 manylinux 标签(当前为 manylinux_2_31)以符合 PEP 600。
  3. 将轮式文件上传到 S3 存储桶 vllm-wheels 下的 /{commit_hash}/ 目录。

索引生成

上传每个轮式文件后,.buildkite/scripts/upload-wheels.sh 脚本会

  1. 列出 S3 中提交目录下的所有现有轮式文件
  2. 使用 .buildkite/scripts/generate-nightly-index.py 生成索引
    • 解析轮式文件名以提取元数据(版本、变体、平台标签)。
    • 创建 HTML 索引文件(index.html),以兼容 PyPI。
    • 生成机器可读的 metadata.json 文件。
  3. 将索引上传到多个位置(覆盖现有索引)。
    • /{commit_hash}/ - 始终上传,用于特定提交的访问。
    • /nightly/ - 仅用于 main 分支上的提交(非 PR)。
    • /{version}/ - 仅用于发布轮式文件(版本号中不包含 dev)。

处理并发构建

索引生成脚本可以通过在生成索引前始终列出提交目录中的所有轮式文件来处理并发构建的多个变体,从而避免竞态条件。

目录结构

S3 存储桶结构遵循此模式:

s3://vllm-wheels/
├── {commit_hash}/              # Commit-specific wheels and indices
│   ├── vllm-*.whl              # All wheel files
│   ├── index.html              # Project list (default variant)
│   ├── vllm/
│   │   ├── index.html          # Package index (default variant)
│   │   └── metadata.json       # Metadata (default variant)
│   ├── cu129/                  # Variant subdirectory
│   │   ├── index.html          # Project list (cu129 variant)
│   │   └── vllm/
│   │       ├── index.html      # Package index (cu129 variant)
│   │       └── metadata.json   # Metadata (cu129 variant)
│   ├── cu130/                  # Variant subdirectory
│   ├── cpu/                    # Variant subdirectory
│   └── .../                    # More variant subdirectories
├── nightly/                    # Latest main branch wheels (mirror of latest commit)
└── {version}/                  # Release version indices (e.g., 0.11.2)

所有构建的轮式文件都存储在 /{commit_hash}/ 中,而不同的索引被生成并引用它们。这避免了轮式文件重复。

例如,您可以通过以下 URL 指定来使用不同的索引:

  • https://wheels.vllm.ai/nightly/cu130 用于构建的最新 main 分支 CUDA 13.0 轮式文件。
  • https://wheels.vllm.ai/{commit_hash} 用于特定提交构建的轮式文件(默认变体)。
  • https://wheels.vllm.ai/0.12.0/cpu 用于 0.12.0 发布版 CPU 变体的轮式文件。

请注意,并非所有变体都存在于每个提交中。可用变体可能会随时间变化,例如将 cu130 更改为 cu131。

变体组织

索引按变体组织:

  • 默认变体:没有变体后缀的轮式文件(即使用当前的 VLLM_MAIN_CUDA_VERSION 构建的)放置在根目录。
  • 变体子目录:带有变体后缀的轮式文件(例如 +cu130.cpu)组织在子目录中。
  • 默认别名:默认变体可以有一个别名(例如,当前为 cu129),以保持一致性和便利性。

变体从轮式文件名中提取(如文件名约定中所述)。

  • 变体编码在本地版本标识符中(例如 +cu129dev<N>+g<hash>.cu130)。
  • 示例
    • vllm-0.11.2.dev278+gdbc3d9991-cp38-abi3-manylinux1_x86_64.whl → 默认变体
    • vllm-0.10.2rc2+cu129-cp38-abi3-manylinux2014_aarch64.whlcu129 变体
    • vllm-0.11.1rc8.dev14+gaa384b3c0.cu130-cp38-abi3-manylinux1_x86_64.whlcu130 变体

索引生成详情

generate-nightly-index.py 脚本执行以下操作:

  1. 使用正则表达式解析轮式文件名以提取:
    • 包名
    • 版本(已提取变体)
    • Python 标签、ABI 标签、平台标签
    • 构建标签(如果存在)
  2. 按变体分组轮式文件,然后按包名分组。
    • 目前只构建 vllm,但该结构支持未来构建多个包。
  3. 生成 HTML 索引(符合简单仓库 API)。
    • 顶层 index.html:列出所有包和变体子目录。
    • 包级别 index.html:列出该包的所有轮式文件。
    • 使用相对路径到轮式文件,以提高可移植性。
  4. 生成 metadata.json:
    • 机器可读的 JSON,包含所有轮式文件元数据。
    • 包含 path 字段,其中包含 URL 编码的轮式文件相对路径。
    • setup.py 在纯 Python 构建期间定位兼容的预编译轮式文件时使用。

AWS 服务特殊处理

轮式文件和索引直接存储在 AWS S3 上,我们使用 AWS CloudFront 作为 S3 存储桶前面的 CDN。

由于 S3 不提供正确的目录列表功能,为了支持 PyPI 兼容的简单仓库 API 行为,我们部署了一个 CloudFront Function,它会:

  • 将任何不以 / 结尾且看起来不像文件的 URL(即最后一个路径段不包含点 .)重定向到具有尾部 / 的相同 URL。
  • /index.html 追加到任何以 / 结尾的 URL。

例如,以下请求将被处理为:

  • /nightly/nightly/index.html
  • /nightly/cu130//nightly/cu130/index.html
  • /nightly/index.html/nightly/vllm.whl → 不变

AWS S3 文件名转义

S3 会根据其命名规则在上传时自动转义文件名。对 vllm 的直接影响是文件名中的 + 将被转换为 %2B。我们在索引生成脚本中特别注意在生成 HTML 索引和 JSON 元数据时正确转义文件名,以确保 URL 正确且可直接使用。

setup.py 中使用预编译的轮式文件

当使用 VLLM_USE_PRECOMPILED=1 安装 vLLM 时,setup.py 脚本会:

  1. 通过 precompiled_wheel_utils.determine_wheel_url() **确定轮式文件位置**。
    • 环境变量 VLLM_PRECOMPILED_WHEEL_LOCATION(用户指定的 URL/路径)始终具有最高优先级,并跳过所有其他步骤。
    • 通过 VLLM_MAIN_CUDA_VERSION 确定变体(可以通过环境变量 VLLM_PRECOMPILED_WHEEL_VARIANT 覆盖);还将尝试使用默认变体作为后备。
    • 确定此分支的 *基本提交*(稍后解释)(可以通过环境变量 VLLM_PRECOMPILED_WHEEL_COMMIT 覆盖)。
  2. https://wheels.vllm.ai/{commit}/vllm/metadata.json(默认变体)或 https://wheels.vllm.ai/{commit}/{variant}/vllm/metadata.json(特定变体)**获取元数据**。
  3. **根据以下条件选择兼容的轮式文件**:
    • 包名(vllm
    • 平台标签(架构匹配)
  4. **下载并提取**预编译的二进制文件:
    • C++ 扩展模块(.so 文件)
    • Flash Attention Python 模块
    • Triton 内核 Python 文件
  5. **修补 package_data** 以包含安装中的提取文件。

什么是基本提交?

基本提交是通过查找当前分支与上游 main 分支之间的合并基础来确定的,以确保源代码与预编译二进制文件之间的兼容性。

注意:在使用预编译轮式文件之前,用户有责任确保没有本地代码(例如 C++ 或 CUDA)的更改。

实现文件

夜间构建轮式文件机制中涉及的关键文件:

  • .buildkite/release-pipeline.yaml:构建轮式文件的 CI 管道。
  • .buildkite/scripts/upload-wheels.sh:上传轮式文件并生成索引的脚本。
  • .buildkite/scripts/generate-nightly-index.py:生成 PyPI 兼容索引的 Python 脚本。
  • setup.py:包含用于获取和使用预编译轮式文件的 precompiled_wheel_utils 类。