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

📅 2026/8/14 11:52:18
【架构实战】Kubernetes故障排查全景图:从Pod异常到集群雪崩的诊断手册
【架构实战】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 describenodenode-name# 看节点资源使用需Metrics Serverkubectltopnodes正常节点应该满足ReadyTrue没有MemoryPressure、DiskPressure、PIDPressure、NetworkUnavailable。2.2 常见节点异常症状可能原因排查命令NotReadykubelet停了/网络问题/etcd失联systemctl status kubeletMemoryPressure内存不足OOMKiller正在杀进程dmesg | grep -i killed processDiskPressure磁盘空间不足df -h/docker system dfPIDPressure进程数超限ps aux | wc -l2.3 OOMKiller连环杀人事件最恶心的场景节点内存紧张 → 内核OOMKiller杀Pod → Pod重启 → 内存继续紧张 → 继续杀。循环往复。排查步骤# 看dmesg里的OOM日志实时dmesg-w|grep-ioom# 看哪个容器被杀了dmesg|grep-ikilled process|tail-20# 看节点内存分配free-hkubectltopnodes --sort-bymemory根因解决Pod设合理的resources.limits.memory防止贪婪容器耗尽节点节点加内存或扩容调低Pod的OOMScoreAdj让不重要的先被杀kubectl annotate pod pod scheduler.alpha.kubernetes.io/oom-score-adj-9992.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 Manager3.2 etcd是根本etcd存着整个集群的状态etcd挂了API Server也活不了。# etcd健康检查需要etcdctlETCDCTL_API3etcdctl\--endpointshttps://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看磁盘utilizationLeader频繁切换网络抖动或节点负载过高导致。查网络延迟和节点负载空间不足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--tail100# 看scheduler日志kubectl logs-nkube-system kube-scheduler-node-name--tail100# 确认leader是谁多实例HA时kubectl get endpoints kube-controller-manager-nkube-system-oyaml kubectl get endpoints kube-scheduler-nkube-system-oyaml四、调度层Pod为什么卡在PendingPod一直是Pending说明调度失败。常见原因4.1 资源不足# 看看哪些资源紧张kubectl describenode|grep-A5Allocated resources# 看节点可分配资源kubectltopnodes# 看具体Pod的资源请求kubectl get podpod-name-ojsonpath{.spec.containers[*].resources}解决思路扩容节点、减少Pod资源请求、或用Pod优先级/抢占PriorityClass。4.2 亲和性/反亲和性冲突# 看Pod的调度决策详情kubectl describe podpod-name|grep-A20Events:# 典型输出# 0/3 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, 2 Insufficient memory.亲和性/反亲和性规则太严格时很容易无节点满足。检查kubectl get podpod-name-ojsonpath{.spec.affinity}|jq.4.3 PVC绑定超时有StatefulSet挂载PVC时PVC如果因为存储类问题无法绑定Pod也会卡住kubectl get pvc# 看哪些PVC是Pendingkubectl describe pvcpvc-name五、运行时层容器启动失败Pod不再是Pending但容器有问题。5.1 容器状态速查# 按状态筛选kubectl get pods --all-namespaces --field-selectorstatus.phaseFailed kubectl get pods --all-namespaces --field-selectorstatus.phaseCrashLoopBackOff# 看容器详情kubectl describe podpod-namekubectl logspod-name--previous# 上一次崩溃的日志5.2 CrashLoopBackOff详解这个状态是容器启动→退出→重试→再退的循环。原因是Exit Code非0。常见原因排查路径1. 应用启动命令/参数错误# 看镜像启动命令kubectl get podpod-name-ojsonpath{.spec.containers[0].command}# 在本地测试镜像dockerrun--rmimagecommand-from-above2. 依赖服务不可达应用启动需要连数据库/Redis/配置中心但依赖还没Ready。解决方案用initContainer做健康检查或用depends-on语义通过AdmissionWebhook实现。3. 配置文件缺失或权限问题# 看容器文件系统kubectlexec-itpod-name--ls-la/app/# 看环境变量kubectlexec-itpod-name--env|sort4. 健康检查失败导致OOMLiveness探针连续失败3次会重启容器。如果应用启动慢initialDelaySeconds设小了就会误杀livenessProbe:initialDelaySeconds:60# 给够启动时间periodSeconds:10failureThreshold:35.3 ImagePullBackOff拉不到镜像# 看拉取错误详情kubectl describe podpod-name|grep-A10Events:# 常见原因# 1. 镜像名拼写错误# 2. 私有镜像仓库未配置imagePullSecrets# 3. 仓库认证过期docker login过期# 4. 节点没有该仓库的访问权限解决检查imagePullSecrets有效性确认节点能访问镜像仓库docker pull image在节点上跑一次。5.4 OOMKilled容器内存超限被杀不一定是节点内存不足也可能是Pod的resources.limits.memory设小了kubectl get podpod-name-ojsonpath{.status.containerStatuses[0].lastState.terminated.exitCode}# 如果是137说明被SIGKILLOOM排查看容器启动时的内存峰值kubectl top pod结合Prometheus看内存曲线适当调高limit。六、网络层服务之间通不了网络问题最复杂但有章可循。6.1 DNS是万恶之源Pod间通信失败80%是DNS问题。先查# 进入问题Podkubectlexec-itpod-name--sh# 在Pod内测试DNSnslookupkubernetes.defaultnslookupservice-name.namespace.svc.cluster.localcat/etc/resolv.conf# 看ndots配置# 测试网络连通性curl-vtelnet://service-name:port常见DNS坑ndots太多Pod里/etc/resolv.conf的ndots默认是5意味着任何少于5个点的域名都会被追加搜索域导致内部服务解析变成外部查询。解决方案Pod启动时加- DNSDOT1或直接用全限定域名。CoreDNS不健康看CoreDNS日志和Pod状态kubectl logs-nkube-system-lk8s-appkube-dns--tail50kubectl get pods-nkube-system-lk8s-appkube-dns6.2 Service连接失败# 看Endpoints是否有人kubectl get endpointsservice-name-nnamespace# 如果Endpoints为空说明selector匹配的Pod有问题标签不对/全部宕机# 看Service配置kubectl get svcservice-name-nnamespace-oyaml典型问题改Deployment的Pod标签忘了更新Service的selector导致流量找不到后端。6.3 NetworkPolicy误伤配了NetworkPolicy但只开放了部分流量默认是全部拒绝。确认策略是否覆盖了所有必要的流量kubectl get networkpolicy-Akubectl describe networkpolicyname-nnamespace七、集群雪崩连锁故障怎么破最危险的场景单个服务故障 → 请求堆积 → 资源耗尽 → 大量Pod重启 → 更大规模故障。7.1 雪崩的触发链条常见触发路径超时设置缺失A服务调用B服务无超时B慢→A线程池耗尽→A不可用→调用A的服务也崩重试风暴没有退避策略的重试一倒全倒健康检查不完善不健康的服务未被及时摘除持续接收请求资源无隔离所有Pod跑在同一节点资源竞争互相影响。7.2 快速止血第一步切断入口流量# 紧急下线Service改副本数为0kubectl scale deploymentsvc-name--replicas0-nnamespace# 或者加NoSchedule污点强制摘除kubectl cordonnode-name# 或者删掉有问题的Pod让它不再重建kubectl delete podpod-name--grace-period0--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 --tail200 -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 --imagebusybox -- sh看CoreDNS状态kubectl get pods -n kube-system -l k8s-appkube-dns九、小结K8s故障排查的核心是分层定位节点层先确认机器还活着资源没耗尽控制平面层API Server和etcd是根本它们健康才有后面的一切调度层Pending的Pod重点看资源和亲和性运行时层容器退出看Exit Code拉不到镜像查认证网络层80%的网络问题查DNS服务不通先查Endpoints应用层超时、重试、依赖是连锁故障的三大元凶。记住kubectl describe比kubectl get更有价值事件Events才是真相。多看日志少删Pod重启大多数问题在事件和日志里已经有答案了。下篇预告Kubernetes存储实战——从EmptyDir到Ceph CSI的持久化存储选型指南。