Kubernetes CrashLoopBackOff 排查全流程:从 describe 到日志到 exit code

Kubernetes CrashLoopBackOff 排查全流程:从 describe 到日志到 exit code

线上发个版,Pod 状态突然变成 CrashLoopBackOff,重启次数噌噌往上涨,服务 502。这几乎是每个用 K8s 的人都会撞上的场景。很多人第一反应是 kubectl delete pod 让它重建------但如果是配置或代码问题,重建再多次也是白搭,反而把现场删没了。

这篇按「看状态 → 看事件 → 看日志 → 看退出码」的顺序,把排查流程走一遍,每一步该敲什么命令、看什么关键字,讲清楚。

先搞懂 CrashLoopBackOff 是什么

它不是一种错误,而是一种状态 :容器启动 → 崩溃退出 → kubelet 按退避策略(10s、20s、40s......最长 5min)等一会儿再重启 → 又崩。BackOff 指的就是这个越来越长的重启间隔。

所以 CrashLoopBackOff 只告诉你「容器起来就挂」,真正的原因藏在崩溃的那一下。排查的核心是抓住崩溃瞬间的信息

第一步:kubectl get + describe 看全貌

bash 复制代码
# 看重启次数和状态,RESTARTS 高且在涨就是它
kubectl get pod -n myns

# 关键:describe 看 Events 和上一次容器的退出状态
kubectl describe pod my-app-7d9f -n myns

describe 输出里盯三个地方:

text 复制代码
Last State:     Terminated
  Reason:       Error
  Exit Code:    1               # ← 退出码是最重要的线索
  Started:      ...
  Finished:     ...
State:          Waiting
  Reason:       CrashLoopBackOff

底部的 Events 区域也要看,像镜像拉不下来(ErrImagePull)、探针失败(Liveness probe failed)、OOM 都会在这里留痕。

第二步:退出码直接缩小范围

Exit Code 是判断方向最快的信号,几个高频值背下来:

Exit Code 含义 常见原因
0 正常退出 容器主进程跑完就退了(比如把一次性脚本当常驻服务)
1 应用异常 代码抛未捕获异常、配置读不到
137 被 SIGKILL(128+9) OOMKilled 内存超限,或 liveness 探针杀的
143 被 SIGTERM(128+15) 优雅关闭,通常是被正常调度掉
126/127 命令不可执行/找不到 entrypoint 路径错、脚本没加执行权限

看到 137 别急着改代码,先确认是不是内存的事:

bash 复制代码
kubectl describe pod my-app-7d9f -n myns | grep -i oom
# 输出 Reason: OOMKilled 就实锤了内存超限

第三步:看日志,重点是「上一个」容器的日志

这是最容易踩的坑。Pod 已经重启了,kubectl logs 默认给你的是当前这个 容器的日志------它可能刚起来还没崩,啥也看不到。真正有价值的是崩掉的那个容器:

bash 复制代码
# -p / --previous 看上一个已终止容器的日志,这才是崩溃现场
kubectl logs my-app-7d9f -n myns --previous

# 多容器 Pod 要指定容器名
kubectl logs my-app-7d9f -n myns -c app --previous

崩溃日志里通常直接写着原因:数据库连不上、环境变量缺失、端口被占、配置文件解析失败。绝大多数 Exit Code 1 都能在 --previous 日志里找到根因。

第四步:如果日志也是空的

有些容器崩得太快,--previous 也捞不到东西(比如 entrypoint 直接报错、进程秒退)。这时换思路,让容器别崩,进去手动跑:

yaml 复制代码
# 临时把 command 覆盖成 sleep,让 Pod 能起来供你调试
apiVersion: v1
kind: Pod
metadata:
  name: debug-app
spec:
  containers:
  - name: app
    image: myrepo/my-app:v1.2.3   # 用出问题的同一个镜像
    command: ["sh", "-c", "sleep 3600"]   # 覆盖原 entrypoint,先撑住
bash 复制代码
kubectl apply -f debug-app.yaml
kubectl exec -it debug-app -- sh
# 进去后手动执行原来的启动命令,报错就直接打在你眼前
/app/entrypoint.sh

这招能把「容器秒崩看不到日志」变成「命令行里直接报错」,屡试不爽。

高频根因对照

排查多了会发现,CrashLoopBackOff 翻来覆去就那么几类:

  • 配置缺失 :ConfigMap/Secret 没挂上,或 key 名写错,应用读不到必需配置直接退。kubectl describeEnvironmentMounts 能对一遍。
  • 依赖没就绪:启动时强连数据库/Redis,连不上就 panic。正确做法是加重试或用 initContainer 探测依赖。
  • liveness 探针太激进 :应用启动慢(比如 JVM 预热),但 initialDelaySeconds 给太短,还没起来就被探针判死重启。表现是日志正常却反复重启,Events 里有 Liveness probe failed。改大 initialDelaySeconds 或改用 startupProbe
  • OOMKilled(137) :limits.memory 给低了,或应用真漏内存。先把 limit 调合理,再排查是不是真泄漏。
  • 把一次性任务当服务跑(Exit 0):脚本跑完就退,Deployment 又拉起来。这种应该用 Job 而不是 Deployment。

小结

CrashLoopBackOff 排查记住这条链路:

  • kubectl get pod 确认重启在涨 → kubectl describe podExit CodeEvents
  • 退出码先分方向:137 查 OOM,1 查应用异常,126/127 查启动命令。
  • kubectl logs --previous 才是崩溃现场,别看当前容器日志。
  • 日志也捞不到,就用 command: sleep 覆盖 entrypoint,进容器手动跑复现。

一句话记忆点:别急着 delete pod,先 describe 看退出码、logs 加 --previous 看崩溃现场------删了就没现场了。

相关推荐
冰封之寂2 小时前
Docker 部署与基础命令详解:从安装到容器管理全流程指南
linux·运维·docker·容器
Baron X2 小时前
Gitea Docker 部署教程
docker·gitea
隔振消音专家2 小时前
冷水机组振动传导影响及专业化减振适配治理方案
大数据·运维
Brilliantwxx2 小时前
【Linux】 软件包管理器(yum)+ Vim使用
linux·运维·服务器·开发语言·编辑器·vim
skywalk81632 小时前
在FreeBSD的Uubntu兼容环境下安装Reasonix
linux·运维·freebsd
^yi2 小时前
【Linux系统编程】对操作系统的理解
linux·运维·服务器·操作系统·系统调用·os
Kina_C3 小时前
LVS-NAT 负载均衡实验从环境搭建到规则持久化
linux·运维·服务器·负载均衡·lvs
Cloud云卷云舒3 小时前
AI Agent记忆系统:分层记忆体系的技术架构与实践
云原生·ai-native·haishandb
Android洋芋3 小时前
PrintFriendly网页文章转PDF插件工具及技术分析
运维·服务器·pdf·网页转pdf