Kubernetes 集群排障与诊断:从 Pod 症状到节点/集群根因的实战手册

系统讲解 Kubernetes 故障排查方法:Pod 层症状定位(CrashLoopBackOff/Pending/OOMKilled/ImagePullBackOff)、kubectl describe/events 的正确用法、kubectl debug 临时容器与 kubectl node-shell 诊断、节点级排查(kubelet/cgroup/磁盘)、网络与 DNS 故障、etcd 与控制面排障,以及 must-gather 与现场排障流程。

生产集群出现故障时,最怕的不是问题本身,而是没有一套"由表及里、逐层收敛"的排查方法。本指南从最常见的 Pod 症状出发,自底向上地带你走完三条主线:工作负载层(Pod 为什么不健康)→ 节点层(为什么 Pod 起不来)→ 集群层(为什么控制面或网络坏了),并给出每个环节该敲的命令、该看的关键字段,以及现场排障的纪律。


目录


1. 排障心法:由表及里、逐层收敛

1.1 三层模型

工作负载层(Pod / Deployment / Service):
  症状:CrashLoop、Pending、连不上、503

节点层(Node / kubelet / 容器运行时):
  症状:节点 NotReady、磁盘满、镜像拉取失败

集群层(etcd / apiserver / 网络插件 / DNS):
  症状:kubectl 超时、apiserver 5xx、跨节点不通、DNS 解析失败

排查顺序:从"离业务最近"的一层开始,逐层向外扩张
  → 先看 Pod 本身(describe/events/logs)→ 再节点 → 再集群/网络

ℹ️ 心法:“看 events 永远先于看日志”。Pod 层的调度失败、拉取失败、探针失败都会写进 Events,几秒钟就能定位方向;日志是第二步才看的。

1.2 常备命令集

# 一眼概览
kubectl get pods -n ns -o wide          # 含节点、IP
kubectl get events -n ns --sort-by=.lastTimestamp | tail
kubectl describe pod <pod> -n ns        # 状态+事件+容器状态
kubectl get node -o wide
kubectl top node / kubectl top pod -n ns   # 资源占用

2. Pod 症状 1:Pending(调度失败)

2.1 常见的 Pending 原因

Pending = 调度器还没为它找到节点
常见原因(按频率):
  1. 资源不足:节点上剩余资源 < requests(requests 总和超节点容量)
  2. 节点不可调度:污点未容忍 / NodeSelector 不匹配 / 亲和性不满足
  3. PVC 未绑定:等待 PVC Bound(存储类没货/不存在)
  4. 配额受限:ResourceQuota 拒绝创建
  5. 节点 NotReady / 被 cordon

2.2 用 events 定位

kubectl describe pod <pod> -n ns | grep -A5 Events
# 典型输出:
#   0/1 nodes are available: 2 Insufficient cpu, 1 node(s) had taint
#     {node-taint: key=dedicated:NoSchedule}, 1 Insufficient memory.
#   waiting for a volume to be created, either by external provisioner
逐条对策:
  - Insufficient cpu/memory → 看请求量、扩容节点或减 requests
  - taint not tolerated → 补 toleration 或去掉污点
  - volume waiting → 检查 storageclass / PVC 状态
  - quota → kubectl describe resourcequota

3. Pod 症状 2:CrashLoopBackOff 与 OOMKilled

3.1 区分崩溃类型

CrashLoopBackOff = 容器反复启动又崩溃(代码/配置/依赖问题)
  → 看日志定位为什么崩
OOMKilled = 容器被内核 OOM 杀掉(内存超限)
  → 看 limit 是否设太低 / 真实用量

其他:ContainerCreating 卡住(拉镜像慢 / 挂卷失败 / 探针不通过)
     Terminating 卡住(GracePeriod 内没退出 / finalizer 阻塞)

3.2 排查命令

# 崩溃:看退出码与日志
kubectl get pod <pod> -n ns -o jsonpath='{.status.containerStatuses[].state}'
kubectl logs <pod> -n ns --previous     # 上一个实例的日志(崩溃原因常在里面)
kubectl logs <pod> -n ns --tail=200 -f

# OOM:看容器状态里的 reason
kubectl describe pod <pod> -n ns | grep -A3 'Last State'
#   Last State: Terminated  Reason: OOMKilled  Exit Code: 137

# 资源实际用量(是否真的逼近 limit)
kubectl top pod <pod> -n ns
典型处置:
  - 崩溃:改配置 / 修依赖 / 换启动命令
  - OOM:调高 memory limit 或优化内存(先确认是"真用得多"还是泄漏)
  - 探针失败:看 readiness/liveness 阈值与启动时长(startupProbe 不够长)

