【架构实战】Kubernetes故障排查全景图:从Pod异常到集群雪崩的诊断手册
2026/8/14 11:52:10 网站建设 项目流程

【架构实战】Kubernetes故障排查全景图:从Pod异常到集群雪崩的诊断手册

Kubernetes出问题的时候,往往不是单个症状。Pod起不来可能只是冰山一角,底下可能是资源耗尽、网络分区、etcd抖动、OOMKiller连环杀节点……这一篇把故障排查的思维框架和实操命令整理成册,遇到问题照着走,少踩坑。

一、故障排查的正确姿势:分层定位

遇到K8s故障,很多人第一反应是kubectl get pods——然后对着CrashLoopBackOff发呆。正确思路是从下往上逐层定位,先确认基础设施正常,再看编排层,最后看应用层:

第一层:节点层(Node) ↓ 节点是否Ready?资源是否耗尽? 第二层:网络层(Network) ↓ DNS解析正常吗?Pod间能互通吗? 第三层:控制平面层(Control Plane) ↓ API Server响应吗?etcd健康吗?Controller正常吗? 第四层:调度层(Scheduling) ↓ Pod卡在Pending?调度失败原因是什么? 第五层:运行时层(Runtime) ↓ 容器启动了吗?健康检查过了吗? 第六层:应用层(Application) ↓ 进程正常运行吗?配置对吗?

每层都有对应的检查命令,定位清楚了再动手,别上来就删Pod重启。

二、节点层:先确认机器还活着

节点是所有Pod的宿主机,节点出问题上层必遭殃。

2.1 节点状态速查

# 快速看所有节点状态kubectl get nodes-owide# 看节点详情(含事件、污点、条件)kubectl describenode<node-name># 看节点资源使用(需Metrics Server)kubectltopnodes

正常节点应该满足:Ready=True,没有MemoryPressureDiskPressurePIDPressureNetworkUnavailable

2.2 常见节点异常

症状可能原因排查命令
NotReadykubelet停了/网络问题/etcd失联systemctl status kubelet
MemoryPressure内存不足,OOMKiller正在杀进程dmesg | grep -i "killed process"
DiskPressure磁盘空间不足df -h/docker system df
PIDPressure进程数超限ps aux | wc -l

2.3 OOMKiller连环杀人事件

最恶心的场景:节点内存紧张 → 内核OOMKiller杀Pod → Pod重启 → 内存继续紧张 → 继续杀。循环往复。

排查步骤:

# 看dmesg里的OOM日志(实时)dmesg-w|grep-i"oom"# 看哪个容器被杀了dmesg|grep-i"killed process"|tail-20# 看节点内存分配free-hkubectltopnodes --sort-by=memory

根因解决

  • Pod设合理的resources.limits.memory,防止贪婪容器耗尽节点;
  • 节点加内存或扩容;
  • 调低Pod的OOMScoreAdj让不重要的先被杀:kubectl annotate pod <pod> scheduler.alpha.kubernetes.io/oom-score-adj=-999

2.4 节点网络排查

# 看节点能通API Server吗curl-khttps://<API-SERVER>:6443/healthz# 看节点的Pod子网是否正确路由iproute show# 看kube-proxy是否正常(iptables规则)iptables-L-n-tnat|grepKUBE-SERVICES|wc-l

三、控制平面层:API Server还活着吗

API Server是整个集群的大脑。它一倒,所有kubectl命令都废了。

3.1 控制平面健康检查

# 最直接的健康检查(所有组件)kubectl get--raw='/healthz?verbose'# 分开检查各组件kubectl get--raw='/healthz/apiserver'# API Serverkubectl get--raw='/healthz/etcd-0'# etcd(如果直连)kubectl get--raw='/healthz/scheduler'# Schedulerkubectl get--raw='/healthz/controller-manager'# Controller Manager

3.2 etcd是根本

etcd存着整个集群的状态,etcd挂了API Server也活不了。

# etcd健康检查(需要etcdctl)ETCDCTL_API=3etcdctl\--endpoints=https://127.0.0.1:2379\--cert=/etc/kubernetes/pki/etcd/server.crt\--key=/etc/kubernetes/pki/etcd/server.key\--cacert=/etc/kubernetes/pki/etcd/ca.crt\endpoint health# 看etcd日志是否有写入延迟或leader切换journalctl-uetcd-n100--no-pager

常见etc d问题

  • 磁盘慢:etcd对磁盘IO极为敏感,强烈建议用SSD。iostat -x 1看磁盘utilization;
  • Leader频繁切换:网络抖动或节点负载过高导致。查网络延迟和节点负载;
  • 空间不足:etcd DB超过默认8GB限制。清理或扩磁盘,紧急时做defrag。

