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:是否只影响某个发布版本;region或zone:是否是区域性故障。
日志中则应包含 trace_id、span_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,其中包含 namespace、service 和 status_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% 阈值。
落地时优先检查这五件事
- 从关键请求开始:先覆盖登录、下单、支付等关键路径,不必一开始就采集所有组件的所有数据。
- 统一服务身份:确保指标、日志和 Trace 使用一致的
service、namespace、version等字段。 - 控制基数和成本:限制指标标签,设置日志保留期,并按价值决定 Trace 采样率。
- 让告警可行动:告警消息应指出受影响服务、持续时间、可能的排查入口和对应运行手册。
- 验证而不是假设:通过压测、故障演练或一次受控发布,确认告警能触发、Trace 能贯通、日志能检索。
Kubernetes 可观测性的目标不是拥有最多的图表,而是在用户体验下降时,快速回答三个问题:谁受到了影响,请求在哪一段变慢或失败,以及最近发生了什么变化。只有当遥测数据能持续缩短这段推理过程,它才真正从指标变成了意义。