4. Pod 症状 3:ImagePullBackOff 与 ErrImagePull

4.1 拉取失败的常见根因

ImagePullBackOff = 镜像拉取持续失败
常见根因:
  1. 镜像名/标签写错(不存在)
  2. 私有仓库认证失败(imagePullSecrets 缺失/过期)
  3. 仓库不可达(网络策略 / 域名解析 / 出口防火墙)
  4. 镜像拉取超时(大镜像 / 慢网络)
  5. 命名空间错误(如把 docker.io/ 写错)

4.2 排查命令

kubectl describe pod <pod> -n ns | grep -A3 Events
# Failed to pull image "xxx": rpc error ... not found
# Failed to pull image "xxx": pull access denied / unauthorized

# 检查 secrets 与仓库
kubectl get secrets -n ns
kubectl get pod <pod> -n ns -o jsonpath='{.spec.imagePullSecrets}'

# 手动拉取验证
crictl pull <image>    # 在节点上手动拉,看具体报错

5. 进入容器排障:kubectl exec / debug / node-shell

5.1 常用进入手段

# 1. exec 进业务容器(容器要活着)
kubectl exec -it <pod> -n ns -- /bin/sh

# 2. 容器死了/没 shell → kubectl debug 起临时调试容器
kubectl debug <pod> -n ns -it \
    --image=nicolaka/netshoot:latest    # 网络诊断镜像(curl/dig/tcpdump...)

# 3. 诊断不可调度/挂起的 Pod(复制一份加特权)
kubectl debug <pod> -n ns -it --copy-to=debug-xxx \
    --set=spec.nodeName=<node> \
    --image=nicolaka/netshoot:latest

# 4. 诊断节点本身(Node 视角,挂 host 根文件系统)
kubectl debug node/<node> -it \
    --image=ubuntu:22.04 -- chroot /host
netshoot 镜像(nicolaka/netshoot)是 K8s 排障瑞士军刀:
  内置 curl、dig、nslookup、tcpdump、iperf、ss、traceroute...
  诊断网络/连通性/端口/协议问题时首选

kubectl debug(k8s 1.27+ 内置,基于临时容器 ephemeral containers):
  不改变原容器、可进已崩溃容器所在 Pod、诊断节点

5.2 在调试容器里做什么

# 网络连通
curl -v http://svc.ns:8080/healthz
nslookup svc.ns.svc.cluster.local
# 抓包确认延迟/丢包
tcpdump -i eth0 port 8080
# 系统资源
top / free -m / df -h

6. 节点级排查:kubelet、cgroup 与磁盘

6.1 节点 NotReady 的排查

# 节点状态与条件
kubectl get node <node> -o yaml | grep -A8 conditions:
kubectl describe node <node> | grep -A5 Conditions
#   Ready=False + 原因(KubeletNotReady / RuntimeNotReady)

# 登录节点查 kubelet
journalctl -u kubelet -n 100 --no-pager
systemctl status kubelet
# 常见:证书过期、磁盘满、容器运行时异常

6.2 磁盘与 cgroup 资源

节点层三大隐患:
  1. 磁盘满(/ 或 /var/lib/docker|containerd)
     → 镜像层占满、日志占满
     → 清理:crictl rmi 未使用镜像、logrotate、扩容
  2. cgroup 内存/CPU 冲突
     → 检查 node 上的系统进程是否被 kubelet 误杀(cgroup v2 配置)
  3. inode 耗尽(小文件巨多)
     → df -i 查看,清理
# 快速体检节点
ssh node
df -h && df -i
crictl images | wc -l
top -b -n1 | head -20        # 看 load 与 top 进程
dmesg | grep -i 'oom\|killed'   # 内核 OOM 记录

7. 网络与 DNS 排障

7.1 网络故障分层

网络问题要分清在哪一跳:
  - Pod ↔ Pod 同节点?跨节点?
  - Pod ↔ Service?(kube-proxy/iptables/IPVS 规则)
  - Pod ↔ 外部?(NAT / egress 策略)
  - 集群 ↔ 集群外(出口网关 / LoadBalancer)

常用探针命令(在调试容器里):
  ping <pod-ip>             # 基础连通
  curl -v <service-cluster-ip>:port   # Service 层
  nslookup <svc>            # DNS
  traceroute / tcpdump      # 中间链路

7.2 DNS(CoreDNS)排障

症状:代码里解析域名失败 / nslookup 超时
排查:
  1. CoreDNS Pod 是否 Running(kubectl get pods -n kube-system -l k8s-app=kube-dns)
  2. 看 CoreDNS 日志(query 拒绝 / 递归上游失败)
  3. 检查 /etc/resolv.conf(nameserver / search domain)
  4. 常见根因:DNSPolicy、本地缓存(nodelocaldns)、上游 DNS 可达性