3.3 Controller Manager和Scheduler

这两个组件跑在Pod里(static pod或Deployment),如果它们不工作:

  • Scheduler挂了:新Pod全部卡在Pending,集群停止调度新工作;
  • Controller Manager挂了:Deployment/ReplicaSet不再维护期望副本数,Service不更新Endpoints。
# 看kube-controller-manager日志kubectl logs-nkube-system kube-controller-manager-<node-name>--tail=100# 看scheduler日志kubectl logs-nkube-system kube-scheduler-<node-name>--tail=100# 确认leader是谁(多实例HA时)kubectl get endpoints kube-controller-manager-nkube-system-oyaml kubectl get endpoints kube-scheduler-nkube-system-oyaml

四、调度层:Pod为什么卡在Pending

Pod一直是Pending,说明调度失败。常见原因:

4.1 资源不足

# 看看哪些资源紧张kubectl describenode|grep-A5"Allocated resources"# 看节点可分配资源kubectltopnodes# 看具体Pod的资源请求kubectl get pod<pod-name>-ojsonpath='{.spec.containers[*].resources}'

解决思路:扩容节点、减少Pod资源请求、或用Pod优先级/抢占(PriorityClass)。

4.2 亲和性/反亲和性冲突

# 看Pod的调度决策详情kubectl describe pod<pod-name>|grep-A20"Events:"# 典型输出# 0/3 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, 2 Insufficient memory.

亲和性/反亲和性规则太严格时,很容易无节点满足。检查:

kubectl get pod<pod-name>-ojsonpath='{.spec.affinity}'|jq.

4.3 PVC绑定超时

有StatefulSet挂载PVC时,PVC如果因为存储类问题无法绑定,Pod也会卡住:

kubectl get pvc# 看哪些PVC是Pendingkubectl describe pvc<pvc-name>

五、运行时层:容器启动失败

Pod不再是Pending,但容器有问题。

5.1 容器状态速查

# 按状态筛选kubectl get pods --all-namespaces --field-selector=status.phase=Failed kubectl get pods --all-namespaces --field-selector=status.phase=CrashLoopBackOff# 看容器详情kubectl describe pod<pod-name>kubectl logs<pod-name>--previous# 上一次崩溃的日志

5.2 CrashLoopBackOff详解

这个状态是"容器启动→退出→重试→再退"的循环。原因是Exit Code非0。

常见原因排查路径:

1. 应用启动命令/参数错误

# 看镜像启动命令kubectl get pod<pod-name>-ojsonpath='{.spec.containers[0].command}'# 在本地测试镜像dockerrun--rm<image><command-from-above>

2. 依赖服务不可达
应用启动需要连数据库/Redis/配置中心,但依赖还没Ready。解决方案:用initContainer做健康检查或用depends-on语义(通过AdmissionWebhook实现)。

3. 配置文件缺失或权限问题

# 看容器文件系统kubectlexec-it<pod-name>--ls-la/app/# 看环境变量kubectlexec-it<pod-name>--env|sort

4. 健康检查失败导致OOM
Liveness探针连续失败3次会重启容器。如果应用启动慢,initialDelaySeconds设小了就会误杀:

livenessProbe:initialDelaySeconds:60# 给够启动时间periodSeconds:10failureThreshold:3

5.3 ImagePullBackOff:拉不到镜像

# 看拉取错误详情kubectl describe pod<pod-name>|grep-A10"Events:"# 常见原因:# 1. 镜像名拼写错误# 2. 私有镜像仓库未配置imagePullSecrets# 3. 仓库认证过期(docker login过期)# 4. 节点没有该仓库的访问权限

解决:检查imagePullSecrets有效性,确认节点能访问镜像仓库(docker pull <image>在节点上跑一次)。

5.4 OOMKilled

容器内存超限被杀,不一定是节点内存不足,也可能是Pod的resources.limits.memory设小了:

kubectl get pod<pod-name>-ojsonpath='{.status.containerStatuses[0].lastState.terminated.exitCode}'# 如果是137,说明被SIGKILL(OOM)

排查:看容器启动时的内存峰值,kubectl top pod结合Prometheus看内存曲线,适当调高limit。

六、网络层:服务之间通不了

网络问题最复杂,但有章可循。

6.1 DNS是万恶之源

Pod间通信失败,80%是DNS问题。先查:

# 进入问题Podkubectlexec-it<pod-name>--sh# 在Pod内测试DNSnslookupkubernetes.defaultnslookup<service-name>.<namespace>.svc.cluster.localcat/etc/resolv.conf# 看ndots配置# 测试网络连通性curl-vtelnet://<service-name>:<port>

