引言
在 Kubernetes 上运行微服务时,系统的复杂度和动态性会急剧上升。Pod 随时可能被重建、节点会漂移、服务依赖关系变化频繁。在这种情况下,传统的”登录机器看日志”的运维方式已经力不从心。可观测性(Observability)应运而生,它通过三大支柱——Metrics(指标)、Logging(日志)、Tracing(链路追踪),让系统的内部状态从外部可见。此外,Kubernetes 事件体系(Events)作为平台级信号源,同样不可或缺。本文系统讲解 K8s 可观测性的架构设计与实战落地。

核心概念:可观测性三支柱
Metrics(指标)
Metrics 是对系统运行状态的量化度量,通常以时间序列数据形式存储和展示。典型指标包括:
- 基础设施指标:CPU 使用率、内存占用、磁盘 I/O、网络流量
- Kubernetes 指标:Pod 重启次数、Pod 调度延迟、Node 压力
- 应用指标:请求 QPS、错误率、响应延迟、业务吞吐量
Prometheus 是 Kubernetes 生态中最流行的 Metrics 采集方案,它通过 ServiceMonitor 和 PodMonitor 自动发现集群中的目标,拉取指标数据。
Tracing(链路追踪)
分布式系统中一个用户请求往往要经过多个微服务,链路追踪(Distributed Tracing)可以还原请求的完整调用路径,定位瓶颈节点。核心概念包括:
- Trace:一次完整的请求调用链
- Span:调用链中的一个独立操作单元
- Trace Context:在跨服务调用间传递的上下文标识(TraceID + SpanID)
OpenTelemetry 是当前事实标准的追踪规范,它兼容 Jaeger、Zipkin、Tempo 等多种后端。
Events(事件体系)
Kubernetes 事件体系记录集群中发生的重要操作,如 Pod 创建失败、Node 不可达、镜像拉取超时等。事件通过 kubectl describe 命令查看,是排查问题的第一手线索。
实战一:Prometheus + Grafana 指标监控体系
1. 部署 Prometheus Operator
Prometheus Operator 提供声明式的监控配置管理,通过 CRD 定义 ServiceMonitor、PodMonitor 等资源。
# Prometheus 部署 manifest
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
name: prometheus
namespace: monitoring
labels:
app: prometheus
spec:
replicas: 3
version: v2.51.0
serviceAccountName: prometheus
podMonitorSelector:
matchLabels:
team: infra
serviceMonitorSelector:
matchLabels:
app.kubernetes.io/managed-by: prometheus-operator
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: standard
resources:
requests:
storage: 50Gi
resources:
requests:
cpu: 100m
memory: 512Mi
limits:
memory: 2Gi
retention: 15d
2. 配置 ServiceMonitor 自动发现
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: my-app-monitor
labels:
app.kubernetes.io/managed-by: prometheus-operator
spec:
selector:
matchLabels:
app: my-app
endpoints:
- port: metrics
path: /metrics
interval: 15s
scrapeTimeout: 10s
namespaceSelector:
any: true
3. 查看关键集群指标
# 查看节点 CPU 使用率
kubectl top nodes
# 查看 Pod 内存占用
kubectl top pods -n default
# 通过 Prometheus API 查询
curl -s http://prometheus.monitoring.svc:9090/api/v1/query
-G
--data-urlencode 'query=rate(container_cpu_usage_seconds_total{namespace="default"}[5m])'
| jq '.data.result[] | {pod: .metric.pod, value: .value[1]}'
4. Prometheus 告警规则示例
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: node-alerts
labels:
prometheus: prometheus
role: alert-rules
spec:
groups:
- name: node.rules
rules:
- alert: NodeMemoryPressure
expr: node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes < 0.1
for: 5m
labels:
severity: critical
annotations:
summary: "节点 {{ $labels.instance }} 内存不足"
description: "可用内存低于总内存的 10%,已持续 5 分钟"
实战二:OpenTelemetry 链路追踪
1. 部署 OpenTelemetry Operator
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
name: otel-collector
namespace: monitoring
spec:
mode: deployment
image: otel/opentelemetry-collector-contrib:0.93.0
resources:
requests:
cpu: 250m
memory: 256Mi
config:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
jaeger:
protocols:
thrift_compact:
endpoint: 0.0.0.0:6831
processors:
batch:
send_batch_size: 1000
timeout: 1s
exporters:
jaeger:
endpoint: jaeger-collector.jaeger.svc:4317
prometheus:
endpoint: 0.0.0.0:8889
service:
pipelines:
traces:
receivers: [otlp, jaeger]
processors: [batch]
exporters: [jaeger]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [prometheus]
2. 应用代码集成 OpenTelemetry SDK
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.instrumentation.requests import RequestsInstrumentor
from opentelemetry.instrumentation.flask import FlaskInstrumentor
# 初始化追踪
trace_provider = TracerProvider()
trace.set_tracer_provider(trace_provider)
trace_provider.add_span_processor(
BatchSpanProcessor(
OTLPSpanExporter(
endpoint="otel-collector.monitoring.svc:4317",
insecure=True
)
)
)
# 自动埋点
FlaskInstrumentor().instrument_app(app)
RequestsInstrumentor().instrument()
tracer = trace.get_tracer(__name__)
@app.route("/order")
def create_order():
with tracer.start_as_current_span("create_order") as span:
span.set_attribute("order.id", "12345")
# 业务逻辑
span.set_status(trace.Status(trace.StatusCode.OK))
return {"status": "created"}
3. 手动创建 Span 与上下文传播
with tracer.start_as_current_span("payment_process") as span:
span.set_attribute("payment.provider", "stripe")
span.set_attribute("payment.amount", 99.99)
try:
# 调用外部支付 API
response = requests.post("https://api.stripe.com/v1/charges",
headers={"Authorization": "Bearer sk_test_xxx"},
json={"amount": 9999, "currency": "usd"})
span.set_attribute("payment.response_code", response.status_code)
if response.status_code != 200:
raise Exception("Payment failed")
except Exception as e:
span.record_exception(e)
span.set_status(trace.Status(trace.StatusCode.ERROR))
4. 在 Grafana Tempo 中查询 Trace
# 通过 Tempo API 按 TraceID 查询
curl -s "http://tempo.monitoring.svc:3200/api/traces/<trace-id>" | jq '.trace.spans[] | {spanId: .spanID, operation: .operationName, duration: .duration}'
# 按服务名过滤 Trace
curl -s "http://tempo.monitoring.svc:3200/api/search?service=my-app&min_duration=100ms&limit=20" | jq '.traces[].traceID'
实战三:Kubernetes 事件体系与深度排查
1. 实时查看集群事件
# 查看最近 5 分钟内的集群事件
kubectl get events --all-namespaces
--field-selector involvedObject.kind=Pod
--sort-by='.lastTimestamp' | tail -20
# 实时监听新事件
kubectl get events --all-namespaces -w
2. 事件结构详解
{
"metadata": {
"name": "my-pod.1789999999999",
"namespace": "default",
"creationTimestamp": "2026-09-15T10:00:00Z"
},
"involvedObject": {
"kind": "Pod",
"namespace": "default",
"name": "my-pod",
"uid": "abc-123-def-456"
},
"reason": "BackOff",
"message": "Back-off restarting failed container",
"source": {
"component": "kubelet",
"host": "node-01"
},
"type": "Warning",
"count": 5,
"firstTimestamp": "2026-09-15T09:58:00Z",
"lastTimestamp": "2026-09-15T10:00:00Z"
}
3. 事件驱动的问题排查模式
| 事件原因 | 常见场景 | 排查方向 |
|---|---|---|
| FailedScheduling | 资源不足或亲和性不满足 | kubectl describe node 检查节点容量 |
| ImagePullBackOff | 镜像拉取失败 | 检查镜像名称、认证 Secret、网络连通性 |
| CrashLoopBackOff | 容器反复崩溃 | kubectl logs --previous 查看历史日志 |
| OOMKilled | 内存超限被杀 | 检查资源 limit 配置,优化应用内存 |
| NodeNotReady | 节点失联 | 检查节点网络、kubelet 状态、磁盘空间 |
4. 事件过期与持久化
Kubernetes 事件默认保留 1 小时。如果集群长期运行且需要审计,可通过 event-exporter 将事件持久化:
apiVersion: apps/v1
kind: Deployment
metadata:
name: event-exporter
namespace: monitoring
spec:
replicas: 1
selector:
matchLabels:
app: event-exporter
template:
metadata:
labels:
app: event-exporter
spec:
serviceAccountName: event-exporter
containers:
- name: event-exporter
image: stakater/event-exporter:v1.5.0
env:
- name: DESTINATIONS
value: "file:///var/log/events/events.jsonl"
- name: DESTINATION_URL
value: "http://influxdb.monitoring.svc:8086"
volumeMounts:
- name: event-log
mountPath: /var/log/events
volumes:
- name: event-log
emptyDir: {}
常见问题
Q1: Prometheus 采集到的 Pod 指标延迟很大,如何优化?
答:检查以下几点:
1. 调低 ServiceMonitor 的 scrape interval(如从 30s 降到 10s)
2. 检查 Prometheus 资源限制是否过高,导致 GC 压力
3. 使用 --storage.tsdb.retention.time 限制数据保留周期,减小基数
4. 启用 Prometheus 的 WAL(Write-Ahead Log)优化
Q2: 链路追踪数据丢失怎么办?
答:
1. 检查 OTel Collector 的 exporter 队列配置,增加 sending_queue 大小
2. 确认后端追踪系统(Jaeger/Tempo)没有过载
3. 启用 Collector 的内存队列和磁盘队列持久化
4. 降低采样率(sampler.probability: 0.1)控制数据量
Q3: K8s 事件被自动删除了,如何回溯?
答:
1. 使用 event-exporter 将事件实时写入外部存储(InfluxDB/Elasticsearch)
2. 使用 kube-audit-events 审计日志替代临时事件
3. 启用 Kubernetes 审计日志(audit log),记录所有 API 请求
4. 通过 etcd 直接备份事件数据(需要 etcd backup)
Q4: 如何区分 Metrics 和 Logging 的适用场景?
答:Metrics 用于聚合趋势观察(如 P99 延迟、QPS 曲线),适合做告警和仪表板;Logging 用于单次事件的详细上下文(如错误堆栈、请求参数),适合排障时定位具体问题。两者互补,不可相互替代。
总结
Kubernetes 可观测性是保障生产环境稳定性的核心能力。通过 Prometheus 采集指标实现基础设施和应用层面的实时监控;通过 OpenTelemetry 链路追踪还原分布式调用路径,快速定位性能瓶颈;通过 Kubernetes 事件体系捕获平台级异常信号。三者结合构成了完整的可观测性体系,让运维团队从”被动救火”转变为”主动感知”。建议在新项目上线前就规划好可观测性架构,而不是在故障发生时临时补建。
下期预告
第 23 天:扩展开发——CRD 与 Operator 模式,我们将深入 Kubernetes 扩展机制,学习如何通过自定义资源定义(CRD)和 Operator 模式,将运维经验编码为自动化控制器,实现”一切皆 YAML”的声明式管理范式。敬请关注!


















暂无评论内容