Skip to content
CI/CD 基本概念:流水线、阶段与任务
流水线不是单个过程,而是一组按约束组织起来的执行单元。理解它的结构,是讨论配置、调试和排障的前提。整个模型围绕三个抽象展开:阶段(Stage)、任务(Job)、步骤(Step)。
阶段
阶段是流水线的第一层分组。它把一个完整的交付流程拆成若干段落,每个段落负责一类工作——例如构建阶段产出可运行的包,测试阶段验证包的行为,部署阶段把包推到目标环境。
阶段之间是严格串行的。前一阶段的所有任务完成后,下一阶段才会启动。这个约束不是摆设:构建阶段失败意味着代码还没有变成可运行形态,测试没有意义;测试阶段失败,部署一个已知有问题的版本就是在制造麻烦。部分平台(例如华为云 CodeArts Pipeline)还支持在阶段边界配置准出条件,要求检查结果满足策略后才放行,而不仅仅是任务执行完毕。
任何阶段出现错误或测试失败,流水线终止,后续变更必须从代码提交重新开始。因此,阶段在本质上是一种门禁机制——它把“是否允许继续”的判断内化到了执行顺序里。
阶段回答的问题是:什么时候做,以及做不完或做坏了就停。
任务
一个阶段通常包含多项独立的工作,它们之间没有先后依赖。任务就是用来承载这些独立工作的单元。
在 GitLab 中,同一个阶段内声明的所有 job 会并行执行。比如在 test 阶段,你可以同时跑单元测试、集成测试和代码风格检查。它们各自拉取代码、安装依赖、执行命令,互不影响。只有这些 job 全部成功,test 阶段才算完成,deploy 阶段才会启动。
GitHub Actions 的默认行为不同——jobs 默认并行,但如果需要阶段式的推进,必须用 needs 关键字手动声明依赖链。两种设计的差异在于:GitLab 把“阶段”作为优先的编排维度,GitHub Actions 把“依赖”作为优先的编排维度。最终都能实现同样的执行顺序,只是配置的思考路径不一样。
任务回答的问题是:在同一段时间内,可以同时做什么。
步骤
步骤是任务内部的最小执行单元,通常是一条 Shell 命令或一个脚本调用。一个任务就是一组按顺序排列的步骤。
以 GitLab CI 的 job 为例:
yaml
build-app:
stage: build
script:
- npm ci
- npm run buildscript 下面的两行就是两个步骤。它们在同一台 runner 上依次执行:先装依赖,再跑构建。前一步失败,后续步骤默认跳过,整个 job 标记为失败。GitHub Actions 的步骤行为完全一样——job 内的 steps 按定义顺序执行,某一步失败后,该 job 的其余步骤不再运行。
步骤的存在是为了把任务内部的操作显式化。排查失败时,你可以立刻知道是安装依赖那一步挂了,还是构建脚本本身挂了,不需要对着一条合并后的日志猜测。
步骤回答的问题是:一项任务究竟按什么顺序做。
层次结构
把阶段、任务、步骤串起来,得到的是一个三段式层次:
- 流水线包含若干个阶段,阶段之间串行;
- 每个阶段包含若干个任务,同一阶段的任务并行;
- 每个任务包含若干个步骤,步骤串行执行。
这个结构不是某个工具的独特设计,而是几乎所有 CI/CD 平台共享的抽象模型。GitLab 的 Pipeline → Job → Script、GitHub Actions 的 Workflow → Job → Step、Jenkins 的 Pipeline → Stage → Steps,都是同一套模型的不同命名。命名差异本身不重要,关键是在阅读文档和编写配置时,头脑里要有这三个层次的位置感。
执行流程
理解了静态结构之后,看一遍完整的执行过程。
触发通常来自 Webhook。开发者在本地推送代码到仓库,Git 平台收到 push 事件后向 CI/CD 平台发送 HTTP 回调。平台根据事件类型和分支匹配规则,找到对应的流水线定义并启动执行。
启动后的流程如下:
- 平台解析流水线配置,建立阶段队列。
- 第一阶段启动,该阶段内的所有任务被分发到可用的 runner 上并行执行。
- 每个任务内部,步骤按声明顺序依次执行。任意步骤以非零状态码退出,该任务立即失败。
- 第一阶段内所有任务完成(且全部成功)后,第二阶段启动;否则流水线终止。
- 重复步骤 2—4,直到所有阶段完成或中途终止。
这就是“阶段串行、任务并行、步骤串行”在运行时的落地方式。
配置示例
下面这段 .gitlab-ci.yml 展示了三层结构在实际配置中的样子:
yaml
stages:
- build
- test
- deploy
build-app:
stage: build
script:
- npm ci
- npm run build
unit-test:
stage: test
script:
- npm test
lint:
stage: test
script:
- npm run lint
deploy-staging:
stage: deploy
script:
- npm run deploy -- --env staging逐层来看:
stages声明了三个阶段及其执行顺序:build→test→deploy。build-app、unit-test、lint、deploy-staging是四个任务,各自通过stage归属到对应阶段。- 每个任务下的
script是一组步骤,按书写顺序执行。 unit-test和lint同在test阶段,运行时会并行执行。等这两个都成功后,deploy阶段才会启动。
对应到层次模型:
Pipeline
├── Stage: build
│ └── Job: build-app
│ ├── Step: npm ci
│ └── Step: npm run build
├── Stage: test
│ ├── Job: unit-test
│ │ └── Step: npm test
│ └── Job: lint
│ └── Step: npm run lint
└── Stage: deploy
└── Job: deploy-staging
└── Step: npm run deploy -- --env staging阶段提供了顺序和门禁,任务提供了并行度,步骤提供了可回溯的执行记录。
注意点
不同工具的默认并行策略不同。 GitLab 中只有同阶段的 job 才并行,且前一阶段全部成功才会推进。GitHub Actions 中 jobs 默认全部并行,阶段语义需要用 needs 显式构建。如果按 GitLab 的心智模型去写 GitHub Actions 的 workflow,容易写出没有依赖声明、所有 job 一起跑的配置,行为会与预期完全不同。
阶段是逻辑分组,不保证环境隔离。 同一个阶段的不同任务可能跑在不同的 runner 上,也可能复用同一台 runner(取决于平台调度)。如果需要干净的环境,应该在任务中显式处理,而不是依赖阶段来做隔离。
步骤的原子性是约定,不是强制保证。 步骤通常是一条命令,但这条命令内部可能做很多事。如果一份脚本文件在步骤中被调用,它的内部失败不一定能正确传递退出码。写脚本时应当处理 set -e 或等价机制。
门禁不等于人工审批。 阶段的自动推进靠的是前一阶段全部成功。如果需要人工确认才进入下一阶段,那是审批节点的职责,不在阶段串行机制本身的覆盖范围内。部分平台支持在阶段间插入手动审批,但这是扩展功能而非核心抽象。
小结
理解流水线,最值得内化的就是这三个层次:
- 阶段 编排顺序,失败即停,是质量门禁;
- 任务 提供并行,同阶段的任务同时跑,缩短反馈时间;
- 步骤 记录执行的每一步,让失败可以精确定位。
后续讨论流水线如何与实际构建流程对接时,这三个概念会一直出现。
参考链接
- [1] https://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/strategy-cicd-litmus/understanding-cicd.html
- [5] https://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/strategy-cicd-litmus/cicd-best-practices.html
- [6] https://docs.gitlab.com/ci/pipelines/
- [7] https://docs.gitlab.com/ci/yaml/
- [8] https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions
- [9] https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idneeds
- [10] https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idsteps
- [11] https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows
- [13] https://www.jenkins.io/doc/book/pipeline/syntax/
- [15] https://support.huaweicloud.com/bestpractice-pipeline/pipeline-bestpractice-pdf.pdf
