4. 部署频率 SLI 口径(一):从 K8s Deployment/StatefulSet 的 revision 历史中提取部署事件,计算单位时间内的部署次数

4.1 为什么选择 Revision 历史作为部署事件源

在 DORA 度量体系中,部署频率(Deployment Frequency, DF) 是最核心的四个指标之一,它直接反映团队交付吞吐能力。对于运行在 Kubernetes 上的应用,最精确、最无侵入的部署事件来源并非 CI/CD 管道的触发日志,而是 Kubernetes 控制面自身记录的 Revision 历史。

Kubernetes 的 Deployment 和 StatefulSet 控制器在每次 Pod 模板(PodTemplateSpec)发生变化时,会自动创建一个新的 Revision,并记录在 .spec.revisionHistoryLimit 控制的滚动历史中。这个机制天然具备以下优势:

  • 数据权威性:Revision 由 kube-controller-manager 在 API Server 上原子性地创建,不受 CI/CD 工具链故障或网络中断影响。
  • 无侵入采集:无需在 CI/CD 管道中埋点,无需修改应用代码或 Helm Chart。
  • 统一口径:无论团队使用 Jenkins、GitLab CI、ArgoCD 还是手动 kubectl apply,最终都会在 Revision 历史中留下记录。
  • 粒度精确:每个 Revision 对应一次真实的 Pod 模板变更,天然过滤掉“空部署”(如只修改副本数、只修改 label 等不触发新 Revision 的操作)。
关键原则:部署频率 SLI 只统计 触发新 Revision 的变更。仅修改 replicas、修改滚动更新策略、修改 label/annotation(不影响 Pod 模板)等操作,不产生新 Revision,也不计入部署次数。

4.2 Revision 历史的数据结构与提取方法

4.2.1 Revision 的存储方式

Kubernetes 将每个 Revision 以 ReplicaSet(对于 Deployment)或 ControllerRevision(对于 StatefulSet)的形式持久化在 etcd 中。两种资源的 Revision 提取方式略有不同:

工作负载类型 Revision 载体 Revision 标识字段 创建时间字段
Deployment ReplicaSet metadata.annotations['deployment.kubernetes.io/revision'] metadata.creationTimestamp
StatefulSet ControllerRevision metadata.name 中的 revision 数字(如 web-7d8f9c6b5) metadata.creationTimestamp

4.2.2 提取部署事件的步骤

  1. 确定目标工作负载:按 namespace、label selector 或 deployment/statefulset 名称列表筛选。
  2. 获取所有关联的 Revision 载体:
    • 对于 Deployment:通过 kubectl get replicasets -l <selector> -n <ns> 获取所有 ReplicaSet。
    • 对于 StatefulSet:通过 kubectl get controllerrevisions -n <ns> 获取所有 ControllerRevision。
  3. 过滤出有效的部署事件:
    • 只保留 metadata.ownerReferences 指向目标 Deployment/StatefulSet 的 Revision。
    • 排除当前活跃的 Revision(即 .status.currentRevision 或 .status.observedGeneration 对应的最新 Revision),因为活跃 Revision 的创建时间不代表本次部署完成时间。
  4. 提取时间戳:使用 metadata.creationTimestamp 作为部署事件的发生时间。
  5. 按时间窗口聚合:将时间戳按天、周或月进行分组计数。
生产环境建议:不要直接在生产集群上频繁执行 kubectl get replicasets --all-namespaces。推荐使用 Prometheus 的 kube_replicaset_created 指标或通过 Kubernetes API 的 Watch 机制增量采集,避免对 API Server 造成过大压力。

4.3 部署频率 SLI 的计算口径

部署频率 SLI 的通用计算公式为:

部署频率 = 有效部署事件总数 / 时间窗口长度(天)

在 Kubernetes Revision 历史场景下,具体口径定义如下:

口径参数 取值 说明
事件定义 每个非活跃的 Revision 创建事件 排除当前正在运行的 Revision,避免重复计数
时间窗口 滚动窗口(如最近 7 天 / 30 天) 推荐使用 7 天窗口,兼顾稳定性和灵敏度
聚合粒度 按工作负载(deployment/statefulset)聚合 也可按 namespace、团队、服务层级聚合
排除项 回滚操作、金丝雀发布中的中间 Revision 回滚会创建新 Revision,但应视为一次部署;金丝雀的中间 Revision 是否计入取决于团队定义

4.4 部署事件提取流程架构

下图展示了从 Kubernetes 集群中提取 Revision 历史并计算部署频率的完整数据流:

从 Revision 历史提取部署频率的数据流 Kubernetes API Server ReplicaSet / ControllerRevision etcd 持久化存储 Revision 历史记录 Prometheus kube_replicaset_created Revision 事件采集器 定时轮询 / Watch API Prometheus 指标抓取 kube-state-metrics 暴露 部署事件处理器 过滤活跃 Revision → 提取 creationTimestamp → 按工作负载分组 时间序列数据库 Prometheus / Thanos / VictoriaMetrics 可视化与告警 Grafana Dashboard / 部署频率趋势 说明:Revision 历史天然包含回滚和金丝雀发布的中间版本,团队应根据自身部署策略决定是否计入 SLI

4.5 实际计算示例

假设我们有一个名为 payment-service 的 Deployment,在最近 7 天内产生了以下 Revision 历史:

Revision 编号 ReplicaSet 名称 创建时间 是否活跃
1 payment-service-6b8d9f4c7 2025-03-01 10:00:00 否
2 payment-service-7c9e0a5d8 2025-03-03 14:30:00 否
3 payment-service-8d0f1b6e9 2025-03-05 09:15:00 否
4 payment-service-9e1g2c7f0 2025-03-07 16:45:00 是(当前运行)

计算过程:

  • 有效部署事件总数:3(Revision 1、2、3,排除活跃的 Revision 4)
  • 时间窗口:7 天
  • 部署频率 = 3 / 7 ≈ 0.43 次/天
常见陷阱:如果团队频繁执行 kubectl rollout undo 回滚,每次回滚都会创建一个新的 Revision(即使 Pod 模板与历史版本相同)。此时部署频率会虚高。建议在 SLI 口径中明确:回滚操作是否计入部署次数。通常建议计入,因为回滚同样代表一次生产变更,且可能引入风险。

4.6 与 CI/CD 管道部署次数的差异对比

对比维度 K8s Revision 历史口径 CI/CD 管道触发口径
数据来源 Kubernetes 控制面(etcd) Jenkins / GitLab CI / ArgoCD 日志
可靠性 高(集群原生,不受管道故障影响) 中(管道故障、日志丢失会导致数据缺失)
粒度 精确到 Pod 模板变更 可能包含空部署、构建失败等无效事件
回滚处理 自动生成新 Revision,可识别 需额外逻辑判断是否为回滚
采集复杂度 低(直接调用 Kubernetes API) 高(需对接多种 CI/CD 工具)
口径一致性 统一(所有工作负载使用相同机制) 不统一(不同工具、不同团队定义不同)

从 SRE 和可观测性角度,强烈推荐优先使用 K8s Revision 历史作为部署频率 SLI 的数据源。它提供了最干净、最可靠、最统一的部署事件视图,是构建 DORA 度量体系的基础设施级最佳实践。