关于 buildkite-pipelines
buildkite-pipelines 是编写、优化和排查 Buildkite 流水线 YAML 的技能,涵盖常见流水线结构及进阶执行方式,适用于维护 CI/CD 工作流的团队。
主要功能
- 01流水线步骤类型与依赖关系
- 02缓存、并行执行与矩阵构建
- 03注释、重试与制品
- 04动态生成流水线
- 05故障排查与常见错误
适用场景
- 01定义测试与部署步骤
- 02减少重复安装依赖
- 03并行运行测试任务
- 04根据仓库状态生成步骤
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ buildkite/ skills --skill buildkite-pipelines安装后在 Claude Code 中输入/buildkite-pipelines确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlexamples/basic-pipeline.ymloptimized-pipeline.ymlreferences/advanced-patterns.mddynamic-pipeline-patterns.mddynamic-pipeline-troubleshooting.mdgroup-steps.mdretry-and-error-codes.mdstep-types-reference.md详细介绍
Buildkite 流水线
流水线 YAML 是 Buildkite CI/CD 的核心。本技能介绍如何编写、优化和排查 .buildkite/pipeline.yml——步骤类型、缓存、并行、注释、重试、动态流水线、矩阵构建、插件、通知、制品和并发。
快速开始
在仓库根目录创建 .buildkite/pipeline.yml:
steps:
- label: ":hammer: Tests"
command: "npm test"
artifact_paths: "coverage/**/*"
- wait
- label: ":rocket: Deploy"
command: "scripts/deploy.sh"
branches: "main"
在 Buildkite 中将流水线的初始命令设置为上传此文件:
steps:
- label: ":pipeline: Upload"
command: buildkite-agent pipeline upload
Agent 会读取 .buildkite/pipeline.yml,并将步骤上传到 Buildkite 执行。
Buildkite 默认会查找 .buildkite/pipeline.yml。使用 buildkite-agent pipeline upload path/to/other.yml 可指定其他路径。
如需通过编程方式创建流水线,请参阅 buildkite-api 技能。 如需设置 Agent 和队列,请参阅队列文档。
步骤类型
| 类型 | 用途 | 最简语法 |
|---|---|---|
| command | 运行 shell 命令 | - command: "make test" |
| wait | 等待所有先前步骤通过 | - wait |
| block | 暂停以等待人工批准 | - block: ":shipit: Release" |
| trigger | 在另一个流水线上启动构建 | - trigger: "deploy-pipeline" |
| group | 将步骤归为一组(可折叠) | - group: "Tests",并嵌套 steps: |
| input | 继续前收集用户输入 | - input: "Release version",并附带 fields: |
有关每种步骤类型的详细属性和高级示例,请参阅 references/step-types-reference.md。
缓存
缓存依赖项是效果最显著的优化。使用基于清单失效的缓存插件:
steps:
- label: ":nodejs: Test"
command: "npm ci && npm test"
plugins:
- cache#v1.8.1:
paths:
- "node_modules/"
manifest: "package-lock.json"
缓存键根据清单文件的哈希值生成。当 package-lock.json 发生变化时,缓存会重新构建。
托管 Agent 还支持内置的 cache 键(无需插件):
steps:
- label: ":nodejs: Test"
command: "npm ci && npm test"
cache:
paths:
- "node_modules/"
key: "v1-deps-{{ checksum 'package-lock.json' }}"
如需了解托管 Agent 的设置和实例规格,请参阅 Buildkite 托管 Agent 文档。
快速失败和非阻塞步骤
在任何作业失败时立即取消其余作业:
steps:
- label: ":rspec: Tests"
command: "bundle exec rspec"
cancel_on_build_failing: true
对于不应阻塞构建的步骤(安全扫描、代码检查、覆盖率),请使用 soft_fail:
steps:
- label: ":shield: Security Scan"
command: "scripts/security-scan.sh"
soft_fail:
- exit_status: 1
软失败的步骤会在 UI 中显示为警告,但不会导致构建失败。在 wait 步骤上搭配 continue_on_failure: true,即可让下游步骤无论如何都继续运行。
并行和依赖关系
并行执行
默认情况下,同一级别的步骤会并行运行。使用 parallelism 将单个步骤拆分执行:
steps:
- label: ":rspec: Tests %n"
command: "bundle exec rspec"
parallelism: 10
这会创建 10 个并行作业。每个作业都会收到 BUILDKITE_PARALLEL_JOB(0-9)和 BUILDKITE_PARALLEL_JOB_COUNT(10)环境变量,以便拆分工作。
如需根据计时数据智能拆分测试,请参阅 buildkite-test-engine 技能。
显式依赖关系
使用 depends_on 声明步骤级依赖关系,无需使用 wait:
steps:
- label: "Build"
key: "build"
command: "make build"
- label: "Unit Tests"
depends_on: "build"
command: "make test-unit"
- label: "Integration Tests"
depends_on: "build"
command: "make test-integration"
构建完成后,单元测试和集成测试会并行运行,无需 wait 步骤。
注释
使用 buildkite-agent annotate 在构建页面上直接显示构建结果。支持 Markdown 和 HTML。
steps:
- label: ":test_tube: Tests"
command: |
if ! make test 2>&1 | tee test-output.txt; then
buildkite-agent annotate --style "error" --context "test-failures" < test-output.txt
exit 1
fi
buildkite-agent annotate "All tests passed :white_check_mark:" --style "success" --context "test-results"
| 标志 | 默认值 | 说明 |
|---|---|---|
--style | default | 视觉样式:default、info、warning、error、success |
--context | random | 唯一 ID——重复使用同一 context 会替换注释 |
--append | false | 将内容追加到具有相同 context 的现有注释 |
在注释中链接已上传的制品:
- command: |
buildkite-agent artifact upload "coverage/*"
buildkite-agent annotate --style "info" 'Coverage: <a href="artifact://coverage/index.html">view report</a>'
重试
自动重试
根据退出状态重试暂时性失败:
steps:
- label: ":hammer: Build"
command: "make build"
retry:
automatic:
- exit_status: -1 # Agent lost
limit: 2
- exit_status: 143 # SIGTERM (spot instance termination)
limit: 2
- exit_status: 255 # Timeout or SSH failure
limit: 2
- exit_status: "*" # Any non-zero exit
limit: 1
手动重试
控制是否允许手动重试:
retry:
manual:
allowed: false
reason: "Deployment steps cannot be retried"
如需完整的退出代码表和重试策略建议,请参阅 references/retry-and-error-codes.md。
动态流水线
根据仓库状态在运行时生成流水线步骤。使用 buildkite-agent pipeline upload 上传生成的 YAML:
steps:
- label: ":pipeline: Generate"
command: |
.buildkite/generate-pipeline.sh | buildkite-agent pipeline upload
何时使用哪种方式
流水线方案各不相同。选择能满足需求的最简单选项:
| 情况 | 方案 |
|---|---|
| 每次构建的步骤相同,最多只需按分支筛选 | 静态 YAML |
| 在组织范围内强制执行流水线结构,由管理员控制(Enterprise 计划) | 流水线模板 |
| 在多个流水线间共享可复用且经过审核的逻辑(缓存、Docker、制品传输) | 固定版本的插件 |
| 特定文件未更改时跳过步骤 | if_changed |
| 每个服务拥有独立流水线的单体仓库 | monorepo-diff 插件 |
通过 OR 逻辑组合 if 和 if_changed | 动态生成 |
| 在多个流水线间统一应用重试 / 超时 / 环境配置 | 动态生成(共享配置) |
在运行时计算测试分片、矩阵组合、parallelism × matrix | 动态生成(通常使用 SDK) |
| 服务间存在传递依赖的单体仓库 | 动态生成(自定义依赖图) |
| 从基础设施故障中恢复(OOM → 更大的 Agent) | 动态生成(pre-exit 钩子) |
| 步骤依赖前序步骤的输出(多阶段) | 动态生成,通常使用 --replace 或链式上传 |
| 无论前序步骤是否失败都必须运行的清理 / 拆除步骤 | 动态生成(pre-exit 上传收尾步骤) |
| 仅在主步骤失败时运行的回退步骤 | 动态生成(pre-exit 检查退出状态) |
| 流水线 YAML 已超出团队的维护能力 | 动态生成(使用 Python / TS / Go / Ruby SDK) |
不要为不合适的任务使用动态流水线
当步骤本身需要改变时,动态生成才是合适的工具。要在步骤间传递数据,有更简单的基本工具:
buildkite-agent meta-data set/get— 任何后续步骤都能在同一构建中读取的小型键值对(版本字符串、提交 SHA、功能标志)。- 制品 — 在步骤间传递的文件(
buildkite-agent artifact upload/download)。 - 触发步骤
env:— 传递给其他流水线中构建的环境变量。
如果只需要传递数据,使用元数据或制品更简单、更安全。请参阅 buildkite-agent-runtime 技能。
引导脚本
生成器脚本始终以 set -euo pipefail 开头。 如果没有 pipefail,pipeline upload 失败时会返回管道中最后一个命令的退出代码,构建步骤会报告成功,而且不会出现任何生成的步骤——这是动态流水线最常见的故障模式。
下面是一个仅对已更改服务运行测试的生成器示例:
#!/bin/bash
set -euo pipefail
CHANGED=$(git diff --name-only HEAD~1)
cat <<YAML
steps:
YAML
for dir in services/*/; do
svc=$(basename "$dir")
if echo "$CHANGED" | grep -q "^services/$svc/"; then
cat <<YAML
- label: ":test_tube: $svc"
command: "cd services/$svc && make test"
key: "test-$svc"
YAML
fi
done
为每个生成的步骤设置 key:。它可启用 depends_on,使重试具备幂等性(如果上传步骤重新运行,DuplicateKeyError 会阻止静默重复),并为不同构建提供稳定的标识符。推送前,请使用 buildkite-agent pipeline upload --dry-run 在本地验证。
每次上传不超过 500 个步骤,每次构建不超过 4,000 个作业(平台默认值,可通过支持渠道申请提高)。对于规模更大的单体仓库,请使用触发步骤将任务分散到多个独立构建中。
对于需要类型检查且可进行单元测试的生成器,Buildkite SDK 支持 JavaScript/TypeScript、Python、Go 和 Ruby。生成器产生约 10 个以上的步骤后,请将相关步骤封装在分组步骤中——添加任意分组都会为构建启用 DAG 模式,而且分组不接受 concurrency 属性(请参阅 references/group-steps.md)。
生成器步骤还可以读取运行时状态(元数据、制品、git diff)并上传流水线的下一阶段——这是多阶段构建使用的处理器模式。关于此模式、扇出 / 扇入,以及通过 pre-exit 钩子实现的收尾 / 始终运行步骤,请参阅 references/dynamic-pipeline-patterns.md。关于故障模式,请参阅 references/dynamic-pipeline-troubleshooting.md。关于高级生成器模式(Python、单体仓库、多阶段),请参阅 references/advanced-patterns.md。
条件执行
步骤级条件
使用 if 根据构建状态有条件地运行步骤:
steps:
- label: ":rocket: Deploy"
command: "scripts/deploy.sh"
if: build.branch == "main" && build.message !~ /\[skip deploy\]/
如需查看完整的条件表达式列表,请参阅条件表达式。
[skip ci] 注意事项: Buildkite 只会检查 HEAD 提交消息中的 [skip ci] / [ci skip]。如果这个标记位于一次多提交推送中的较早提交里,构建仍会触发。
基于目录的步骤筛选(if_changed)
如果相关文件没有更改,则跳过步骤。仅在上传流水线时由 Buildkite agent 应用。请参阅 https://buildkite.com/docs/pipelines/configure/dynamic-pipelines/if-changed.md。
steps:
- label: ":nodejs: Frontend tests"
command: "npm test"
if_changed:
- "src/frontend/**"
- "package.json"
有关排除模式和单体仓库配置,请参阅 references/advanced-patterns.md。
对于大型单体仓库,可使用 Sparse Checkout 插件,仅为上传步骤检出 .buildkite/,从而大幅加快流水线上传速度。
有条件地运行插件
步骤级 if 不会阻止插件执行。将步骤包装在 group 中即可完全跳过插件:
steps:
- group: ":docker: Build"
if: build.env("DOCKER_PASSWORD") != null
steps:
- label: "Build image"
command: "docker build -t myapp ."
plugins:
- docker-login#v2.1.0:
username: myuser
password-env: DOCKER_PASSWORD
矩阵构建
在多个配置下运行相同的步骤:
steps:
- label: "Test {{matrix.ruby}} on {{matrix.os}}"
command: "bundle exec rake test"
matrix:
setup:
ruby:
- "3.2"
- "3.3"
os:
- "ubuntu"
- "alpine"
adjustments:
- with:
ruby: "3.2"
os: "alpine"
skip: true # Known incompatible
每个 adjustments 条目中有效的属性:with、skip、soft_fail、env。agents: 键在 adjustments 中无效——Buildkite 会拒绝该流水线,并提示“agents is not a valid property on the matrix.adjustments configuration”。若要将矩阵组合路由到不同队列(例如,Linux 与 Windows agent),请使用单独的步骤或动态流水线生成器。
插件
通过 3 行 YAML 块添加功能。固定版本以确保可复现:
plugins:
- docker-compose#v5.5.0:
run: app
config: docker-compose.ci.yml
| 插件 | 用途 |
|---|---|
cache#v1.8.1 | 基于清单失效机制的依赖缓存 |
docker#v5.12.0 | 在 Docker 容器内运行步骤 |
docker-compose#v5.5.0 | 使用 Docker Compose 构建和运行 |
artifacts#v1.9.4 | 在步骤之间下载制品 |
test-collector#v2.0.0 | 将测试结果上传到 Test Engine |
始终固定插件版本(例如,使用 docker#v5.12.0,而不是 docker#v5)。如果插件发布了新的主版本,未固定版本可能会导致构建失败。
对于组织内部的私有插件,请使用完整的 Git URL——简写语法仅适用于公开插件:
plugins:
- ssh://[email protected]/my-org/my-plugin.git#v1.0.0:
config: value
通知和制品
在 steps: 上方添加流水线级别的 notify:,即可在构建状态发生变化时发送 Slack、电子邮件或 Webhook 通知。语法请参阅通知。
制品上传和下载
从步骤上传制品,并在后续步骤中下载:
steps:
- label: "Build"
command: "make build"
artifact_paths: "dist/**/*"
- wait
- label: "Package"
command: |
buildkite-agent artifact download "dist/*" .
make package
在 Docker 构建中使用制品时,请在开始 Docker 构建前下载制品,因为容器内无法使用 buildkite-agent:
steps:
- label: "Docker build"
command: |
buildkite-agent artifact download "dist/*" .
docker build -t myapp .
并发
限制共享资源的步骤并行执行数量。务必将 concurrency 与 concurrency_group 配对使用——如果没有组名,限制会被静默忽略。
steps:
- label: ":rocket: Deploy"
command: "scripts/deploy.sh"
concurrency: 1
concurrency_group: "deploy/production"
concurrency_method: "eager"
对于部署等彼此独立的作业,使用 concurrency_method: "eager"(下一个可用项)。如果执行顺序很重要,则使用默认值 "ordered"(FIFO)。设置 priority(默认为 0,数值越高优先级越高)以控制接下来运行哪些排队作业。
如需查看完整的并发配置选项,请参阅控制并发。
如需了解如何从终端触发、监控和调试流水线,请参阅 buildkite-cli 技能。
常见错误
| 错误 | 结果 | 修复方法 |
|---|---|---|
依赖步骤之间缺少 wait | 步骤会并行运行,第二个步骤会因第一个步骤尚未完成而失败 | 添加 - wait,或使用 depends_on: |
所有依赖关系都只使用 wait 步骤 | 虽然有效,但不符合惯例;wait 会阻塞所有先前的步骤,导致无法并行运行互不依赖的步骤 | 为命名步骤设置 key:,并使用 depends_on: "key" 表达细粒度依赖;仅在需要无条件屏障时使用 wait |
包安装步骤所在的流水线没有 plugins: | 每次构建都会从头重新安装依赖,拖慢构建并增加成本 | 添加 cache 插件(或为托管 Agent 使用内置的 cache: 键),缓存 node_modules/、.gradle/ 等目录。请参阅上文的缓存部分 |
使用步骤级别的 if 跳过插件 | 插件仍会执行(它们会在评估 if 之前运行) | 将步骤放入带有 if 条件的 group 中 |
| 未固定插件版本 | 插件发布了含有破坏性更改的版本时,构建会失败 | 始终使用完整的 semver:plugin#v1.2.3 |
在使用 concurrency 时忘记设置 concurrency_group | 未指定组名时,concurrency 会被忽略 | 始终将 concurrency 与 concurrency_group 配合使用 |
artifact_paths glob 与输出不匹配 | 工件不会上传,且不会显示任何提示,下游步骤会失败 | 在本地测试 glob 模式;嵌套目录使用 **/* |
| 将并行作业拆分逻辑硬编码 | 测试分配不均,一个缓慢的作业会阻塞构建 | 使用 parallelism: N,通过 Test Engine 按耗时拆分 |
| 在流水线 YAML 中内联机密 | 机密会显示在构建日志和 Buildkite UI 中 | 使用集群机密或 Agent 环境钩子 |
将 retry.automatic 与 exit_status: "*" 和较高的限制值配合使用 | 真正的错误会被反复重试,浪费计算资源 | 指定特定的退出代码;将通配符限制值保持为 1 |
在 matrix.adjustments 内使用 agents: | 流水线上传失败:"agents is not a valid property on the matrix.adjustments configuration" | 从 adjustments 中移除 agents:;为每个平台使用单独的步骤,或使用动态流水线生成器来按组合路由到队列 |
| 构建失败,但所有可见步骤都已通过 | 某个触发步骤启动的子流水线失败了,或者某个步骤被取消而非解除阻塞 | 检查被触发流水线的构建状态;检查阻塞步骤是否被取消 |
| 流水线上传失败,且没有明确错误信息 | YAML 语法错误或 Agent 端的问题未显示在构建日志中 | 在本地验证 YAML;在主机上检查 Agent 日志,查找详细的上传错误;运行 buildkite-agent pipeline upload --debug |
| 在公共流水线上启用来自分支的构建 | 贡献者可以修改 pipeline.yml 来窃取机密 | 对公共仓库,在流水线设置中禁用来自分支的构建;为外部 PR 使用没有机密访问权限的单独流水线 |
| Docker Compose 步骤生成了工件,但 Agent 找不到 | 在容器内创建的文件对主机 Agent 不可见 | 在 docker-compose.yml 中将工作目录挂载为卷,以便容器输出可供 artifact_paths: 使用 |
| 动态流水线生成了 1000+ 个步骤 | UI 变慢,流水线处理性能下降 | 将生成的流水线控制在约 500 个步骤以内;对于更大的单体仓库,使用带有触发步骤的编排流水线 |
其他资源
参考文件
references/step-types-reference.md— 所有步骤类型的详细属性表references/advanced-patterns.md— 动态流水线生成器、矩阵调整、monorepo 模式、多阶段流水线references/retry-and-error-codes.md— 全面的退出代码表、按故障类型划分的重试策略references/group-steps.md— 分组步骤属性、DAG 模式、跨上传合并、不嵌套的变通方案、对作业数量上限的影响references/dynamic-pipeline-troubleshooting.md— 静默上传失败、配额限制、环境变量插值、重试时重复、重试风暴references/dynamic-pipeline-patterns.md— 扇出/扇入、SDK 生成、处理程序模式、最终处理步骤、基于触发器的扇出
示例
examples/basic-pipeline.yml— 最简可运行流水线(测试、等待、部署)examples/optimized-pipeline.yml— 功能齐全的流水线,包含缓存、并行处理、注释、重试、工件和通知
如需从其他 CI 系统迁移流水线,请参阅 buildkite-migration 技能。