3. 可观测性三大支柱在升级场景的应用:指标、日志与链路如何覆盖升级事件

Kubernetes 集群升级是一个典型的“状态机”过程:从预检、控速、节点排空、组件替换到后验证,每一步都可能引入故障。单一数据源无法完整描述升级的“健康度”。可观测性的三大支柱——指标(Metrics)、日志(Logs)、链路(Traces)——分别从聚合统计、事件记录和请求因果三个维度覆盖升级事件,形成互补的观测网格。

3.1 三大支柱在升级场景中的角色矩阵

下表从数据特征、升级事件覆盖范围、典型工具三个维度对比三大支柱在升级场景中的分工:

维度 指标(Metrics) 日志(Logs) 链路(Traces)
数据特征 时序聚合,数值型,低基数/高基数 非结构化/半结构化文本,带时间戳 请求级因果,Span 树,上下文传播
升级事件覆盖 节点状态、API Server 延迟、Pod 启动耗时、资源水位 kubelet 错误、组件崩溃、认证失败、排空超时 API 请求链路、控制器调谐、Webhook 调用链
典型工具 Prometheus + VictoriaMetrics / Thanos Loki / Elasticsearch + Fluentd Jaeger / Tempo / OpenTelemetry Collector
升级阶段敏感度 预检、控速、后验证 排空、组件替换、回滚 组件替换、Webhook 变更、准入控制
设计原则:指标用于“发现异常”,日志用于“定位根因”,链路用于“还原调用路径”。在升级场景中,三者应共享同一套标签体系(如 upgrade_id、node_group、phase),以实现从指标告警到日志检索再到链路追踪的“一键下钻”。

3.2 指标(Metrics):升级过程的“仪表盘”

指标是升级过程中最直接的“健康信号”。通过预定义的聚合指标,运维团队可以实时判断升级是否在安全边界内运行。核心指标分为三类:

  • 进度类指标:已升级节点数、剩余节点数、当前批次完成率。
  • 风险类指标:节点排空失败率、Pod 驱逐超时次数、API Server 错误率(5xx)。
  • 资源类指标:节点内存/CPU 使用率、etcd 磁盘空间、控制平面组件重启次数。

以下是一个典型的升级进度 Prometheus 记录规则示例:

# 记录每个升级批次的节点状态
- record: upgrade:node_phase_total
  expr: count by (upgrade_id, phase) (kube_node_info{phase=~"draining|upgrading|restarting|completed"})

# 记录排空失败率(5分钟滑动窗口)
- record: upgrade:drain_failure_ratio
  expr: |
    sum(rate(upgrade_drain_failure_total[5m]))
    /
    (sum(rate(upgrade_drain_attempt_total[5m])) > 0)
避坑提示:不要只依赖默认的 Kubernetes 指标(如 kube_node_status_condition)。升级场景需要自定义指标(如 upgrade_phase_duration_seconds、upgrade_rollback_triggered_total),这些指标必须通过升级控制器或 Operator 主动暴露,否则无法区分“正常波动”与“升级故障”。

3.3 日志(Logs):升级事件的“黑匣子”

日志提供了升级过程中最细粒度的上下文。当指标显示异常时,日志是定位根因的第一入口。升级场景中需要重点采集的日志源包括:

  • kubelet 日志:节点排空、Pod 驱逐、容器重启事件。
  • kube-apiserver 日志:认证失败、资源冲突、Webhook 调用超时。
  • 集群升级控制器日志:批次决策、控速逻辑、回滚触发条件。
  • 节点初始化脚本日志:包管理器输出、kubelet 启动参数变更。

日志结构化是升级可观测性的关键。推荐使用 JSON 格式并包含以下字段:

{
  "timestamp": "2025-03-21T14:30:00Z",
  "upgrade_id": "ug-20250321-v1.28-v1.29",
  "node": "worker-03",
  "phase": "draining",
  "event": "pod_eviction_timeout",
  "pod": "nginx-abc123",
  "namespace": "production",
  "duration_seconds": 300,
  "error": "PodDisruptionBudget 'pdb-nginx' minAvailable violation"
}
最佳实践:在升级控制器中注入 upgrade_id 和 phase 标签到所有日志条目。这样在 Loki 或 Elasticsearch 中,只需一条查询 {upgrade_id="ug-20250321-v1.28-v1.29"} |= "error" 即可聚合整个升级周期的所有异常事件。

3.4 链路(Traces):升级影响的“因果链”

链路追踪在升级场景中常被忽视,但它恰恰是理解“升级导致服务降级”因果关系的唯一手段。升级过程中,组件版本变更、Webhook 配置更新、API 版本废弃都会改变请求路径。链路追踪可以回答以下问题:

  • 升级后,某个请求是否因为 API 版本不匹配而失败?
  • MutatingWebhookConfiguration 更新后,Pod 创建请求的延迟是否增加?
  • 控制平面升级期间,etcd 写入延迟是否影响了所有写请求?

以下是一个升级场景下的链路追踪上下文传播示例(OpenTelemetry):

// 在升级控制器中创建根 Span
tracer := otel.Tracer("upgrade-controller")
ctx, span := tracer.Start(context.Background(), "node-upgrade",
    trace.WithAttributes(
        attribute.String("upgrade.id", "ug-20250321-v1.28-v1.29"),
        attribute.String("node.name", "worker-03"),
        attribute.String("phase", "draining"),
    ),
)
defer span.End()

// 在排空操作中创建子 Span
drainCtx, drainSpan := tracer.Start(ctx, "drain-node")
// 执行排空逻辑...
drainSpan.SetAttributes(
    attribute.Int("pods.evicted", 12),
    attribute.Int("pods.failed", 1),
)
drainSpan.End()
关键设计:升级链路追踪的“根 Span”应该以“节点升级”或“批次升级”为粒度,而不是以“整个集群升级”为粒度。这样每个节点升级的耗时、失败点、重试次数都可以独立分析,避免单个长 Span 掩盖局部故障。

3.5 三大支柱的协同覆盖模型

下图展示了指标、日志、链路如何协同覆盖一次完整的节点升级事件生命周期:

三大支柱协同覆盖节点升级事件生命周期 预检 排空 升级 重启 验证 指标覆盖 • 节点资源水位 • API Server 延迟 P99 • 排空失败率 • Pod 启动耗时 • 组件重启次数 • etcd 操作延迟 日志覆盖 • kubelet 排空错误 • Pod 驱逐超时详情 • API 版本不匹配 • Webhook 调用失败 • 控制器决策日志 • 节点初始化输出 链路覆盖 • 排空操作调用链 • Webhook 准入延迟 • API 请求版本协商 • 控制器调谐因果 • etcd 事务追踪 • 组件启动初始化链 每个升级阶段都同时被指标、日志、链路覆盖,形成“检测 → 定位 → 还原”的闭环

3.6 升级事件统一标签体系

要实现三大支柱的协同,必须建立统一的标签(Label / Tag)体系。推荐的最小标签集如下:

标签名 类型 示例值 说明
upgrade_id 字符串 ug-20250321-v1.28-v1.29 全局唯一升级批次标识
node_group 字符串 worker-batch-01 节点分组,用于控速和灰度
phase 枚举 draining 当前升级阶段
node_name 字符串 worker-03 目标节点
source_version 字符串 v1.28.5 升级前版本
target_version 字符串 v1.29.2 升级目标版本
result 枚举 success / failure / rollback 升级结果
实施要点:在升级控制器中,将上述标签注入到 Prometheus 指标的 Label、日志的 Structured Fields、以及 OpenTelemetry Span 的 Attributes 中。这样在 Grafana 中,可以从一个指标图表直接跳转到关联的日志查询和链路追踪视图,实现真正的“可观测性闭环”。