networking 命令示例:
  kubectl get svc -n kube-system kube-dns
  kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50

8. 控制面与 etcd 排障

8.1 apiserver / 控制面异常

# apiserver 是否可达、健康
kubectl get --raw=/healthz
kubectl get --raw=/livez /readyz
# 控制面 Pod 状态
kubectl get pods -n kube-system | grep -E 'apiserver|controller|scheduler'
journalctl -u kube-apiserver -n 100

# 常见:apiserver 证书过期、etcd 慢导致 apiserver 延迟

8.2 etcd 健康与存储

# etcd 成员与健康(在有 etcd 的节点)
etcdctl --endpoints=https://127.0.0.1:2379 \
  --cacert=... --cert=... --key=... endpoint health --cluster
etcdctl endpoint status --cluster -w table   # leader、raft、db 大小

# 关键告警信号:
#  - leader 频繁切换(网络抖动/磁盘慢)
#  - db 大小过大(compact 不及时)
#  - raft 延迟高(磁盘 IO 慢)
控制面排障要点:
  - 故障多半是"etcd 慢 → apiserver 慢 → 全集群雪崩"
  - 优先查 etcd 磁盘 IO、网络、成员健康
  - apiserver 被限流(RequestTimeout)也要看 etcd 响应时间

9. 现场排障纪律与 must-gather

9.1 现场排障五步纪律

现场排障(Incident)流程:
  1. 止血优先:先恢复服务(重启/扩容/回滚),再深挖根因
  2. 记录时间线:每个操作和观察都记录(事后复盘用)
  3. 由表及里:按 工作负载→节点→集群 顺序收敛
  4. 保留现场:崩溃样本、日志、pod 状态快照先留存再处置
  5. 复盘闭环:根因、改进项、监控/演练补位

禁止:没留现场就删 Pod / 重启节点(丢了证据)

9.2 must-gather:把现场打包

# OpenShift 提供 must-gather;标准 K8s 可用 kubectl 打包:
kubectl get pods -A -o wide > pods.txt
kubectl get events -A --sort-by=.lastTimestamp > events.txt
kubectl get nodes -o yaml > nodes.yaml
kubectl get all -A -o yaml > all.yaml
# 关键组件日志
kubectl logs -n kube-system <apiserver-pod> --tail=500 > apiserver.log
# 打包上传给同事/供应商排查
tar czf cluster-snapshot.tar.gz pods.txt events.txt nodes.yaml all.yaml

ℹ️ 原则:排障时先"复制现场"再"动手处置"——快照永远先于变更。这不仅保护证据,也让多人协作时大家看同一份事实。


10. 生产最佳实践与避坑

10.1 Checklist

□ 先看 Events 再看日志,避免乱查
□ 常备 netshoot / debug 镜像,掌握 kubectl debug
□ 磁盘/inode 监控(df -i、镜像清理)
□ 节点 OOM/cgroup 监控(dmesg、top)
□ etcd 健康与 db 大小监控(leader 切换、延迟)
□ 网络/DNS 监控(CoreDNS 错误、连通性探测)
□ must-gather 脚本化,一按即出
□ 排障演练(GameDay):模拟 Pending / CrashLoop / DNS 故障

10.2 常见坑

坑现象对策
只看日志不看 Events方向查错先 describe 看 Events
没留现场就删 Pod证据丢失先快照再处置
磁盘满没监控节点集体 NotReadydf/inode 监控 + 清理策略
OOM 归因错误调 limit 却还是死区分真用量 vs 泄漏
etcd 慢没发现全集群雪崩etcd 健康 + 延迟告警
排障靠直觉反复试错三层模型 + 纪律流程

10.3 一句话原则

排障不是猜,是"逐层收敛"——每一条证据都把根因范围缩小一格。

小结

K8s 排障 = 把"症状"翻译成"根因"的收敛过程:先看 Events 定位方向,用 describe/logs/debug 钻进去,再到节点查 kubelet/磁盘/cgroup,最后看控制面与 etcd。落地记住五件事:Events 先于日志、kubectl debug 与 netshoot 常备、磁盘与 etcd 健康要监控、现场先快照再处置、故障要做演练复盘。当团队的排障从"经验直觉"升级为"流程化收敛",再复杂的故障也能在几分钟内被框定根因——这才是运维成熟度的真正体现。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「云原生」更多文章

  1. Kubernetes 备份容灾与数据保护:Velero、etcd 与恢复演练实战
  2. Kubernetes 渐进式交付:Argo Rollouts、金丝雀/蓝绿与流量治理实战
  3. Kubernetes 集群安全加固与审计:从 CIS Benchmark 到纵深防御