Kubernetes故障排查的系统化思路
Kubernetes集群的故障表现千变万化,但排查路径有规律可循。核心原则是从控制面到数据面、从宏观到微观逐层收敛。一个Pod无法正常工作,可能是kube-scheduler未调度、可能是kubelet启动失败、可能是容器运行时异常、也可能是应用自身的问题。盲目试错不如按照固定排查路径逐步定位。
排查顺序:事件(Event) → Pod状态 → 节点状态 → 控制面组件 → 网络与存储。Events是最常被忽略的信息源,它记录了Kubernetes内部对资源的所有操作和状态变更。
Pod CrashLoopBackOff诊断路径
CrashLoopBackOff是最常见的Pod异常状态,含义是容器启动后反复崩溃退出。排查步骤:
第一步:查看Pod事件和容器状态
# 查看Pod状态和最近事件
kubectl describe pod <pod-name> -n <namespace>
# 关注以下关键信息:
# - State: Waiting/Running/Terminated
# - Last State: 退出码和原因
# - Events: 调度、拉取镜像、启动容器的时序
第二步:查看容器日志
# 查看当前容器日志
kubectl logs <pod-name> -n <namespace>
# 查看上一次崩溃的容器日志(关键!)
kubectl logs <pod-name> -n <namespace> --previous
# 多容器Pod需指定容器名
kubectl logs <pod-name> -c <container-name> --previous
CrashLoopBackOff的常见根因和对应处理:
退出码1:应用进程异常退出,通常是配置错误、环境变量缺失、端口冲突。检查应用日志定位具体错误行。
退出码137:容器被OOM Kill。describe输出中会看到Last State的Reason为OOMKilled。解决方案是增加resources.limits.memory或在应用层优化内存使用。
退出码139/134:段错误(SIGSEGV)或中止(SIGABRT),通常是C/C++依赖库版本不兼容或glibc版本冲突。在Alpine镜像中运行依赖glibc的程序是常见触发场景。
退出码2:应用框架级别的启动错误(如Spring Boot配置文件解析失败)。这类错误信息不在stdout/stderr,而需要查看应用自身的日志文件。
# 进入容器内查看应用日志文件
kubectl exec -it <pod-name> -- /bin/sh
cat /var/log/app/application.log
ImagePullBackOff排查方法
镜像拉取失败的排查相对直接,但有一种隐蔽场景容易被忽略:私有镜像仓库的认证配置。
# 查看详细拉取错误
kubectl describe pod <pod-name> | grep -A5 Events
# 常见错误类型:
# - Failed to pull image: 访问不到镜像仓库(网络/认证问题)
# - image pull backoff: 重试次数耗尽
# - ErrImagePull: 镜像不存在或标签错误
私有镜像仓库认证配置:
# 创建registry认证Secret
kubectl create secret docker-registry regcred \
--docker-server=registry.example.com \
--docker-username=robot\$user \
--docker-password=<token> \
--docker-email=dev@example.com
# 在Pod spec中引用
spec:
imagePullSecrets:
- name: regcred
containers:
- name: app
image: registry.example.com/app:v1.2.0
需要注意Harbor等私有仓库的用户名中可能包含$符号,在Shell中需要转义。这个问题在CI/CD流水线中经常出现,表现为Secret创建成功但认证仍然失败。
节点NotReady的诊断与恢复
节点NotReady意味着kubelet停止向kube-apiserver上报节点状态,超过40秒后节点被标记为NotReady,5分钟后Pod会被驱逐。
kubelet异常是最常见原因
# 在目标节点上检查kubelet状态
systemctl status kubelet
# 查看kubelet日志
journalctl -u kubelet --since "1 hour ago" | tail -100
# 常见kubelet故障:
# - disk pressure: 节点磁盘使用率超过85%
# - memory pressure: 节点内存不足
# - PLEG is not healthy: 容器运行时通信超时
Disk Pressure是生产环境最常遇到的节点NotReady原因。Kubernetes默认当节点磁盘使用率超过85%时标记为DiskPressure,kubelet停止在该节点调度新Pod,并可能驱逐已有Pod。处理方式:
# 清理节点磁盘空间
# 1. 清理未使用的容器镜像
crictl rmi --prune
# 2. 清理退出状态的容器
crictl ps -a --state Exited -q | xargs -r crictl rm
# 3. 清理旧的日志文件
find /var/log/pods -type f -name "*.log" -mtime +7 -delete
# 4. 调整kubelet的磁盘阈值
# /var/lib/kubelet/config.yaml
evictionHard:
imagefs.available<15%
nodefs.available<10%
PLEG Not Healthy排查
Pod Lifecycle Event Generator(PLEG)是kubelet通过CRI接口与容器运行时通信的模块。PLEG超时意味着kubelet无法从containerd/docker获取容器状态。常见原因:
1. containerd进程卡死:重启containerd并检查磁盘IO是否正常
2. 容器数量过多导致CRI查询超时:调整kubelet的–pleg-reinterval和–pleg-max-retries参数
3. 内核版本与容器运行时不兼容:某些低版本内核的cgroup v2支持不完整
Service与NetworkPolicy连通性排查
Pod能Running但无法访问Service,是另一个高频故障场景。排查链路:
# 1. 检查Service Endpoints是否正常
kubectl get endpoints <service-name>
# 如果ENDPOINTS为none,说明没有Pod匹配selector
# 2. 从Pod内部测试DNS解析
kubectl exec -it <pod-name> -- nslookup <service-name>.<namespace>.svc.cluster.local
# 3. 直接用ClusterIP测试连通性
kubectl exec -it <pod-name> -- curl -v http://<cluster-ip>:<port>/healthz
# 4. 检查NetworkPolicy是否阻断流量
kubectl get networkpolicy -n <namespace>
Service Endpoints为空是最常见的”能Running但不通”的原因。Selector的标签不匹配是根因,注意标签值的大小写和拼写。NetworkPolicy阻断则更隐蔽,特别是在多团队共享集群的场景下,一个全局default-deny策略可能影响所有命名空间。
排查工具箱速查表
| 故障现象 | 排查命令 | 常见根因 |
|---|---|---|
| CrashLoopBackOff | kubectl logs –previous | 应用崩溃/OOM/配置错误 |
| ImagePullBackOff | kubectl describe pod | 镜像不存在/认证失败 |
| Pending | kubectl describe pod | 资源不足/节点选择器无匹配 |
| 节点NotReady | journalctl -u kubelet | Disk Pressure/kubelet异常 |
| Service不通 | kubectl get endpoints | Selector不匹配/NetworkPolicy |
| PVC Pending | kubectl describe pvc | StorageClass不存在/容量不足 |
掌握这套排查路径后,绝大部分Kubernetes故障可以在15分钟内定位到根因。关键是在排查前不要急于操作,先通过Events和日志收集完整信息,再根据现象匹配对应的诊断路径。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/kubernetes-gu-zhang-pai-cha-shi-zhan-cong-pod-yi-chang-dao/