Prhub

#40415 [CI] Automate Docker Hub release image publishing

原始 PR 作者 khluu 合并时间 2026-05-06 08:15 文件变更 4 提交数 6 评论 14 代码增减 +221 / -95

执行摘要

自动化 Docker Hub 发布镜像流程

以前发布 Docker 镜像需要人工从 Buildkite 注解中复制命令执行,容易出错且遗漏了 Ubuntu 24.04 镜像。docker manifest rm 在首次发布时因缺少 || true 导致失败。本 PR 旨在完全自动化发布流程,减少人工操作失误,并统一镜像发布方式。

建议 DevOps 和 CI 工程师精读此 PR,尤其是 review 中关于 shell 脚本错误处理、竞争条件和依赖管理的讨论。这些模式在自动化发布流程中非常典型,值得借鉴。发布负责人应关注 PyPI 上传问题是否被后续修复。

讨论亮点
  • CPU 拉取错误处理claude[bot] 指出原 if docker pull ... 2>/dev/null; then 会掩盖所有错误(标签不匹配、认证过期等),建议改用 docker manifest inspect。作者采纳,重写了 CPU 镜像检测逻辑。
  • 版本号 v 前缀不一致:CPU 构建使用原始版本号打标签,而发布脚本会 strip v 再重新添加,导致不匹配。作者移除了多余的 v strip,现在统一使用带 v 的版本号。
  • 发布与 CPU 构建的竞争条件:发布步骤一开始没有依赖 CPU 构建,若操作员同时放行,发布可能拉到未完成的 CPU 镜像。作者在 block 依赖中添加了 build-cpu-release-image-x86/arm64 并设置 allow_failure: true,确保等待构建完成。
  • set -euo pipefail 元数据获取失效buildkite-agent meta-data get 失败导致脚本无错误消息退出。作者通过添加 --default "" 参数解决。
    • PyPI 上传脚本依赖问题(未解决):claude[bot] 指出安装 requirements/build/cuda.txt 会在无 CUDA 的环境中触发 CUDA 路径检测失败,建议安装最小依赖集或使用 --no-deps 等方式。该问题在 PR 合并时尚未修复。

实现拆解

  1. 创建自动化发布脚本.buildkite/scripts/publish-release-images.sh):180 行的 Bash 脚本,负责从 ECR 拉取已构建好的各架构镜像,用 latestv$VERSION 标签重新标记,推送到 Docker Hub,然后创建多架构 manifest 并推送。脚本支持 CUDA 13.0(默认)、CUDA 12.9、Ubuntu 24.04(两种 CUDA 版本)、ROCm 和 CPU 变体。CPU 镜像处理使用 docker manifest inspect 检查是否存在,若不存在则跳过并警告,避免静默失败。

  2. 调整 Buildkite Pipeline 配置.buildkite/release-pipeline.yaml):在 Publish release images 分组之前新增一个 block 步骤 block-publish-release-images,要求操作员手动确认后才能进行发布。该 block 依赖于所有多架构 manifest 创建步骤、ROCm 构建和发布版本输入,同时通过 allow_failure: true 依赖两个 CPU 构建步骤,等待它们完成但不阻塞整个 pipeline。实际发布步骤 publish-release-images-dockerhub 在 block 解封后执行,调用上述脚本。此外还为两个 CPU 构建步骤添加了 key: 标识,便于依赖引用。

  3. 简化注解脚本.buildkite/scripts/annotate-release.sh):删除了原先打印 Docker pull/tag/push/manifest 命令的 93 行内容,仅保留 wheel 下载说明和一条提示(说明镜像发布已自动化)。原脚本中 ROCM_BASE_CACHE_KEY 等不再需要,一并移除。

  4. 修复 PyPI 上传脚本依赖.buildkite/scripts/upload-release-wheels-pypi.sh):在创建 sdist 前安装 requirements/build/cuda.txt,确保 setup.py 的运行依赖(如 torch)可用。但这一改动在 review 中被指出可能引入 CUDA 工具链依赖冲突,尚未完全解决。

文件 模块 状态 重要度
.buildkite/scripts/publish-release-images.sh 发布脚本 added 5.58
.buildkite/release-pipeline.yaml Pipeline 配置 modified 4.9
.buildkite/scripts/annotate-release.sh 注解脚本 modified 4.52
.buildkite/scripts/upload-release-wheels-pypi.sh 上传脚本 modified 2.4

关键源码片段

.buildkite/scripts/publish-release-images.sh core-logic

新增的自动化发布脚本核心,实现了从 ECR 拉取、打标签、推送、创建 manifest 的完整流程,支持所有镜像变体。

#!/bin/bash
# SPDX-License-Identifier: Apache-2.0set -euo pipefail
​
# 获取发布版本号,并去掉可能的 v 前缀
RELEASE_VERSION=$(buildkite-agent meta-data get release-version --default "" | sed 's/^v//')
if [ -z "${RELEASE_VERSION}" ]; then
    echo "ERROR: release-version metadata not set"
    exit 1
