【架构实战】Kubernetes故障排查全景图:从Pod起不来到底层雪崩的诊断手册
应用上了Kubernetes,最怕的不是"没部署",而是"部署了却跑不起来",或者"跑得好好的突然雪崩"。新手一遇到Pod起不来就到处乱试,老手则有一套从现象到底层的排查漏斗。上一篇讲了安全加固,这一篇把Kubernetes的故障排查体系拆成一张全景图,给你一套能直接上手的诊断手册。
一、先建立"三层漏斗"思维
遇到故障千万别一头扎进去看日志,那样只会越看越乱。先把问题定位到对应层级,再逐层下钻:
- 现象层(Pod状态):Pod是Pending、CrashLoopBackOff还是Running但没流量?这是最外层的信号。
- 资源层(配置与依赖):镜像、配置、PVC、资源配额、亲和性是不是没满足条件?
- 基础设施层(节点与集群):kubelet、CNI、etcd、控制面是不是出了问题?
口诀是:先看Phase定大方向,再看Events找直接原因,最后看底层组件排查根因。下面所有排查都遵循这个顺序。
二、Pod生命周期与状态机
排查之前,先认清楚Pod能处于哪些状态:
| Phase | 含义 | 典型触发 |
|---|---|---|
Pending | 已接受但还没调度/起容器 | 资源不足、PVC未绑定、调度失败 |
Running | 至少一个容器在运行 | 正常态,但可能"假活" |
Succeeded | 所有容器正常退出 | Job/CronJob完成 |
Failed | 至少一个容器非正常退出 | 主进程退出码非0 |
Unknown | 节点失联,状态拿不到 | kubelet心跳丢失 |
注意:Pod Running ≠ 业务正常。容器起来了但反复OOM、或探针一直失败被重启,都是"假活"。
三、Pod起不来的经典五连
3.1 ImagePullBackOff / ErrImagePull
现象:Pod一直拉不下来镜像。
根因:镜像名写错、tag不存在、私有仓库没配imagePullSecret、节点网络不通仓库。
排查:
kubectl describe pod<pod>|grep-A5Events# 看具体拉取错误kubectl get events --sort-by=.lastTimestamp# 全局事件按时间排序解决:核对镜像地址与tag;私有仓库补imagePullSecrets;节点执行crictl pull <image>验证网络可达。
3.2 CrashLoopBackOff
现象:容器反复重启,间隔越来越长。
根因:应用启动即崩溃(配置错误、依赖未就绪、端口被占)、健康检查配置过严、资源limit太小触发OOM。
排查:
kubectl logs<pod>--previous# 看上一次崩溃前的日志kubectl logs<pod>-c<container>kubectl describe pod<pod>|grep-i"back-off\|exit"解决:先用--previous拿到崩溃日志;把liveness探针初始延迟initialDelaySeconds调大;确认resources.limits足够;若是依赖未就绪,改用readinessProbe+重试而非直接崩溃。
3.3 CreateContainerConfigError
现象:容器创建失败,提示config错误。
根因:引用了不存在的ConfigMap/Secret、envFrom的键缺失、挂载路径冲突。
排查:
kubectl describe pod<pod>|grep-i"configmap\|secret\|createcontainer"kubectl get configmap<name>-n<ns>-oyaml解决:确认引用的ConfigMap/Secret名称和key存在;用kubectl get cm -n <ns>核对命名空间。
3.4 OOMKilled
现象:容器被kill,状态码137,重启循环。
根因:内存使用超过resources.limits.memory,被cgroup杀掉。
排查:
kubectl get pod<pod>-ojsonpath='{.status.containerStatuses[0].lastState.terminated.reason}'kubectltoppod<pod># 看实际内存占用解决:调大memory limit;排查内存泄漏;设置合理的requests让调度更精准。
3.5 Pending(调度失败)
现象:Pod一直Pending,不分配节点。
根因:资源不足、节点有taint而Pod无toleration、nodeSelector/亲和性不匹配、PVC未绑定。
排查:
kubectl describe pod<pod>|grep-i"failedscheduling\|insufficient\|taint"kubectl get nodes-owide# 看节点资源与taint解决:缩容/扩容节点;加tolerations;放宽nodeSelector;确认PVC能绑定到PV。
四、必备排查工具箱
| 命令 | 用途 |
|---|---|
kubectl describe pod | 看事件、状态、挂载、探针 |
kubectl logs --previous | 看崩溃前日志 |
kubectl get events --sort-by=.lastTimestamp | 集群级时间线 |
kubectl exec -it <pod> -- sh | 进容器排查(需容器在跑) |
kubectl debug <pod> -it --image=busybox | 临时调试容器(不影响原Pod) |
kubectl top pod/node | 实时资源占用(需装metrics-server) |
crictl ps/pods/logs | 节点侧直接操作容器运行时 |
kubectl debug是神器:当原容器没有shell或已崩溃无法exec时,用临时容器挂载同一PID/网络命名空间进去看现场。
五、网络故障排查
网络问题是Kubernetes里最磨人的一类。按"由内到外"逐段排查:
5.1 Pod到Pod不通
先看CNI插件状态:kubectl get pods -n kube-system | grep -i <cni>,节点上crictl确认网络插件容器在跑。跨节点不通先确认节点间路由和防火墙(如Calico的BGP、Flannel的VXLAN端口4789)。
5.2 Service访问失败
Service是VIP+iptables/IPVS规则。排查顺序:
kubectl get endpoints<svc># 看endpoint是否真的有后端Podkubectl get svc<svc>-oyaml# 看selector和端口iptables-tnat-L|grep<svc># 确认规则存在(iptables模式)最常见原因是Label selector对不上,导致endpoint为空,请求被丢弃。
5.3 DNS解析失败
Pod内nslookup失败,多半是CoreDNS问题:
kubectl get pods-nkube-system-lk8s-app=kube-dns kubectl logs-nkube-system-lk8s-app=kube-dns若NodeLocalDNS或CoreDNS Pod异常,整个集群解析都会挂,表现为间歇性的"偶发超时"。
5.4 Ingress 502/504
Ingress Controller本身没问题,但后端Service的readiness探针没过,流量就不会转发过去。先看后端endpoint,再看Ingress Controller日志里的upstream超时。
六、存储故障
| 现象 | 根因 | 排查 |
|---|---|---|
| PVC一直Pending | 没有匹配PV或SC未配置 | kubectl describe pvc,看StorageClass是否存在、provisioner是否就绪 |
| 挂载失败 | 节点没装对应CSI驱动 | 节点上crictl images看driver镜像;查kubelet日志FailedMount |
| ReadWriteOnce冲突 | 单节点卷被多Pod争用 | 改用RWX存储类,或确保Pod调度到同一节点 |
| 数据盘满 | PV所在磁盘写满 | 节点df -h,清理或扩容 |
动态供给失败往往是StorageClass的provisioner Pod(如csi-resizer、external-provisioner)异常,单独看这些sidecar的日志最准。
七、节点与集群级雪崩
7.1 Node NotReady
节点状态NotReady,通常是kubelet失联或节点资源压力触发了Condition:
kubectl getnode<node>-oyaml|grep-A10Conditions看MemoryPressure/DiskPressure/PIDPressure。磁盘满(尤其是container runtime的imagefs)会触发kubelet驱逐,把节点上Pod全赶走。
7.2 集群雪崩(级联故障)
最危险的场景:节点磁盘/内存压力 → kubelet大规模驱逐Pod → 被驱逐的Pod重新调度到别的节点 → 新节点也压力升高 → 调度风暴 → API Server请求激增 → etcd写入延迟 → 更多超时与重试。
识别:
kubectl get pods-A|grep-cEvicted# 驱逐数量异常kubectl get--raw=/metrics|grepapiserver_request_duration_seconds# API延迟ETCDCTL_API=3etcdctl endpoint health# etcd健康止血:临时cordon/隔离问题节点,先停止非关键负载,给控制面喘息空间;再逐节点排查根因,而不是盲目扩容加剧风暴。
八、故障排查SOP清单
| 症状 | 第一条命令 | 大概率根因 |
|---|---|---|
| Pod一直Pending | describe看FailedScheduling | 资源/taint/亲和性 |
| 反复重启 | logs --previous | 启动崩溃/探针过严 |
| 镜像拉取失败 | describe看Events | 镜像名/密钥/网络 |
| Service不通 | get endpoints | selector不匹配 |
| DNS超时 | 查CoreDNS Pod | CoreDNS异常 |
| PVC挂不上 | describe pvc | SC/provisioner |
| 节点NotReady | get node -o yamlConditions | 资源压力/磁盘满 |
| 大面积Evicted | `get pods -A | grep Evicted` |
九、小结:监控优先于排查
最好的故障排查,是让问题在用户感知之前就暴露。三件事要做到位:
- 可观测性前置:metrics-server + Prometheus采集节点/Pod资源,配好告警(CPU、内存、磁盘、驱逐数),别等雪崩才看。
- 探针配置合理:liveness防假活、readiness控流量,初始延迟和阈值要给足,别把探针变成"自杀开关"。
- 建立SOP与文化:把上面的清单固化成团队runbook,故障演练(chaos)常态化,让排查变成肌肉记忆而非临场发挥。
记住:Kubernetes的故障从来不是"突然发生",而是"早有征兆"。会看Events、会看指标、会顺着三层漏斗下钻,你就能从"救火队员"变成"防火工程师"。
下一篇预告:Kubernetes多集群管理实战——从单集群到联邦调度的演进之路。