Kubernetes 可观测性实战:集群、Pod、网络、存储全链路监控

系统性 Kubernetes 可观测性实战指南:K8s 分层监控模型(集群/节点/Pod/容器/应用/API Server/etcd)、kubelet/cAdvisor/Metrics Server/Node Exporter 指标详解、Vertical Pod Autoscaler (VPA) / Horizontal Pod Autoscaler (HPA) 监控、Kubernetes Events / Audit Logs / Control Plane 日志、网络可观测性(CNI / kube-proxy / CoreDNS / Ingress)、存储可观测性(PVC/StorageClass/CSI driver metrics)、K8s 告警规则(Prometheus Rule)、Grafana K8s Dashboard 生态(社区模板/自定义)、Kubectl resource metrics / stern / k9s 排障工具链。

Kubernetes 让基础设施变得可编排,但也让故障排查变得多层次。 一个请求失败可能是因为应用代码问题、Pod 资源不足、节点磁盘压力、网络策略拦截、DNS 解析超时、Ingress 配置错误、API Server 响应慢,或者 etcd 存储满了。K8s 可观测性的目标是建立从集群到容器的全链路可视性。


一、K8s 分层监控模型

1.1 五层架构

Kubernetes 可观测性分层:

Layer 5: Application(应用层)
  ├── 应用指标(RED:Rate/Errors/Duration)
  ├── 业务指标(订单数、转化率)
  ├── APM 追踪(OpenTelemetry)
  └── 日志(结构化 JSON)

Layer 4: Container(容器层)
  ├── CPU / Memory / Disk IO / Network
  ├── 容器进程(PID 压力)
  ├── 容器重启次数
  └── OOMKilled / Evicted

Layer 3: Pod(编排层)
  ├── 副本数 vs 期望数
  ├── 就绪探针 / 存活探针状态
  ├── Pod 调度延迟
  └── 亲和性/反亲和性冲突

Layer 2: Node(节点层)
  ├── CPU / Memory / Disk / Network
  ├── 节点状态(Ready/NotReady)
  ├── 内核压力(Pressure)
  └── 节点污点/污点容忍

Layer 1: Cluster(控制平面层)
  ├── API Server 延迟/错误率
  ├── etcd 延迟/存储/领袖选举
  ├── Scheduler 调度延迟/失败数
  └── Controller Manager 性能

二、核心组件指标

2.1 kubelet 与 cAdvisor

# kubelet 指标
# Pod 启动延迟
kubelet_pod_start_duration_seconds_count

# 容器运行时操作延迟
kubelet_runtime_operations_duration_seconds{operation_type=~"create_container|pull_image"}

# PLEG(Pod Lifecycle Event Generator)延迟
kubelet_pleg_relist_duration_seconds

# cAdvisor 容器指标
# 容器 CPU 使用率
rate(container_cpu_usage_seconds_total{container!=""}[5m])

# 容器内存使用
container_memory_working_set_bytes{container!=""}

# 容器网络 IO
rate(container_network_receive_bytes_total[5m])
rate(container_network_transmit_bytes_total[5m])

# 容器文件系统使用
container_fs_usage_bytes{container!=""}

2.2 Metrics Server

# Metrics Server 提供 kubectl top 能力
kubectl top nodes
# NAME        CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
# node-01     850m         21%    8192Mi          51%
# node-02     1200m        30%    10240Mi         64%

kubectl top pods --all-namespaces
# NAMESPACE   NAME                    CPU(cores)   MEMORY(bytes)
# default     nginx-7d8c9b4f5-x2b3c   5m           128Mi
# default     api-5f4d8c9b2-a1b2c     150m         512Mi

# Metrics Server HPA 指标
# kubectl get --raw /apis/metrics.k8s.io/v1beta1/pods

2.3 Node Exporter

