Kubernetes 可观测性:别只收集指标,要还原一次请求发生了什么

2026-08-31 29 预计阅读时间: 1 分钟
来源: cncf.io AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:9 分钟

Kubernetes 让基础设施更容易编排、扩缩容和自愈,却也改变了故障的形态:Pod 会漂移,副本会频繁替换,服务依赖持续增长,一次用户请求可能依次穿过 Ingress、多个 Service、消息队列、存储系统和后台任务。此时,单张 CPU 曲线只能告诉你“某处变忙了”,无法解释用户为什么超时。

真正有用的可观测性,不是把更多数据塞进仪表盘,而是把指标、日志、链路和 Kubernetes 元数据组织成能够回答问题的证据。

从资源状态转向用户请求

Kubernetes 自带的资源视角依然重要。CPU 饱和、内存不足、Pod 重启和调度失败,都可能直接造成服务异常。但如果监控止步于节点和容器,排障人员通常只能看到结果,无法定位影响路径。

可以把观测对象分成两层:

  • 基础设施层:节点压力、容器资源、Pod 生命周期、调度事件、网络与存储状态。
  • 服务层:请求率、错误率、延迟分布、队列积压、依赖调用和用户体验。

服务层应优先围绕请求建立信号。对于 HTTP 服务,可以从 RED 模型开始:

  • Rate:单位时间内处理了多少请求;
  • Errors:失败请求占比是多少;
  • Duration:请求延迟如何分布,尤其是 P95、P99;
  • Saturation:连接池、线程池、队列或下游容量是否接近上限。

平均值往往会掩盖局部问题。例如,大多数请求耗时 50 毫秒,少量请求却超过 5 秒,平均延迟仍可能看起来正常。生产告警应更多使用分位数、错误比例和持续时间,而不是只盯瞬时峰值。

让指标、日志和链路共享同一套上下文

遥测数据只有能够关联,才会产生意义。一次请求出错时,工程师需要从服务级告警进入具体 Trace,再跳到相关 Pod 的日志,并查看当时是否发生了重启、扩容或节点迁移。

建议至少保留这些低基数维度:

  • cluster:故障发生在哪个集群;
  • namespace:属于哪个环境或团队边界;
  • service:由哪个逻辑服务负责;
  • workload:对应 Deployment、StatefulSet 或 Job;
  • version:是否只影响某个发布版本;
  • regionzone:是否是区域性故障。

日志中则应包含 trace_idspan_id、请求路径、状态码和业务错误码。这样,指标负责发现异常,Trace 负责还原调用路径,日志负责解释局部执行细节,Kubernetes 事件负责补充基础设施变化。

标签不能无限增加。不要把用户 ID、订单号、完整 URL、随机请求 ID 直接放进 Prometheus 标签,否则时间序列数量会迅速膨胀。高基数字段更适合写入日志或 Trace;指标标签应保持有限、稳定且可聚合。

一套可以直接改造的排障流程

下面的脚本只依赖 kubectl;其中 kubectl top 需要集群已经安装 Metrics Server。运行前修改命名空间、工作负载和标签选择器。

#!/usr/bin/env bash
set -euo pipefail

NAMESPACE="payments"
WORKLOAD="checkout-api"
SELECTOR="app=checkout-api"

printf '\n== Deployment status ==\n'
kubectl -n "$NAMESPACE" rollout status "deployment/$WORKLOAD" --timeout=30s || true

printf '\n== Pods and placement ==\n'
kubectl -n "$NAMESPACE" get pods -l "$SELECTOR" -o wide

printf '\n== Resource usage ==\n'
kubectl -n "$NAMESPACE" top pods -l "$SELECTOR" || \
  echo "kubectl top unavailable; check Metrics Server"

printf '\n== Recent warning events ==\n'
kubectl -n "$NAMESPACE" get events \
  --field-selector type=Warning \
  --sort-by='.lastTimestamp' | tail -n 30

printf '\n== Restarts and container states ==\n'
kubectl -n "$NAMESPACE" get pods -l "$SELECTOR" \
  -o custom-columns='POD:.metadata.name,RESTARTS:.status.containerStatuses[*].restartCount,STATE:.status.containerStatuses[*].state'

printf '\n== Logs from the last 15 minutes ==\n'
kubectl -n "$NAMESPACE" logs "deployment/$WORKLOAD" \
  --all-containers=true --since=15m --prefix=true | tail -n 300

这组命令适合回答几个基础问题:异常是否与新版本同时发生,Pod 是否集中在某个节点,是否出现 OOM、探针失败或镜像拉取错误,以及应用日志中是否存在一致的失败模式。

它还不是完整的可观测性方案。Pod 已被删除时,本地容器日志可能随之消失;副本多次替换后,现场也很难重建。因此,生产环境通常需要集中式日志存储、持续采集的指标系统和跨服务 Trace。

用 SLO 语义替代“机器有点忙”

告警应描述用户影响,而不是简单报告某个资源超过阈值。下面给出一个可改造的 PrometheusRule。它假设集群使用 Prometheus Operator,并且应用暴露 http_requests_total,其中包含 namespaceservicestatus_class 标签。部署前必须按实际指标名和标签修改;release 标签也要与 Prometheus 的规则选择器匹配。

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: service-request-alerts
  namespace: monitoring
  labels:
    release: kube-prometheus-stack
spec:
  groups:
    - name: service-request-slo
      rules:
        - record: service:http_requests:rate5m
          expr: |
            sum by (namespace, service, status_class) (
              rate(http_requests_total[5m])
            )

        - alert: ServiceHighErrorRate
          expr: |
            (
              sum by (namespace, service) (
                rate(http_requests_total{status_class=~"5.."}[5m])
              )
              /
              clamp_min(
                sum by (namespace, service) (
                  rate(http_requests_total[5m])
                ),
                0.001
              )
            ) > 0.05
          for: 10m
          labels:
            severity: page
          annotations:
            summary: "{{ $labels.namespace }}/{{ $labels.service }} error rate is above 5%"
            description: "The 5xx ratio has remained above 5% for 10 minutes. Check recent releases, traces, dependency errors, pod restarts, and warning events."

保存为 service-request-alerts.yaml 后,可以这样检查并应用:

kubectl apply --dry-run=server -f service-request-alerts.yaml
kubectl apply -f service-request-alerts.yaml
kubectl -n monitoring get prometheusrule service-request-alerts

这里使用 for: 10m 是为了降低瞬时抖动造成的误报,但阈值并非通用答案。支付接口、内部批处理和低流量管理后台的容忍度完全不同。更成熟的做法是从服务的 SLO 和错误预算推导告警窗口,而不是为所有服务复制同一个 5% 阈值。

落地时优先检查这五件事

  1. 从关键请求开始:先覆盖登录、下单、支付等关键路径,不必一开始就采集所有组件的所有数据。
  2. 统一服务身份:确保指标、日志和 Trace 使用一致的 servicenamespaceversion 等字段。
  3. 控制基数和成本:限制指标标签,设置日志保留期,并按价值决定 Trace 采样率。
  4. 让告警可行动:告警消息应指出受影响服务、持续时间、可能的排查入口和对应运行手册。
  5. 验证而不是假设:通过压测、故障演练或一次受控发布,确认告警能触发、Trace 能贯通、日志能检索。

Kubernetes 可观测性的目标不是拥有最多的图表,而是在用户体验下降时,快速回答三个问题:谁受到了影响,请求在哪一段变慢或失败,以及最近发生了什么变化。只有当遥测数据能持续缩短这段推理过程,它才真正从指标变成了意义。


相关推荐