Pod 状态列写着 CrashLoopBackOff,RESTARTS 数字每隔几十秒涨一次。这不是一个错误码,而是 kubelet 在告诉你:容器起来了、又挂了,我正按退避策略重试。真正的原因藏在容器进程里,不在这行状态上。下面这套顺序我用了很久,基本能在五分钟内定位到根因。
先分清楚是哪一类崩溃
先跑一条命令,把退出码拿到手:
kubectl describe pod <pod-name> -n <namespace> | grep -A5 "Last State"
退出码决定了后面往哪个方向查,别跳过这步。
| 退出码 | 含义 | 先查什么 |
|---|---|---|
| 1 | 应用自己抛异常退出 | 容器日志、配置项、依赖服务是否可达 |
| 137 | 被 SIGKILL,多半是 OOM | memory limit、JVM/Node 堆参数 |
| 126 / 127 | 命令不可执行或找不到 | command/args 写法、镜像里有没有这个二进制 |
| 0 | 正常退出但 Pod 期望常驻 | 主进程跑完就结束了,前台没挂住 |
六步排查顺序
kubectl logs <pod> --previous,当前容器的日志往往是空的kubectl describe pod 底部会写 OOMKilled、Liveness probe failed、ImagePullBackOffOOMKilled 的处理
如果 Events 里明确写了 OOMKilled,先确认是 limit 给少了,还是应用本身内存参数没跟着 limit 走。Java 应用常见的坑是容器 limit 设了 512Mi,JVM 却按宿主机内存算堆大小。加上这两个参数能让 JVM 感知 cgroup 限制:
-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0
Node 应用同理,用 --max-old-space-size 显式限制。改完再看实际用量:
kubectl top pod <pod> -n <namespace>
健康检查误杀怎么改
Spring Boot、Django 这类应用冷启动要十几秒,探针如果 5 秒就开始探,容器会被反复重启,日志里还看不出应用报错。给启动慢的服务加 startupProbe 比调大 initialDelaySeconds 更稳妥:
startupProbe:
httpGet:
path: /actuator/health
port: 8080
failureThreshold: 30
periodSeconds: 5
这样最长给 150 秒启动窗口,启动成功后 livenessProbe 才开始生效。
常见问题
问:kubectl logs 什么都不输出怎么办?
答:容器可能在几毫秒内就退出了,日志没来得及刷。加 --previous 读上一次的;还是空的话把 command 换成 ["/bin/sh","-c","sleep 3600"],然后 kubectl exec -it 进去手动执行原命令。
问:RESTARTS 一直涨但业务其实正常,要处理吗?
答:要。多半是 livenessProbe 路径写错或超时太短,服务在被周期性杀掉,只是流量被其他副本顶住了。先把探针路径用 curl 在容器内验一遍。
问:只有某个节点上的 Pod 崩,其他节点正常?
答:查那台节点的资源和内核参数。kubectl describe node 看 MemoryPressure、DiskPressure,再看看是不是本地挂载路径或时间不同步导致的。
你在集群里遇到过哪种奇怪的 CrashLoopBackOff?欢迎到 fenij.com 留言说说,我把有代表性的场景补进这篇。