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 | 交互式 TUI | k9s |
| stern | 多 Pod 日志聚合 | stern --selector app=api |
| kubectl-trace | BPF 追踪 | kubectl trace run node-01 -e '...' |
| inspektor-gadget | K8s 专用 eBPF | kubectl 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 | 用途 |
|---|---|---|
| Rate | sum(rate(http_requests_total[5m])) | 请求吞吐量 |
| Errors | sum(rate(http_requests_total{status=~"5.."}[5m])) | 错误率 |
| Duration | histogram_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 团队的首选工具。
参考与延伸阅读
- Kubernetes Monitoring Guide
- kube-prometheus
- Kubernetes Best Practices — Monitoring
- inspektor-gadget
- https://plumephp.com/docker-compose-production/ — 容器化生产部署
- https://plumephp.com/network-load-balancing/ — Ingress 与负载均衡监控
- https://plumephp.com/event-driven-architecture-domain-events/ — K8s 事件驱动架构
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。