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 三大支柱的协同覆盖模型
下图展示了指标、日志、链路如何协同覆盖一次完整的节点升级事件生命周期:
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 中,可以从一个指标图表直接跳转到关联的日志查询和链路追踪视图,实现真正的“可观测性闭环”。