Kubernetes集群故障排查实战:从Pod CrashLoopBackOff到根因定位全流程

Kubernetes故障排查的系统性方法论

Kubernetes集群出问题时,最怕的不是某个Pod挂掉,而是排障过程像无头苍蝇——日志看了一堆,命令跑了一通,却没定位到根因。系统化排障的核心是缩小范围:从集群→节点→Pod→容器→应用,逐层定位。

排查的第一步永远是确认故障的层级。集群级别的问题(API Server不可达、节点NotReady)和Pod级别的问题(CrashLoopBackOff、OOMKilled)的排查路径完全不同。

Pod CrashLoopBackOff:最常见的在线故障

CrashLoopBackOff意味着容器启动后反复崩溃,Kubelet不断重试。排查流程:

# 查看Pod状态和事件
kubectl get pod myapp-7f9b8c6d4-x2k1j -o wide
kubectl describe pod myapp-7f9b8c6d4-x2k1j

# 关键信息在Events部分和Last State中
# Last State: Terminated  Reason: Error  Exit Code: 137  → OOMKilled
# Last State: Terminated  Reason: Error  Exit Code: 1   → 应用异常退出
# Last State: Terminated  Reason: Completed  Exit Code: 0 → 主进程正常退出但非长期运行

不同Exit Code的根因方向:

Exit Code 137 (OOMKilled):容器内存超限。查看资源限制和实际使用:

kubectl describe pod myapp-7f9b8c6d4-x2k1j | grep -A5 "Limits"
# 解决方案:调大resources.limits.memory,或优化应用内存使用
kubectl patch deployment myapp -p '{"spec":{"template":{"spec":{"containers":[{"name":"myapp","resources":{"limits":{"memory":"2Gi"}}}]}}}}'

Exit Code 1:应用自身报错。查看容器日志:

# 当前容器日志
kubectl logs myapp-7f9b8c6d4-x2k1j

# 上一次崩溃的容器日志(关键!)
kubectl logs myapp-7f9b8c6d4-x2k1j --previous

Exit Code 0:命令执行完就退出了。常见于Job类型的镜像被Deployments使用,或entrypoint脚本执行完毕。检查Dockerfile的ENTRYPOINT和CMD是否正确。

Pod一直Pending:调度失败诊断

Pod长时间Pending意味着调度器无法为其找到合适节点:

kubectl get pod myapp-7f9b8c6d4-x2k1j -o jsonpath='{.status.conditions[0].message}'

常见原因及对应方案:

Insufficient cpu/memory:集群资源不足。检查节点实际可用量:

kubectl top nodes
kubectl describe node node1 | grep -A5 "Allocated resources"

node(s) had volume node affinity conflict:PVC绑定的PV有节点亲和性限制,导致Pod只能调度到特定节点但该节点资源已满。这种情况需要检查StorageClass的volumeBindingMode是否为WaitForFirstConsumer:

kubectl get storageclass standard -o yaml | grep volumeBindingMode
# WaitForFirstConsumer: 延迟绑定,Pod调度后再创建PV
# Immediate: 立即绑定,可能导致亲和性冲突

MatchNodeSelector / NodeAffinity:标签选择器过于严格。列出节点标签确认:

kubectl get nodes --show-labels
kubectl get pod myapp-7f9b8c6d4-x2k1j -o yaml | grep -A10 affinity

Service无法访问:网络层排障

Pod正常但Service访问不通,从底层往上排查:

# 1. Pod自身是否健康
kubectl exec -it myapp-7f9b8c6d4-x2k1j -- curl -s http://localhost:8080/healthz

# 2. Service ClusterIP是否可达(从集群内Pod测试)
kubectl run tmp --image=busybox --rm -it --restart=Never --   wget -qO- http://myapp-svc:8080/healthz

# 3. 检查Endpoints是否正常关联
kubectl get endpoints myapp-svc
# 如果ENDPOINTS为none,说明selector匹配不到任何Pod
kubectl describe svc myapp-svc | grep Selector
kubectl get pods -l app=myapp  # 确认Pod标签

iptables/IPVS规则检查

# iptables模式
iptables -t nat -L KUBE-SERVICES | grep myapp-svc

# IPVS模式
ipvsadm -Ln | grep 10.96.0.100  # 替换为Service ClusterIP

DNS解析问题

# 从Pod内测试DNS
kubectl run tmp --image=busybox --rm -it --restart=Never --   nslookup myapp-svc.default.svc.cluster.local

# CoreDNS日志
kubectl logs -n kube-system coredns-6d4b75cb7d-xxxx
# 如果DNS查询超时,检查CoreDNS的ready探针和上游DNS配置

节点NotReady:Kubelet问题诊断

节点状态变为NotReady时,SSH登录该节点排查:

# 检查kubelet状态
systemctl status kubelet
journalctl -u kubelet --since "10 min ago"

# 常见原因1: PLEG超时(Pod Lifecycle Event Generator)
# 日志特征: "PLEG is not healthy"
# 原因: Docker/containerd运行时卡死,或节点I/O负载过高
# 临时解决: 重启容器运行时
systemctl restart containerd

# 常见原因2: 磁盘压力
df -h /var/lib/kubelet
# kubelet默认磁盘使用率>85%触发DiskPressure,停止调度新Pod
# 清理不用的镜像和已退出容器
crictl rmp -a  # 清理已退出容器
crictl rmi -a  # 清理不用的镜像

etcd集群健康检查

etcd是Kubernetes的数据存储,etcd异常会导致整个集群不可用:

# 检查etcd成员健康
ETCDCTL_API=3 etcdctl endpoint health   --cacert=/etc/kubernetes/pki/etcd/ca.crt   --cert=/etc/kubernetes/pki/etcd/server.crt   --key=/etc/kubernetes/pki/etcd/server.key

# 检查etcd性能指标
ETCDCTL_API=3 etcdctl endpoint status -w table   --cacert=/etc/kubernetes/pki/etcd/ca.crt   --cert=/etc/kubernetes/pki/etcd/server.crt   --key=/etc/kubernetes/pki/etcd/server.key

# 重点关注:DB SIZE是否超过2GB警告线,是否有member处于learner状态

etcd慢查询告警(committed index too far behind)通常意味着某个成员磁盘I/O慢。SSD是etcd节点的硬性要求,机械盘环境必须迁移。

排障工具箱与快捷命令

# 快速查看集群整体状态
kubectl get --raw='/readyz?verbose'
kubectl get events --sort-by='.metadata.creationTimestamp' -A

# 资源配额和使用率一览
kubectl resource-capacity  # 需安装resource-capacity插件

# 网络连通性快速测试
kubectl run netshoot --image=nicolaka/netshoot --rm -it --restart=Never -- bash

# 一行命令收集所有Pod的最近错误日志
kubectl get pods -A --field-selector=status.phase=Failed -o name |   xargs -I{} kubectl logs {} --tail=50

Kubernetes排障的关键是层级定位:先确认是控制面还是数据面的问题,再逐层下钻。盲目进容器看日志只会浪费时间。建立从集群→节点→Pod→容器→应用的排查顺序,配合describe、logs、events三板斧,绝大多数故障都能在15分钟内定位到根因。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/kubernetes-ji-qun-gu-zhang-pai-cha-shi-zhan-cong-2/

(0)
小编小编
上一篇 5小时前
下一篇 5小时前

相关推荐