常见DNS坑

  • ndots太多:Pod里/etc/resolv.confndots默认是5,意味着任何少于5个点的域名都会被追加搜索域,导致内部服务解析变成外部查询。解决方案:Pod启动时加- DNSDOT=1或直接用全限定域名。
  • CoreDNS不健康:看CoreDNS日志和Pod状态:
kubectl logs-nkube-system-lk8s-app=kube-dns--tail=50kubectl get pods-nkube-system-lk8s-app=kube-dns

6.2 Service连接失败

# 看Endpoints是否有人kubectl get endpoints<service-name>-n<namespace># 如果Endpoints为空,说明selector匹配的Pod有问题(标签不对/全部宕机)# 看Service配置kubectl get svc<service-name>-n<namespace>-oyaml

典型问题:改Deployment的Pod标签忘了更新Service的selector,导致流量找不到后端。

6.3 NetworkPolicy误伤

配了NetworkPolicy但只开放了部分流量,默认是"全部拒绝"。确认策略是否覆盖了所有必要的流量:

kubectl get networkpolicy-Akubectl describe networkpolicy<name>-n<namespace>

七、集群雪崩:连锁故障怎么破

最危险的场景:单个服务故障 → 请求堆积 → 资源耗尽 → 大量Pod重启 → 更大规模故障。

7.1 雪崩的触发链条

常见触发路径:

  1. 超时设置缺失:A服务调用B服务无超时,B慢→A线程池耗尽→A不可用→调用A的服务也崩;
  2. 重试风暴:没有退避策略的重试,一倒全倒;
  3. 健康检查不完善:不健康的服务未被及时摘除,持续接收请求;
  4. 资源无隔离:所有Pod跑在同一节点,资源竞争互相影响。

7.2 快速止血

第一步:切断入口流量

# 紧急下线Service(改副本数为0)kubectl scale deployment<svc-name>--replicas=0-n<namespace># 或者加NoSchedule污点强制摘除kubectl cordon<node-name># 或者删掉有问题的Pod让它不再重建kubectl delete pod<pod-name>--grace-period=0--force

第二步:限流保护上游

# Istio/Envoy限流示例apiVersion:networking.istio.io/v1alpha3kind:DestinationRulemetadata:name:myappspec:host:myapptrafficPolicy:connectionPool:tcp:maxConnections:100http:h2UpgradePolicy:UPGRADEhttp1MaxPendingRequests:100maxRequestsPerConnection:100

第三步:加超时+重试退避

# Hystrix/Resilience4j超时配置示例@HystrixCommand( commandProperties ={@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000"),@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "20"),@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "5000")}) public String callService(){...}

7.3 根治方案

  • 服务网格:用Istio/Linkerd做流量管理,熔断、重试超时、限流全在Sidecar处理,应用零改动;
  • HPA自动扩缩容:根据CPU/内存自动扩容,防止单点过载;
  • PodDisruptionBudget:保证故障时仍有最少数量的Pod存活;
  • 资源LimitRange:在namespace级别设默认limit,防止贪婪Pod吃光资源。

八、故障排查黄金命令速查

场景命令
看所有Pod状态kubectl get pods -A -o wide
看Pod事件kubectl describe pod <name> -n <ns>
看容器日志kubectl logs <name> -n <ns> --tail=200 -f
看上一次崩溃日志kubectl logs <name> -n <ns> --previous
看节点资源kubectl top nodes
看Pod资源kubectl top pods -A
看Endpointskubectl get endpoints -A
看所有事件kubectl get events -A --sort-by='.lastTimestamp'
看Service关联的Podkubectl get endpoints <svc> -n <ns>
快速进入Podkubectl debug <pod> -it --image=busybox -- sh
看CoreDNS状态kubectl get pods -n kube-system -l k8s-app=kube-dns

九、小结

K8s故障排查的核心是分层定位

  1. 节点层:先确认机器还活着,资源没耗尽;
  2. 控制平面层:API Server和etcd是根本,它们健康才有后面的一切;
  3. 调度层:Pending的Pod重点看资源和亲和性;
  4. 运行时层:容器退出看Exit Code,拉不到镜像查认证;
  5. 网络层:80%的网络问题查DNS,服务不通先查Endpoints;
  6. 应用层:超时、重试、依赖是连锁故障的三大元凶。

记住:kubectl describekubectl get更有价值,事件(Events)才是真相。多看日志,少删Pod重启,大多数问题在事件和日志里已经有答案了。


下篇预告:Kubernetes存储实战——从EmptyDir到Ceph CSI的持久化存储选型指南。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询