GitLab CI 基础:Pipeline、Job、Stage 概念解析
刚开始接触 GitLab CI 的时候,我其实挺懵的。什么 Pipeline、Job、Stage,一堆术语砸过来。后来我在一个实际项目里亲手搭了一套 Kotlin 回归测试流水线,才真正搞明白这些概念到底在说什么。
说白了,GitLab CI 的核心就是一套自动化任务编排系统。你写一个 .gitlab-ci.yml 文件,告诉 GitLab:「当代码 push 上来以后,先做什么,再做什么,最后做什么」。就这么简单。
一句话总结:Pipeline 是整个流程,Stage 是流程里的阶段,Job 是每个阶段里具体干活的单元。
Pipeline:整条流水线
Pipeline 翻译过来就是「管道」或「流水线」。我习惯把它想象成一条汽车生产线——从原材料进来,到零件组装,再到质量检测,最后成品下线。整个过程就是一个 Pipeline。
在 GitLab CI 里,每次你往仓库 push 代码,或者手动触发一次 CI,就会自动创建一个 Pipeline。这个 Pipeline 里可以包含多个 Stage,Stage 里又包含多个 Job。Pipeline 的状态取决于它里面所有 Job 的执行结果——只要有一个 Job 失败,整个 Pipeline 就是失败的。
我踩过的坑:有一回我写的 Pipeline 里有个 Job 跑了一个小时还没结束,结果整个 Pipeline 被 GitLab Runner 超时杀掉了。后来我学会了给关键 Job 加 timeout 参数,提前暴露问题。
Stage:流水线的阶段
Stage 就是 Pipeline 里的一个个阶段。比如一个典型的回归测试流水线,我会分成这几步:
- build —— 编译 Kotlin 代码,生成 jar 包
- unit-test —— 跑单元测试
- integration-test —— 跑集成测试(这部分往往是回归测试重点)
- deploy-staging —— 部署到测试环境
默认情况下,Stage 是顺序执行的。前一个 Stage 里所有 Job 都成功,才会执行下一个 Stage。但你可以通过 needs 关键字打破这个规则,让某些 Job 提前跑。
注意:Stage 的名字可以随便取,但不要用空格或特殊字符。而且多个 Stage 之间是有依赖关系的——如果你把部署放在编译前面,那部署 Job 肯定拿不到编译产物。
Job:具体干活的工人
Job 是最小执行单元。每个 Job 跑在一个独立的 Runner 容器里,互不干扰。一个 Stage 里可以定义多个 Job,它们默认是并行执行的。这很实用——比如「跑集成测试」这个 Stage,你可以同时跑数据库测试、API 测试、UI 测试,三个 Job 一起上,大大缩短流水线总时间。
来看一个最简示例:
stages:
- build
- test
- deploy
build-job:
stage: build
script:
- ./gradlew assemble
unit-test-job:
stage: test
script:
- ./gradlew test
integration-test-job:
stage: test
script:
- ./gradlew integrationTest
deploy-job:
stage: deploy
script:
- ./gradlew deployToStaging
你看,test 这个 Stage 里有两个 Job,它们会同时启动。我实际项目中遇到过一个问题:两个 Job 同时访问同一个数据库,导致测试数据互相污染。嗯,那之后我学会了用 parallel 和资源隔离。
三者关系:一张图说清
一个小技巧:看清楚依赖关系
| 概念 | 类比 | 关键属性 |
|---|---|---|
| Pipeline | 整条生产流水线 | 由一次 push 或 API 触发,包含所有 Stage |
| Stage | 流水线的某个工位 | 默认顺序执行,可配置并行 |
| Job | 工位上的工人 | 最小执行单元,每个 Job 独立容器运行 |
避坑指南:我曾经在一个大项目里把 20 个 Job 全放在同一个 Stage 里,结果 GitLab Runner 负载过高,好几个 Job 因为等待资源超时失败了。后来我把它们分散到多个 Stage,或使用 parallel: 5 分组执行,问题就解决了。
怎么查看 Pipeline 运行状态?
你 push 代码后,去项目的 CI/CD -> Pipelines 页面就能看到。每个 Pipeline 都有一个状态图标:绿色对号表示通过,红色叉号表示失败,橙色圆圈表示运行中。点进去可以看到每个 Stage 的详情,以及每个 Job 的控制台日志——这是调试问题的利器。
我个人的一个小习惯:在 Job 脚本里加 echo "::group::初始化环境" 之类的日志分组命令,让日志更好读。你想想看,如果某个 Job 失败了,日志打印了上千行,没有分组简直要命。
好,关于 Pipeline、Job、Stage 的基础概念就先讲这么多。记住那个关系图,后面的章节我们会动手写一个真实的 .gitlab-ci.yml,把 Kotlin 回归测试流水线跑起来。