乐于分享
好东西不私藏

我用AI排了一个K8s CrashLoopBackOff,20分钟缩到3分钟

我用AI排了一个K8s CrashLoopBackOff,20分钟缩到3分钟
运维少年 · 科技观察

上周五晚,刚准备下班。

群里@我:"生产环境几个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 podEvents 字段看到记录,比如 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

运维少年 · 科技观察