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指标落地的完整数据流,包含排除逻辑的过滤节点:
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. 通过
2.
3. 手动Job(
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重试率)另行跟踪。