fiCOMMIT="${BUILDKITE_COMMIT}"# 登录 ECR
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/q9t5s3a7
​
# ---- CUDA 13.0 (default) ----
docker pull "public.ecr.aws/q9t5s3a7/vllm-release-repo:${COMMIT}-x86_64"
docker pull "public.ecr.aws/q9t5s3a7/vllm-release-repo:${COMMIT}-aarch64"# 标记并推送 x86_64 镜像
docker tag "public.ecr.aws/q9t5s3a7/vllm-release-repo:${COMMIT}-x86_64" "vllm/vllm-openai:latest-x86_64"
docker tag "public.ecr.aws/q9t5s3a7/vllm-release-repo:${COMMIT}-x86_64" "vllm/vllm-openai:v${RELEASE_VERSION}-x86_64"
docker push "vllm/vllm-openai:latest-x86_64"
docker push "vllm/vllm-openai:v${RELEASE_VERSION}-x86_64"# 标记并推送 aarch64 镜像
docker tag "public.ecr.aws/q9t5s3a7/vllm-release-repo:${COMMIT}-aarch64" "vllm/vllm-openai:latest-aarch64"
docker tag "public.ecr.aws/q9t5s3a7/vllm-release-repo:${COMMIT}-aarch64" "vllm/vllm-openai:v${RELEASE_VERSION}-aarch64"
docker push "vllm/vllm-openai:latest-aarch64"
docker push "vllm/vllm-openai:v${RELEASE_VERSION}-aarch64"# 先清理旧 manifest(第一次失败时忽略)
docker manifest rm "vllm/vllm-openai:latest" || true
docker manifest rm "vllm/vllm-openai:v${RELEASE_VERSION}" || true# 创建并推送多架构 manifest
docker manifest create "vllm/vllm-openai:latest" "vllm/vllm-openai:latest-x86_64" "vllm/vllm-openai:latest-aarch64"
docker manifest create "vllm/vllm-openai:v${RELEASE_VERSION}" "vllm/vllm-openai:v${RELEASE_VERSION}-x86_64" "vllm/vllm-openai:v${RELEASE_VERSION}-aarch64"
docker manifest push "vllm/vllm-openai:latest"
docker manifest push "vllm/vllm-openai:v${RELEASE_VERSION}"

评论区精华

CPU 镜像拉取的错误处理 正确性

claude[bot] 指出原 `if docker pull ... 2>/dev/null; then` 会掩盖所有错误(包括标签不匹配、认证过期等),并导致误导性 WARNING。建议使用 `docker manifest inspect` 来判断镜像是否存在。

结论:作者已修改脚本,使用 `docker manifest inspect` 替代静默 pull,并明确区分镜像缺失与真实错误。 · 已解决

版本号 v 前缀不一致 正确性

claude[bot] 指出 CPU 构建步骤使用原始版本号(如 `1.2.3`),而 publish 脚本会 strip `v` 再重新加 `v`,导致若输入 `1.2.3` 则构建推送 `:1.2.3`,但 publish 寻找 `:v1.2.3` 失败。

结论:作者已删除多余的 v strip,保持版本号一致性。 · 已解决

发布与 CPU 构建的竞争条件 设计

claude[bot] 指出 publish 步骤未依赖 CPU build 步骤,若操作员同时解除 CPU 构建阻塞和发布阻塞,发布可能拉到还未推送完成的旧镜像。建议添加依赖。

结论:作者添加了对 `build-cpu-release-image-x86/arm64` 的依赖(带 `allow_failure`),确保等待构建完成。 · 已解决

set -euo pipefail 导致 metadata 获取失败无诊断 正确性

claude[bot] 指出 `set -euo pipefail` 下 `buildkite-agent meta-data get` 失败会直接终止脚本,且标准错误被重定向到 /dev/null,导致无错误信息。

结论:作者使用了 `--default ""` 参数,避免 get 失败时退出。 · 已解决

PyPI 上传脚本依赖问题 other

claude[bot] 指出安装 `requirements/build/cuda.txt` 会在无 CUDA 的环境中触发 CUDA 路径检测失败,导致 sdist 无法生成,建议安装最小依赖集或使用 `--no-deps` 等方式。

结论:PR 合并前未修复,作者未回应,该问题仍存在。 · unresolved

风险与影响

  • 版本号格式依赖:虽然修复了 v 前缀问题,但仍依赖于操作员在输入版本时的一致性。若输入不带 v 的版本,CPU 构建和发布脚本仍可能因标签不匹配失败(但当前脚本已统一处理)。
  • CPU 镜像发布失败时静默跳过:当 CPU 镜像不存在时,publish 脚本会跳过并发出 WARNING,但不会导致 pipeline 失败。操作员可能忽略此警告,导致版本发布缺失 CPU 镜像。
  • PyPI 上传依赖问题upload-release-wheels-pypi.sh 中安装 cuda.txt 可能导致 sdist 构建失败,从而影响 PyPI 发布流程。该问题在 PR 中未修复,需后续关注。
  • 夜间构建过滤隐式依赖:publish 步骤过滤夜间构建依赖于 Buildkite 的 transitive filter 语义,若 block 步骤被过滤掉则后续步骤自动消失,但显式添加 if 条件会更安全。当前未显式添加,存在未来因 pipeline 结构变化而意外被包含的风险。
  • 对发布流程:从手动复制命令变为自动化执行,大幅降低人为失误的概率。操作员只需在 block 步骤确认即可,流程缩短且更可靠。
  • 对团队效率:发布工程师无需在 Buildkite 和终端之间切换,减少了约 5 分钟的机械操作时间。
  • 对系统影响:无运行时影响,仅影响 CI/CD 流水线。
  • 对镜像完整性:增加了 Ubuntu 24.04 镜像的发布支持,填补了之前的缺失。
CPU 镜像跳过风险 版本格式依赖 PyPI 依赖问题 夜间构建过滤隐式依赖

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论