# 节点 CPU
100 - (avg by (instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

# 节点内存
(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) /
node_memory_MemTotal_bytes * 100

# 节点磁盘
(node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) /
node_filesystem_size_bytes{mountpoint="/"} * 100

# 节点网络
rate(node_network_receive_bytes_total{device!="lo"}[5m])
rate(node_network_transmit_bytes_total{device!="lo"}[5m])

# 节点压力
node_pressure_cpu_waiting_seconds_total
node_pressure_memory_waiting_seconds_total
node_pressure_io_waiting_seconds_total

二、五、容器与 Pod 深度排障

当 Pod 异常时,kubectl describe 输出的 Events 是最直接的诊断线索。学会解读这些事件的含义,可以大幅缩短排障时间。

常见 Pod 事件诊断

事件原因排查方向
FailedScheduling资源不足或约束不满足kubectl describe node 查看资源,kubectl get pdb 查看中断预算
CrashLoopBackOff容器反复崩溃查看容器日志,kubectl logs --previous 获取上次崩溃日志
ImagePullBackOff镜像拉取失败检查镜像名称、Registry 认证、网络连通性
OOMKilled内存超限被 kill调整 resources.limits.memory 或优化代码内存使用
Evicted节点资源压力触发驱逐检查节点磁盘/内存压力,kubectl describe node
FailedMount存储卷挂载失败PVC 状态、StorageClass、CSI 驱动日志
Unhealthy探针失败检查 livenessProbe/readinessProbe 配置和业务健康端点

排障工具链

# 实时多 Pod 日志聚合
stern --all-namespaces --selector app=api --since 5m

# 交互式终端排查
kubectl debug pod/myapp-xxx -it --image=nicolaka/netshoot -- /bin/bash

# 节点资源可视化
kubectl top node
kubectl top pod --all-namespaces --sort-by=cpu

# Pod 网络抓包(在目标 Pod 所在节点执行)
kubectl debug node/node-01 -it --image=nicolaka/netshoot -- tcpdump -i any -n port 8080

# 检查 Pod 安全上下文与权限
kubectl auth can-i --list --as=system:serviceaccount:default:default

排障心法:从外到内、从控制面到数据面。先看 kubectl get events --sort-by='.lastTimestamp',再进 Pod 看日志,最后才是抓包和代码级调试。

三、K8s 核心告警规则

# kubernetes-alerts.yml
groups:
  - name: kubernetes-critical
    rules:
      # Pod 频繁重启
      - alert: PodCrashLooping
        expr: rate(kube_pod_container_status_restarts_total[10m]) > 0
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Pod {{ $labels.pod }} is crash looping"

      # Pod 未就绪
      - alert: PodNotReady
        expr: |
          kube_pod_status_phase{phase=~"Pending|Unknown|Failed"} == 1
        for: 15m
        labels:
          severity: warning

      # Pod OOMKilled
      - alert: PodOOMKilled
        expr: |
          kube_pod_container_status_last_terminated_reason{reason="OOMKilled"} == 1
        labels:
          severity: warning

      # 节点 NotReady
      - alert: NodeNotReady
        expr: kube_node_status_condition{condition="Ready",status="false"} == 1
        for: 5m
        labels:
          severity: critical

      # 节点磁盘压力
      - alert: NodeDiskPressure
        expr: kube_node_status_condition{condition="DiskPressure",status="true"} == 1
        for: 2m
        labels:
          severity: warning

      # 节点内存压力
      - alert: NodeMemoryPressure
        expr: kube_node_status_condition{condition="MemoryPressure",status="true"} == 1
        for: 2m
        labels:
          severity: warning

      # Job 失败
      - alert: JobFailed
        expr: kube_job_status_failed{job_name=~".*"} > 0
        for: 0m
        labels:
          severity: warning

      # HPA 达到最大副本
      - alert: HPAMaxReplicas
        expr: |
          kube_horizontalpodautoscaler_status_current_replicas
          ==
          kube_horizontalpodautoscaler_spec_max_replicas
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "HPA {{ $labels.horizontalpodautoscaler }} at max replicas"

  - name: kubernetes-control-plane
    rules:
      # API Server 延迟
      - alert: APIServerHighLatency
        expr: |
          histogram_quantile(0.99,
            sum(rate(apiserver_request_duration_seconds_bucket[5m])) by (le)
          ) > 1
        for: 5m
        labels:
          severity: warning

      # etcd 领袖选举频繁
      - alert: EtcdFrequentLeaderChanges
        expr: |
          rate(etcd_server_leader_changes_seen_total[1h]) > 0
        for: 5m
        labels:
          severity: critical

      # etcd DB 大小
      - alert: EtcdDatabaseHigh
        expr: etcd_mvcc_db_total_size_in_bytes / etcd_server_quota_backend_bytes > 0.8
        for: 5m
        labels:
          severity: warning

      # Scheduler 调度失败
      - alert: SchedulerFailures
        expr: rate(scheduler_schedule_attempts_total{result="unschedulable"}[5m]) > 0
        for: 10m
        labels:
          severity: warning

四、K8s Events 与 Audit Logs

4.1 Events 监控

# 查看 Pod 事件
kubectl describe pod <pod-name>

# 查看所有 Warning 事件
kubectl get events --field-selector type=Warning --sort-by='.lastTimestamp'

# 按原因筛选
kubectl get events --field-selector reason=FailedScheduling

# 用 stern 实时查看日志
stern --all-namespaces --selector app=api

4.2 Audit Logs

# audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  - level: Metadata
    resources:
      - group: ""
        resources: ["pods"]

  - level: RequestResponse
    resources:
      - group: "rbac.authorization.k8s.io"
        resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"]

  - level: Request
    omitStages:
      - RequestReceived
    nonResourceURLs:
      - /healthz*
      - /version
    users:
      - system:kube-proxy
    verbs: ["get"]
# API Server 启用审计日志
kube-apiserver \
  --audit-policy-file=/etc/kubernetes/audit-policy.yaml \
  --audit-log-path=/var/log/audit.log \
  --audit-log-maxsize=100 \
  --audit-log-maxbackup=10

五、网络可观测性

5.1 CNI 监控

# Calico 指标(如启用 Felix 指标)
# 网络策略命中
felix_active_local_endpoints

# Cilium 指标
cilium_endpoint_count
cilium_drop_total{reason="Policy denied"}

# Flannel 指标
flannel_subnets

5.2 CoreDNS

# DNS 查询速率
coredns_dns_requests_total

# DNS 查询延迟
coredns_dns_request_duration_seconds_bucket

# DNS 查询失败
coredns_dns_responses_total{rcode="NXDOMAIN"}
coredns_dns_responses_total{rcode="SERVFAIL"}

# 缓存命中率
coredns_cache_hits_total
coredns_cache_misses_total

5.3 Ingress

# Nginx Ingress Controller
nginx_ingress_controller_requests
nginx_ingress_controller_nginx_process_requests

# 请求延迟
histogram_quantile(0.99,
  sum by (le, ingress) (rate(nginx_ingress_controller_request_duration_seconds_bucket[5m]))
)

# 5xx 错误
nginx_ingress_controller_requests{status=~"5.."}

六、存储可观测性

6.1 PVC 监控

# PVC 使用率
(
  kubelet_volume_stats_used_bytes
  /
  kubelet_volume_stats_capacity_bytes
) * 100

# PVC 接近满
kubelet_volume_stats_available_bytes / kubelet_volume_stats_capacity_bytes < 0.1

# StorageClass 配额
kube_persistentvolumeclaim_resource_requests_storage_bytes

6.2 CSI Driver 指标

# CSI Driver 暴露了标准的 gRPC 指标
# 需要 CSI 驱动支持

# 示例:创建 PVC 延迟
csi_sidecar_operations_seconds_bucket{driver="csi-driver-name", method_name="CreateVolume"}

七、排障工具链

工具用途命令
kubectl基础查询kubectl get/describe/logs/top
k9s交互式 TUIk9s
stern多 Pod 日志聚合stern --selector app=api
kubectl-traceBPF 追踪kubectl trace run node-01 -e '...'
inspektor-gadgetK8s 专用 eBPFkubectl gadget trace tcp
kubectl-debug调试容器kubectl debug pod-xxx --image=busybox
kor清理孤儿资源kor all

八、OpenTelemetry 与 APM 链路追踪

现代微服务架构中,单个请求可能跨越数十个 Pod 和服务。没有分布式追踪,定位性能瓶颈如同大海捞针。

OpenTelemetry 在 K8s 中的部署架构

App Pod ──► OTel SDK ──► OTel Collector (DaemonSet/Deployment)
                               │
                    ┌──────────┼──────────┐
                    ▼          ▼          ▼
               Prometheus   Jaeger/Tempo   Loki
                  (指标)      (追踪)      (日志)
# OpenTelemetry Collector 配置
# otel-collector-config.yaml
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  batch:
    timeout: 1s
    send_batch_size: 1024
  resource:
    attributes:
      - key: k8s.cluster.name
        value: production
        action: upsert

exporters:
  prometheusremotewrite:
    endpoint: http://prometheus:9090/api/v1/write
  otlp/jaeger:
    endpoint: jaeger-collector:4317
    tls:
      insecure: true

service:
  pipelines:
    metrics:
      receivers: [otlp]
      processors: [batch, resource]
      exporters: [prometheusremotewrite]
    traces:
      receivers: [otlp]
      processors: [batch, resource]
      exporters: [otlp/jaeger]

自动注入(Instrumentation)

# 使用 OpenTelemetry Operator 自动注入 Agent
kubectl apply -f - <<EOF
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
  name: auto-instrumentation
spec:
  exporter:
    endpoint: http://otel-collector:4317
  propagators:
    - tracecontext
    - baggage
  sampler:
    type: parentbased_traceidratio
    argument: "0.1"  # 10% 采样率
EOF

# 在 Pod 上添加注解自动注入
kubectl annotate deployment myapp instrumentation.opentelemetry.io/inject-java="true"

RED 方法仪表盘

指标PromQL用途
Ratesum(rate(http_requests_total[5m]))请求吞吐量
Errorssum(rate(http_requests_total{status=~"5.."}[5m]))错误率
Durationhistogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))P95 延迟

