Kubernetes 生产环境排障实录:典型故障案例与诊断方法论

张开发
2026/6/7 20:40:50 15 分钟阅读

分享文章

Kubernetes 生产环境排障实录:典型故障案例与诊断方法论
Kubernetes 生产环境排障实录典型故障案例与诊断方法论一、引言痛点K8s 故障为何难以定位Kubernetes 已成为云原生时代的事实标准但它的复杂性也带来了独特的故障排查挑战。一个请求失败可能涉及网络、存储、计算、调度等多个层面而 K8s 的分层抽象和组件众多使得问题定位变得困难。相比传统运维K8s 故障排查需要掌握更多的工具和方法。在 K8s 中故障可能发生在 Pod 层面、Service 层面、Ingress 层面、NetworkPolicy 层面甚至是云厂商的负载均衡器层面。本文将系统复盘 K8s 生产环境的典型故障案例从 Pod 启动失败、Service 无法访问、到网络分区故障提供完整的诊断思路和解决路径。二、K8s 故障诊断框架2.1 故障定位决策树flowchart TD A[请求失败] -- B{Pod 是否 Running?} B --|否| C[Pod 启动失败] B --|是| D{Pod 是否在 Endpoint 中?} D --|否| E[Selector 不匹配] D --|是| F{网络连通性?} F --|否| G[网络策略/防火墙] F --|是| H{应用正常?} H --|否| I[应用日志分析] H --|是| J[上游服务故障] C -- C1{kubectl describe} C1 -- C2[事件信息] C2 -- C3{ExitCode?} C3 --|非零| C4[应用错误] C3 --|137| C5[OOMKilled] C3 --|128| C6[镜像拉取失败] style C5 fill:#ffcdd2 style C4 fill:#ffecb32.2 核心诊断命令速查# 1. Pod 状态检查 kubectl get pods -n namespace -o wide kubectl describe pod pod-name -n namespace kubectl logs pod-name -n namespace --previous # 上一个容器的日志 # 2. Service 连通性检查 kubectl get endpoints service-name -n namespace kubectl get svc service-name -n namespace kubectl get networkpolicies -n namespace # 3. 节点状态检查 kubectl get nodes -o wide kubectl describe node node-name kubectl top node node-name # 需要 metrics-server # 4. 事件总览 kubectl get events -n namespace --sort-by.lastTimestamp # 5. 资源配额检查 kubectl describe resourcequota -n namespace kubectl describe limitrange -n namespace三、典型故障案例复盘3.1 案例一Pod OOMKilled# 故障现象 # Pod 状态为 Running但立即被终止RestartCount 持续增加 # 诊断步骤 $ kubectl get pod memory-intensive-app -n production NAME READY STATUS RESTARTS AGE memory-intensive-app 0/1 OOMKilled 5 10m $ kubectl describe pod memory-intensive-app -n production ... Last State: Terminated Reason: OOMKilled Exit Code: 137 Started: Mon, 01 Jan 2024 10:00:00 0000 Finished: Mon, 01 Jan 2024 10:00:30 0000 # 检查资源限制配置 $ kubectl get pod memory-intensive-app -n production -o jsonpath{.spec.containers[0].resources} {limits:{memory:256Mi},requests:{memory:128Mi}} # 解决方案 # 1. 确认应用真实内存需求 # 2. 调整 limits.memory 到合理值 # 3. 优化应用内存使用# 修复后的资源配置 apiVersion: v1 kind: Pod metadata: name: memory-intensive-app namespace: production spec: containers: - name: app image: memory-intensive:latest resources: requests: memory: 512Mi # 调整 requests limits: memory: 1Gi # 设置合理的 limits # 建议 limits 不要超过 node 可用内存的 80%3.2 案例二Service 无法访问# 故障现象 # 从 Pod 内访问 Service 失败但 Service 存在 # 诊断步骤 $ kubectl get svc -n production NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) my-service ClusterIP 10.96.0.100 none 8080/TCP # 检查 Endpoints关键 $ kubectl get endpoints my-service -n production NAME ENDPOINTS AGE my-service 10.244.1.15:8080,10.244.2.20:8080 1d # 如果 ENDPOINTS 为空说明 selector 没有匹配到任何 Pod # 检查 Pod 的 labels $ kubectl get pods -n production --show-labels | grep my-app my-app-pod-1 1/1 Running ... appmy-app,versionv1 my-app-pod-2 1/1 Running ... appmy-app,versionv1 # 检查 Service 的 selector $ kubectl get svc my-service -n production -o jsonpath{.spec.selector} {app:my-app} # 发现问题Pod labels 是 appmy-app但版本 label 不一致 # 进一步测试 DNS 解析 $ kubectl run dnsutils -n production --imagetutum/dnsutils -- sleep 3600 $ kubectl exec -it dnsutils -n production -- nslookup my-service.production.svc.cluster.local # 解决方案修复 selector 或 Pod labels 使其匹配3.3 案例三镜像拉取失败# 故障现象 # Pod 一直处于 ContainerCreating 状态 $ kubectl describe pod my-app -n production ... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning Failed 2m kubelet Failed to pull image registry.example.com/my-app:v2: Error response from daemon: pull access denied, repository does not exist or may require authorization: denied: requested access to the resource is denied # 诊断步骤 # 1. 检查镜像地址是否正确 # 2. 检查 ImagePullSecret 是否配置 # 3. 检查 SA 的 imagePullSecrets $ kubectl get pod my-app -n production -o jsonpath{.spec.imagePullSecrets} [{name:regcred}] $ kubectl get secret regcred -n production --outputjsonpath{.data.\.dockerconfigjson} | base64 -d # 解决方案 # 1. 确认 Secret 中的凭证有效 # 2. 创建新的 Secret kubectl create secret docker-registry regcred \ --docker-serverregistry.example.com \ --docker-usernameuser \ --docker-passwordpassword \ --namespaceproduction # 3. 关联到 ServiceAccount kubectl patch serviceaccount default -n production \ -p {imagePullSecrets:[{name:regcred}]}3.4 案例四网络策略导致的通信中断# 故障现象 # 服务间通信突然中断但 Pod 和 Service 都正常 # 诊断步骤 $ kubectl get networkpolicies -n production NAME POD-SELECTOR AGE deny-all none 30d allow-frontend appfrontend 30d # 检查 deny-all 策略 $ kubectl get networkpolicy deny-all -n production -o yaml # 发现问题deny-all 策略阻止了所有流量但没有相应的 allow 规则允许后端通信 # 解决方案添加允许规则 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-backend namespace: production spec: podSelector: matchLabels: app: backend policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: frontend ports: - protocol: TCP port: 8080四、生产级监控与预警4.1 关键监控指标# Prometheus 告警规则 apiVersion: monitoring.coreos.com/v1 kind: PrometheusRule metadata: name: k8s-critical-alerts namespace: monitoring spec: groups: - name: k8s.pod.status rules: - alert: PodNotReady expr: | kube_pod_status_phase{phase~Pending|Unknown} 0 for: 5m labels: severity: critical annotations: summary: Pod 处于非就绪状态超过 5 分钟 - alert: PodRestartingTooMuch expr: | rate(kube_pod_container_status_restarts_total[15m]) 0.1 for: 5m labels: severity: warning annotations: summary: Pod 重启过于频繁 - alert: PodOOMKilled expr: | kube_pod_container_status_last_terminated_reason{reasonOOMKilled} 0 for: 0m labels: severity: warning annotations: summary: Pod 因 OOM 被终止4.2 日志聚合架构flowchart TD A[应用日志] -- B[Fluent Bit] B -- C[Fluentd] C -- D[Elasticsearch] D -- E[Kibana] F[集群事件] -- G[EventRouter] G -- C五、总结K8s 故障排查的核心是系统化的诊断方法。核心要点可以归纳为三点第一从症状到根因的逐步验证。使用决策树结构化诊断流程从 Pod 状态到网络连通性逐层排查。第二善用 K8s 内建工具。kubectl describe、kubectl logs、kubectl events 是诊断的基础。第三预防优于排查。完善的监控预警和日志聚合可以让故障在发生初期就被发现。K8s 的复杂性是双刃剑它提供了强大的编排能力但也需要运维团队具备相应的诊断能力。

更多文章