Pod CrashLoopBackOff 诊断与修复
CrashLoopBackOff 是 Kubernetes 运维中最常见也最让人头疼的状态之一。Pod 启动后容器进程退出,kubelet 反复尝试重启,每次重启间隔指数退避。定位这个问题的核心是看容器的退出码和上一个容器的日志。
# 查看 Pod 状态和重启次数
kubectl get pods -n production -o wide
# 查看事件,定位重启原因
kubectl describe pod <pod-name> -n production
# 关键字段:Last State 里的 Exit Code
# Exit Code 0: 进程正常退出(通常是应用逻辑问题)
# Exit Code 1: 应用未捕获异常
# Exit Code 137: OOMKilled(内存超限被杀)
# Exit Code 139: Segfault(段错误)
# Exit Code 143: SIGTERM 正常终止
查看上一个崩溃容器的日志:
# --previous 参数查看上次容器的 stdout/stderr
kubectl logs <pod-name> -n production --previous
# 如果日志滚动太快,重定向到文件
kubectl logs <pod-name> -n production --previous > /tmp/crash.log 2>&1
OOMKilled 是 CrashLoopBackOff 的高频原因。处理方式:
# 查看当前资源限制
kubectl get pod <pod-name> -n production -o jsonpath='{.spec.containers[*].resources}'
# 调整资源限制
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi" # 原来可能是 512Mi,适当调大
cpu: "500m"
# 查看 cgroup 层面的内存使用
kubectl exec <pod-name> -- cat /sys/fs/cgroup/memory/memory.usage_in_bytes
调整 limits 不是唯一解法。内存泄漏导致的 OOM 需要从应用层面修复。可以用 pprof 抓取堆内存快照进行分析。
ImagePullBackOff 与镜像拉取问题
私有镜像仓库的认证失败是 ImagePullBackOff 最常见的原因:
# 创建 docker-registry 类型的 Secret
kubectl create secret docker-registry regcred \
--docker-server=registry.example.com \
--docker-username=robot \
--docker-password=<token> \
-n production
# 在 Pod 的 imagePullSecrets 中引用
spec:
imagePullSecrets:
- name: regcred
containers:
- image: registry.example.com/app:v2.1.0
网络层面的排查路径:
# 在节点上手动拉取测试
docker pull registry.example.com/app:v2.1.0
# 检查 DNS 解析
kubectl run dns-test --image=busybox --rm -it -- nslookup registry.example.com
# 检查节点到仓库的网络连通性
kubectl run net-test --image=busybox --rm -it -- wget -O- https://registry.example.com/v2/
Service 与 Endpoints 连通性问题
Service 能找到 Pod 依赖于 Endpoints 的正确映射。Service selector 和 Pod label 不匹配是连通性问题的头号元凶:
# 检查 Endpoints 是否有后端 Pod
kubectl get endpoints <svc-name> -n production
# 空 Endpoints 说明 selector 没匹配到 Pod
# 对比 Service selector 和 Pod labels
kubectl get svc <svc-name> -n production -o yaml | grep -A5 selector
kubectl get pods -n production --show-labels
# 常见错误:selector 里用 camelCase,label 里用 kebab-case
# selector: { app: myApp } vs labels: { app: my-app }
如果 Endpoints 正常但访问不通,排查 kube-proxy:
# 查看 kube-proxy 日志
kubectl logs -n kube-system -l k8s-app=kube-proxy
# 检查 iptables 规则(kube-proxy iptables 模式)
iptables -t nat -L KUBE-SERVICES | grep <svc-cluster-ip>
# 如果使用 IPVS 模式
ipvsadm -Ln | grep <svc-cluster-ip>
节点 NotReady 与驱逐处理
节点变为 NotReady 通常是因为 kubelet 与 API Server 的通信中断,或节点资源耗尽导致 kubelet 无法正常上报状态:
# 查看节点状况
kubectl describe node <node-name>
# 关注 Conditions 部分
# Ready=False: kubelet 失联
# MemoryPressure=True: 节点内存不足
# DiskPressure=True: 节点磁盘不足
# PIDPressure=True: 进程数过多
# 查看 kubelet 日志
journalctl -u kubelet --since "10 minutes ago" -f
# 查看节点资源使用
kubectl top node <node-name>
节点 NotReady 超过 pod-eviction-timeout(默认 5 分钟)后,Pod 会被标记为驱逐状态。但驱逐是异步的,如果节点只是短暂失联,Pod 可能会出现”双活”问题(旧节点上 Pod 还在运行,新节点上已调度了新 Pod)。处理方法:
# 确认节点确实无法恢复后,手动标记不可调度并驱逐
kubectl cordon <node-name>
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data
# 如果节点已经彻底失联,drain 会卡住,加 --force 并跳过等待
kubectl drain <node-name> --ignore-daemonsets --force --grace-period=0
核心组件故障处理
etcd 是 Kubernetes 的核心存储,etcd 不可用意味着整个集群瘫痪:
# 检查 etcd 健康状态
kubectl get cs
# 或直接访问 etcd 端点
ETCDCTL_API=3 etcdctl endpoint health \
--endpoints=https://127.0.0.1:2379 \
--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 --write-out=table \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
# 清理历史修订版本释放空间
ETCDCTL_API=3 etcdctl compact $(etcdctl endpoint status --write-out=json | python3 -c "import sys,json; print(json.load(sys.stdin)[0]['Status']['header']['revision'])")
ETCDCTL_API=3 etcdctl defrag
可观测性建设
故障排查的效率取决于可观测性建设的完善程度。推荐最小化可观测性栈:
# Prometheus + Grafana + Alertmanager
# 关键告警规则
- alert: PodCrashLooping
expr: rate(kube_pod_container_status_restarts_total[15m]) > 0
for: 5m
- alert: NodeNotReady
expr: kube_node_status_condition{condition="Ready",status="unknown"} == 1
for: 5m
- alert: HighMemoryUsage
expr: (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) > 0.9
for: 5m
- alert: EtcdInsufficientMembers
expr: count(up{job="etcd"} == 1) < floor(count(up{job="etcd"}) / 2) + 1
for: 3m
告警渠道配置 PagerDuty 或企业微信 Webhook,确保值班人员第一时间收到通知。故障排查能力是日积月累的结果,每处理一次故障都建议复盘并补充到运维知识库中。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/kubernetes-ji-qun-gu-zhang-pai-cha-shi-zhan-cong/