上周五晚,刚准备下班。
群里@我:"生产环境几个Pod起不来了,状态CrashLoopBackOff。"
CrashLoopBackOff,K8s运维最熟悉的陌生人。说难不难,说烦是真烦。你得一个个查日志、describe、翻事件、想原因、改配置、重新部署。运气好十分钟,运气不好折腾一小时。
但这次我换了个打法。没自己从头查,直接把报错喂给了DeepSeek。
结果:3分钟搞定,比平时快了6倍。
但说句实话。AI不是万能的,如果不懂原理,AI给的建议你也分辨不出好坏。下面这两个场景都是我亲自验证过的,但我也标注了AI给的信息哪些需要你自己判断。
CrashLoopBackOff是啥
简单说就是容器启动就挂、挂了K8s再拉、拉了又挂。K8s会等几秒再重试,等待时间会根据退避策略递增:10s → 20s → 40s → 80s → 160s → 最长5分钟。
最常见的原因就那么几种:
- ·应用本身报错(代码抛异常、端口被占用、启动参数不对)
- ·配置不对(环境变量漏了、ConfigMap没挂上)
- ·资源不够(内存超限被cgroup OOM Kill)
- ·存活检查失败(liveness probe配置有问题)
- ·镜像问题(拉不下来或版本不对)
场景一:OOM Kill排查
那天晚上遇到的情况是这样的:
$ kubectl get pods -n production
NAME READY STATUS RESTARTS AGE
api-gateway-7d4b5c6f9-x2k4n 0/1 CrashLoopBackOff 15 12m
15次重启,明显不是偶发问题。先describe看看详情:
$ kubectl describe pod api-gateway-7d4b5c6f9-x2k4n -n production
关键信息:
- Last State: Terminated,Exit Code: 137
- Restart Count: 15
- Limits: memory 512Mi
- Events里能看到 OOMKilling 记录
Exit Code 137 = 128 + 9,信号9就是SIGKILL。 这说明容器进程是被内核强制杀掉的,不是自己正常退出的。
在K8s里,exit code 137最常见的两个原因:
1. cgroup OOM Killer — 容器实际内存使用超过了limits,cgroup直接杀了进程
2. 节点OOM — 宿主机内存不足,内核选了你的Pod杀掉
这两种情况都能在 kubectl describe pod 的 Events 字段看到记录,比如 OOMKilling 或者 The node was low on resource: memory。
怎么确认?看Events:
$ kubectl describe pod api-gateway-7d4b5c6f9-x2k4n -n production | grep -A5 Events
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning OOMKilling 2m kubelet Memory cgroup out of memory: Killed process 12345 (java)
确认是OOM之后,处理方案很明确:
$ kubectl edit deployment api-gateway -n production
$ kubectl top pod -n production
整个过程自己看describe、看Events、确认exit code含义,不到5分钟。 AI在这步能做的,是帮你解释exit code的含义,以及提醒你去检查Events。但最关键的信息,describe的输出和Events,得你自己去看,AI看不到你的集群。
场景二:启动命令写错了
过了两天又遇到一个相似的CrashLoopBackOff,但这次exit code是0。
Last State: Terminated
Exit Code: 0
Exit Code 0说明进程正常结束了。 但对于Deployment这种要求容器持续运行的控制器来说,进程结束=故障。K8s会按照restartPolicy(默认Always)重启它,启动→结束→重启→结束,不断循环,触发CrashLoopBackOff。
什么情况下容器会正常结束?
最常见的是command写错了。比如:
command: ["/bin/sh", "-c", "echo hello"]
command: ["/bin/sh", "-c", "nohup java -jar app.jar &"]
& 会把Java进程扔到后台,然后shell自己就退出了。shell一退出,容器就结束了(PID 1没了),K8s就重启,循环开始了。
正确的写法是直接让Java前台运行:
command: ["java", "-jar", "app.jar"]
或者如果一定要sh -c的话,保证进程在前台:
command: ["/bin/sh", "-c", "exec java -jar app.jar"]
exec 会用Java进程替换当前的shell进程,这样Java就是PID 1,一直在前台跑着。
用AI辅助排K8s的正确姿势
试了这两个场景之后,我总结了一套流程:
kubectl get pods -A | grep -E 'CrashLoop|Error|Init:'
kubectl describe pod <pod-name> -n <ns>
kubectl logs --previous <pod-name> -n <ns>
拿到这些信息后,AI能帮你做什么:
能做的:
- 解释exit code含义(137=OOM Kill,0=正常退出,1=应用报错)
- 根据describe信息给出排查方向
- 给出修复方案的YAML示例
不能做的:
- 直接连接你的集群去describe(目前的工具做不到)
- 分析业务层面的错误(私有中间件的特殊错误码)
- 给出100%准确的修复方案(最终要靠你自己理解)
给AI的信息越原始越好,直接把 describe、logs 的原始输出贴给它,不要自己总结转述。自己总结经常会漏掉关键信息。
说个大实话
CrashLoopBackOff的排查,本质上只有三件事:
1. 看exit code — 被杀的(137)还是自己退的(0)还是报错的(1-128)
2. 看Events — 有没有OOMKilling、BackOff、探针失败的记录
3. 看日志 — 应用层面的报错信息
这三个信息拿到手,90%的原因就能定位到。AI能帮你加速的是第1步(解释退出码含义)和第3步(分析日志中的异常栈)。
但第2步,看懂Events、关联上下文、确认根因,这个还得靠你自己的经验。
AI在标准化排障上已经能帮你省一半时间。但它给的信息,你要自己验证。毕竟是你在管集群,不是AI。
⚠️ 安全提醒:本文所有排查思路仅供参考。生产环境操作前请确认影响范围,涉及deployment修改、删除Pod等操作,建议先在测试环境验证。
E N D
运维少年 · 科技观察
夜雨聆风