4. 流水线成功率SLI:定义口径与参数配置

流水线成功率(Pipeline Success Rate)是衡量CI/CD交付质量最核心的SLI之一。它直接反映代码从提交到产出制品的全链路健康度。本章将围绕该SLI的定义口径、排除条件和数据采集方式展开,并给出GitLab CI中的具体配置案例。

4.1 核心定义口径:成功Job数 / 总Job数

流水线成功率SLI的原子计算单元是Job,而非Pipeline本身。因为一个Pipeline可能包含多个并行或串行的Job,单个Job的失败往往能更精确地定位问题环节。

指标项 定义 说明
成功Job数 状态为 success 的Job数量 包括手动触发后成功执行的Job,以及重试后成功的Job
总Job数 Pipeline中所有被调度执行的Job总数 不包括 manual 且未触发的Job,不包括 skipped 的Job
成功率公式 成功Job数 ÷ 总Job数 × 100% 按时间窗口(如1小时、1天)聚合计算
口径要点: 总Job数必须排除“未执行”的manual Job,否则分母虚增会导致成功率失真。建议在采集层直接过滤 status != 'manual' && status != 'skipped'。

4.2 排除条件:手动取消与基础设施故障

并非所有Job失败都代表代码或配置问题。为了得到真实的“交付质量”SLI,必须从分母和分子中排除两类非业务性失败:

  • 手动取消(Manual Cancellation):由用户主动点击Cancel导致的Job终止。这类事件通常与代码质量无关,例如:
    - 开发人员误触发Pipeline后手动取消
    - 产品经理临时叫停某个功能分支的构建
    排除方式: 在数据采集时过滤 status == 'canceled' 且 user_id 为人工操作(非系统自动取消)。
  • 基础设施故障(Infrastructure Failure):Runner失联、磁盘空间不足、网络超时、Docker daemon崩溃等环境问题导致的Job失败。
    排除方式: 通过GitLab API的 failure_reason 字段识别,常见值包括 runner_system_failure、stuck_or_timeout_failure、runner_unsupported。
注意: 排除基础设施故障时,建议保留“因资源配额不足(如CI minutes耗尽)导致的失败”,这类问题通常属于团队管理范畴,应纳入SLI统计以驱动改进。

4.3 数据采集方式

GitLab提供了两种主流的数据采集路径:API拉取和Webhook推送。生产环境建议两者结合,确保数据不丢失。

4.3.1 基于GitLab API的拉取模式

通过 GET /projects/:id/jobs 接口获取指定时间范围内的所有Job记录,然后本地聚合计算成功率。以下是一个Python采集脚本的核心逻辑:

import requests
import time

GITLAB_URL = "https://gitlab.example.com"
PROJECT_ID = "12345"
PRIVATE_ = "your__here"
WINDOW_START = int(time.time()) - 3600  # 过去1小时

def fetch_jobs(page=1):
    url = f"{GITLAB_URL}/api/v4/projects/{PROJECT_ID}/jobs"
    params = {
        "per_page": 100,
        "page": page,
        "created_after": "2025-01-01T00:00:00Z",
        "scope": ["success", "failed", "canceled"]
    }
    headers = {"PRIVATE-": PRIVATE_}
    resp = requests.get(url, params=params, headers=headers)
    return resp.json()

def calculate_success_rate(jobs):
    total = 0
    success = 0
    for job in jobs:
        # 排除手动取消和基础设施故障
        if job["status"] == "canceled":
            continue
        if job.get("failure_reason") in ["runner_system_failure", "stuck_or_timeout_failure"]:
            continue
        total += 1
        if job["status"] == "success":
            success += 1
    return success / total if total > 0 else 1.0

# 分页采集并计算
all_jobs = []
page = 1
while True:
    jobs = fetch_jobs(page)
    if not jobs:
        break
    all_jobs.extend(jobs)
    page += 1

rate = calculate_success_rate(all_jobs)
print(f"Pipeline Job成功率: {rate:.2%}")

4.3.2 基于Webhook的推送模式

在GitLab项目设置中配置 Job Events Webhook,将Job状态变化实时推送到自建监控系统。推荐的数据结构如下:

字段 类型 说明
job_id integer Job唯一ID
status string success / failed / canceled
failure_reason string 仅当status=failed时存在
pipeline_id integer 所属流水线ID
created_at datetime Job创建时间
推荐做法: 使用API拉取做全量数据回填(每日一次),使用Webhook做实时增量采集。两者通过 job_id 去重合并,即可得到完整、低延迟的SLI数据源。

4.4 流水线成功率SLI数据流架构

下图展示了从GitLab事件产生到SLI指标落地的完整数据流,包含排除逻辑的过滤节点:

流水线成功率SLI数据采集与过滤架构 流水线成功率SLI 数据采集与过滤架构 GitLab Pipeline Job 事件源 API 拉取 Webhook 推送 排除过滤器 手动取消 / 基础设施故障 SLI 计算器 监控看板 说明: API拉取用于全量回填,Webhook 用于实时增量。两者在SLI计算器 中按job_id去重合并。

4.5 参数配置实战:.gitlab-ci.yml 中的SLI埋点

为了配合SLI采集,建议在流水线配置中显式标记Job的业务类型和重试策略,方便后续排除逻辑的自动化处理:

stages:
  - build
  - test
  - deploy

variables:
  SLI_JOB_TYPE: "build"  # 默认值,可在每个Job中覆盖

build-job:
  stage: build
  variables:
    SLI_JOB_TYPE: "build"
  script:
    - echo "Building application..."
  retry:
    max: 2
    when:
      - runner_system_failure
      - stuck_or_timeout_failure
  artifacts:
    paths:
      - dist/

test-job:
  stage: test
  variables:
    SLI_JOB_TYPE: "test"
  script:
    - echo "Running tests..."
  retry:
    max: 1
    when:
      - runner_system_failure

deploy-job:
  stage: deploy
  variables:
    SLI_JOB_TYPE: "deploy"
  script:
    - echo "Deploying to production..."
  only:
    - main
  when: manual  # 手动触发Job,不计入SLI分母
配置要点:
1. 通过 SLI_JOB_TYPE 变量标记Job类型,便于在监控系统中按阶段分析成功率。
2. retry.when 仅配置基础设施故障类型,避免重试掩盖代码缺陷。
3. 手动Job(when: manual)默认不计入SLI分母,符合口径定义。

4.6 成功率SLI的聚合与阈值建议

采集到原始数据后,建议按以下维度聚合,并设置对应的SLO目标:

聚合维度 时间窗口 建议SLO 说明
全项目全局 7天滚动 ≥ 99.5% 反映整体交付健康度
按Job类型(build/test/deploy) 24小时 ≥ 99% 快速定位薄弱环节
按触发分支(main/feature) 1小时 ≥ 95% 用于开发阶段快速反馈
避坑提醒: 不要将“重试后成功的Job”计入失败次数。在SLI计算中,只要Job最终状态为success,无论重试几次,都应计入成功Job数。重试次数应作为独立的SLI(Job重试率)另行跟踪。