K8s 运维系列 | 第 22 天:可观测性——Metrics、Tracing 与事件体系

引言

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

K8s 运维 第22天

核心概念:可观测性三支柱

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”的声明式管理范式。敬请关注!

微信二维码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容