追踪采样策略:生产环境建议 1-10% 采样,重点接口(如支付、登录)100% 采样。Tempo 等后端支持"尾部采样"(Tail-based Sampling),在请求完成后根据延迟或错误状态决定是否保留,兼顾成本和完整性。

九、成本可观测性:FinOps 与资源优化

K8s 集群的成本管理往往被忽视,直到云账单暴涨。通过可观测性数据驱动资源优化是 FinOps 的核心实践。

资源浪费识别

# CPU 申请 vs 实际使用(申请过大)
(
  sum(kube_pod_container_resource_requests{resource="cpu"}) 
  - 
  sum(rate(container_cpu_usage_seconds_total[5m]))
) / sum(kube_pod_container_resource_requests{resource="cpu"})

# 内存申请 vs 实际使用
(
  sum(kube_pod_container_resource_requests{resource="memory"})
  -
  sum(container_memory_working_set_bytes)
) / sum(kube_pod_container_resource_requests{resource="memory"})

# 长期低利用率 Pod(7 天平均 CPU < 10% 的申请量)
avg_over_time(
  rate(container_cpu_usage_seconds_total[5m])[7d:]
) / kube_pod_container_resource_requests{resource="cpu"} < 0.1

优化策略矩阵

场景策略效果
CPU 申请 > 实际 3 倍调低 request,使用 VPA 自动建议节省 30-50%
内存申请 > 实际 2 倍调低 limit,开启 VPA节省 20-40%
夜间无流量服务HPA 缩至 0,或 CronJob 启停节省 60%+
开发测试环境Spot/Preemptible 实例节省 70%+

工具推荐:Kubecost / OpenCost 提供命名空间/Deployment 级别的成本分摊,是 FinOps 团队的首选工具。

参考与延伸阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「infra」更多文章

  1. 可观测性数据存储选型:TSDB、列式存储、对象存储与成本优化
  2. 云原生 APM 与性能剖析:Continuous Profiling 与火焰图
  3. eBPF 可观测性:内核可编程追踪与性能剖析