3. GitLab CI 流水线核心组件:Job、Stage、Pipeline 的结构与生命周期

在构建 SLI 采集体系之前,必须精确理解 GitLab CI 的三个核心抽象:Job(作业)、Stage(阶段)和 Pipeline(流水线)。这三者构成了流水线的执行骨架,也是 SLI 指标采集的锚点。只有厘清它们的结构关系与生命周期状态,才能设计出高精度的故障排查与告警降噪规则。

3.1 三层组件结构

GitLab CI 采用严格的层级嵌套结构:Pipeline 包含多个 Stage,Stage 包含多个 Job。每个 Job 是实际执行的最小单元,Stage 控制并行与串行顺序,Pipeline 代表一次完整的集成流程。

核心原则:SLI 指标必须绑定到具体的 Job 执行实例(Pipeline ID + Job ID),而非模糊的阶段名称。同一 Stage 内的 Job 并行执行,不同 Stage 之间串行等待。
组件 定义 SLI 采集关注点
Job 由 script、before_script、after_script 定义的执行单元,运行在独立容器中 执行时长、退出码、日志大小、重试次数、artifacts 生成状态
Stage 一组并行 Job 的逻辑分组,由 stages 关键字定义顺序 阶段总耗时、阻塞时间、并行 Job 失败率、依赖传递延迟
Pipeline 由代码推送、合并请求或定时触发的一次完整 CI 执行 总耗时、通过率、失败阶段分布、触发频率、排队时间
GitLab CI 三层组件结构 Pipeline(流水线) 触发源:push / merge_request / schedule / manual 生命周期:pending → running → passed / failed / canceled Stage: build 并行 Job 组 编译、打包 Stage: test 并行 Job 组 单元测试、lint Stage: deploy 并行 Job 组 部署到环境 compile package unit lint staging prod SLI 采集粒度:每个 Job 独立采集 → 聚合到 Stage → 聚合到 Pipeline

3.2 Job 生命周期与状态机

Job 是 SLI 指标的最小采集单元。一个 Job 从创建到结束经历严格的状态转换,每个状态都对应可观测的指标点。

# 典型 Job 定义示例
job_build:
  stage: build
  script:
    - echo "Compiling..."
    - make build
  artifacts:
    paths:
      - dist/
  retry: 2
  timeout: 30 minutes
状态 含义 SLI 采集时机 常见故障模式
pending Job 已创建,等待 Runner 分配 记录入队时间戳 Runner 资源不足导致长时间 pending
running Runner 已领取 Job,开始执行 记录开始时间戳,启动计时 容器拉取镜像超时、脚本卡死
passed 所有 script 命令退出码为 0 记录结束时间戳,计算执行时长 无(正常状态)
failed 至少一条命令退出码非 0 记录失败时间戳、退出码、日志尾部 编译错误、测试失败、依赖缺失
canceled 用户手动取消或上游 Job 失败导致取消 记录取消时间戳 误操作、级联取消未处理
skipped 因 rules 或 only/except 条件不满足而未执行 记录跳过原因 规则配置错误导致 Job 意外跳过
SLI 采集陷阱:不要仅依赖最终状态(passed/failed)判断健康度。pending 时间过长、running 阶段日志无输出超过 5 分钟、retry 次数用尽等中间状态,往往是更早的故障信号。建议对 pending 时长和 running 阶段的心跳间隔单独设置 SLI。

3.3 Stage 执行模型与依赖关系

Stage 定义了 Job 之间的执行顺序和并行边界。默认情况下,同一 Stage 内的 Job 并行执行,不同 Stage 按 stages 列表顺序串行执行。这种模型直接影响 SLI 中的“阶段阻塞时间”和“关键路径”计算。

# 阶段定义示例
stages:
  - build
  - test
  - deploy

# 依赖控制:test 阶段需要 build 阶段的 artifacts
test_job:
  stage: test
  needs: ["build_job"]
  script:
    - npm test
Stage 执行模型与关键路径 Stage: build compile (8s) package (5s) Stage: test unit (12s) lint (3s) Stage: deploy staging (6s) prod (10s) 关键路径(Critical Path) compile (8s) → unit (12s) → prod (10s) = 30s 总耗时 SLI 关键指标:Stage 阻塞时间 = 本 Stage 最慢 Job 耗时 + 上游依赖等待时间 告警降噪:区分“等待 Runner”与“实际执行”两个阶段的耗时

3.4 Pipeline 生命周期与触发类型

Pipeline 的生命周期从触发事件开始,到所有 Stage 执行完毕或中断结束。不同的触发类型对应不同的 SLI 基线,必须分开统计。

触发类型 触发条件 典型 SLI 基线 故障排查特点
push 代码推送到仓库分支 总耗时 < 5 min,通过率 > 95% 关注增量变更导致的编译/测试失败
merge_request 创建或更新合并请求 总耗时 < 10 min,通过率 > 90% 关注合并冲突、目标分支变更
schedule 定时任务(如每日构建) 总耗时 < 30 min,成功率 100% 关注环境依赖过期、外部服务不可用
manual 手动触发(如紧急修复) 无固定基线,按需监控 关注人为操作错误、权限问题
trigger 上游 Pipeline 或 API 调用触发 端到端延迟 < 2 min 关注跨项目依赖、令牌过期

3.5 生命周期状态转换与 SLI 采集点

完整的 Pipeline 生命周期包含以下状态转换,每个转换点都是 SLI 采集的黄金位置:

  1. created → pending:Pipeline 被创建,等待 Runner 资源。采集:创建时间、排队时长。
  2. pending → running:第一个 Job 开始执行。采集:排队延迟、Runner 分配耗时。
  3. running → passed/failed:所有 Stage 执行完毕。采集:各阶段耗时、失败 Job 分布。
  4. running → canceled:手动取消或级联取消。采集:取消原因、已执行 Job 比例。
最佳实践:在 Pipeline 的 created 状态立即记录时间戳,而不是等到 pending。因为从 created 到 pending 的转换可能因 Runner 资源不足而延迟,这个延迟本身就是重要的 SLI 指标。建议在 Webhook 中监听 pipeline_event 的 pending 和 running 状态变化。

3.6 组件关系对 SLI 采集的影响

理解三层组件的结构关系后,可以总结出以下 SLI 采集原则:

采集层级 直接采集对象 聚合方式 告警降噪价值
Job 级 单个 Job 的执行时长、退出码、重试次数 按 Job 名称聚合,建立历史基线 快速定位具体失败的脚本步骤
Stage 级 Stage 总耗时、并行 Job 失败率 按 Stage 名称聚合,计算阻塞时间 区分“单个 Job 失败”与“整个 Stage 阻塞”
Pipeline 级 总耗时、通过率、触发频率 按分支/触发类型聚合 识别全局退化趋势,避免逐 Job 排查