Skip to content
容器与编排异常排查 · 第 2 篇 / 共 2 篇
领域生产问题
专题数据与基础设施排障专题
当前序列容器与编排异常排查
阅读位置第 2 篇 / 共 2 篇当前专题第 3 个序列 / 共 5 个序列

Kubernetes CrashLoopBackOff 时怎么排查

CrashLoopBackOff 是 Kubernetes 里最容易让人紧张的一类告警,因为它看起来像:

  • Pod 起不来
  • 容器在反复重启
  • 服务副本数不断掉
  • 发布刚做完,线上就开始红

但它本身不是根因,而是一个结果:

  • 应用启动失败
  • 配置或依赖缺失
  • 探针配置不合理
  • 资源限制导致进程被杀
  • 启动阶段逻辑太重

真正难的不是知道它在“重启”,而是快速判断:

  • 是应用自己退了
  • 还是被 K8s 杀掉了
  • 是启动期问题
  • 还是运行后又进入坏状态

先说结论

  • CrashLoopBackOff 的第一目标不是“先修配置”,而是先判断容器为什么退出
  • 先区分是进程异常退出、OOMKilled、探针失败还是启动依赖没准备好
  • 再区分这是单 Pod 问题、同版本问题,还是发布导致的批量问题
  • 很多 CrashLoopBackOff 都不是调度问题,而是镜像、配置、探针、启动脚本和资源配置共同作用的结果

一个典型故障现场

一个典型场景是 Java 服务发版后,Pod 状态很快从 Running 变成:

  • CrashLoopBackOff
  • 重启次数快速累加
  • readiness 一直过不了
  • 同版本多个副本都不稳定

这时现场经常会有人同时做很多动作:

  • 重启 Pod
  • 扩容副本
  • 改探针
  • 怀疑节点坏了

但真正更有价值的是先看清:

  • 容器上一次退出码是什么
  • 是不是 OOMKilled
  • 探针失败发生在启动前、中还是后
  • 是否只有新版本在出问题

第一阶段:先止血,保护线上可用性

1. 如果是发版后批量出现,优先考虑暂停发布或回滚

这一步远比一边查一边继续放量更重要。

如果同版本副本都在 CrashLoop,说明问题很可能就在:

  • 新镜像
  • 新配置
  • 新探针
  • 新启动参数

2. 保住健康副本

如果老副本还活着,要避免:

  • 误删旧 Pod
  • 继续滚动导致可用副本继续减少

3. 暂时放宽探针或资源时要谨慎

这类动作只能作为诊断手段,不要直接把它当长期修复。

比如 startup 时间明显不够,可以临时放宽启动窗口帮助确认问题是否只是慢启动;但不能因为“放宽后能活”就忽略真正的启动过重问题。

第二阶段:先分清容器是怎么死的

1. 进程自己退出

常见于:

  • 配置文件缺失
  • 环境变量不对
  • 启动脚本报错
  • 应用初始化失败
  • 依赖连接失败后直接 exit

2. 被 OOMKilled

常见于:

  • JVM 参数过大
  • 启动时缓存预热、类加载、数据加载过重
  • limit 太小
  • 容器里还有额外 sidecar 争内存

3. 被 liveness 或 startup probe 反复杀掉

常见于:

  • 启动很慢但没配 startup probe
  • 探针 URL 本身依赖外部服务
  • 探针阈值照抄模板,不符合当前服务冷启动特性

4. 运行后进入坏状态再退出

这种情况最容易迷惑人,因为容器可能不是启动立刻死,而是跑几十秒、一两分钟后挂掉。

这时更要看:

  • 发布后是否有流量进入
  • 某些初始化任务是不是在启动后异步执行
  • 依赖连接是不是在服务接流量后才暴露问题

第三阶段:现场最该看的四样东西

1. 上一次退出原因和退出码

这是最先要看的,因为它决定排查方向。

如果退出码都没看,就开始猜探针、猜节点、猜镜像,效率会很低。

2. 容器最近日志和上一个实例日志

很多 CrashLoop 问题日志就摆在那里:

  • 配置读取失败
  • 端口冲突
  • 连接数据库失败
  • 初始化 SQL 报错
  • JVM 启动参数不兼容

3. 事件和探针失败信息

如果是探针导致,事件里通常能看到:

  • 连不上端口
  • HTTP 返回非 200
  • 超时
  • 启动窗口不足

4. 资源限制和节点资源

如果节点本身紧张、limit 太小、请求配置不合理,也可能让容器在启动阶段就被资源问题击穿。

常见根因画像

1. 配置中心、Secret、ConfigMap 变更不兼容

新版本起来后,读到的新配置和老版本逻辑不兼容,直接启动失败。

2. Java 服务冷启动变慢,但探针没同步调整

这在 Spring Boot、搜索、分析、缓存预热类服务里非常常见。

3. 镜像变更导致启动脚本或依赖缺失

比如 JDK、时区、字体、系统库、证书链、执行权限等问题。

4. 启动阶段依赖外部服务过多

数据库、Redis、注册中心、配置中心、第三方接口任何一个起不来,应用就直接退出。

5. OOM 或 limit 太紧

开发环境能跑,线上因为容器资源限制更严格,结果一启动就被杀。

一个更实用的排查顺序

CrashLoopBackOff 现场我通常按这个顺序看:

  1. 先确认是单 Pod、单节点、单版本,还是批量现象。
  2. lastState、退出码、是否 OOMKilled。
  3. 看当前日志和上一个实例日志。
  4. 看事件里是否有 probe 失败、挂载失败、拉取失败。
  5. 再看最近是否发版、改配置、改镜像、改资源参数。
  6. 最后才去怀疑节点层或集群层问题。

这样能避免把大量应用级问题误判成 Kubernetes 平台问题。

止血后的治理方向

1. 启动探针、存活探针、就绪探针职责分开

不要一个 /health 接口包打天下。

2. 慢启动服务单独评估启动窗口

尤其是 Java、搜索、分析、缓存预热型服务。

3. 发版前增加启动期验证

比如:

  • 配置完整性检查
  • 依赖连通性检查
  • 内存参数检查
  • 启动时间基线比对

4. 对外部依赖做“可降级启动”设计

不是所有依赖失败都应该让应用直接 exit

总结

CrashLoopBackOff 真正要解决的,不是“Pod 一直重启”这个表象,而是先分清:

  • 容器是自己退了,还是被杀掉了
  • 是启动阶段问题,还是运行阶段问题
  • 是应用问题,还是探针和资源配置问题

把“退出原因、日志、探针、资源、版本变更”这五条线先看清,绝大多数 CrashLoopBackOff 都能很快缩小到真正根因。

延伸阅读相关文章优先当前专题,再补跨专题关联。
同一序列 · 顺着当前主线继续读RabbitMQ 队列积压时怎么排查适合把 K8s、RabbitMQ 和数据库锁等待问题放在一条故障治理主线上看。数据与基础设施排障专题 · 基础设施与中间件故障案例同一序列 · 顺着当前主线继续读数据库死锁和锁等待超时案例怎么复盘适合把 K8s、RabbitMQ 和数据库锁等待问题放在一条故障治理主线上看。数据与基础设施排障专题 · 基础设施与中间件故障案例同专题其他序列 · 共享标签:线上排障、案例排障磁盘打满后为什么删除文件不一定立刻生效适合把 Redis 抖动、MySQL 连接打满、MQ 积压、ES 发黄、ClickHouse 合并堆积和磁盘打满放在同一条基础设施排障主线上看。数据与基础设施排障专题 · 数据与基础设施故障的分层排查同专题其他序列 · 共享标签:线上排障、案例排障磁盘打满时怎么排查适合把数据库连接、死锁、网关异常和磁盘空间问题放在一条排障线上看。数据与基础设施排障专题 · 数据库与网关故障排查跨专题关联 · 共享标签:线上排障、案例排障大 Header、buffer、timeout 问题怎么排查适合把 location 匹配、缓冲区和负载均衡放在一起看。容器与站点部署专题 · Nginx 进阶路由与代理治理跨专题关联 · 共享标签:线上排障、案例排障缓存穿透、击穿、雪崩与缓存一致性适合把缓存更新、击穿雪崩、回源策略和事务边界放到同一条缓存治理主线上看。Redis 专题 · Redis 缓存一致性与更新策略
继续阅读容器与编排异常排查当前序列第 2 篇 / 共 2 篇当前专题第 3 个序列 / 共 5 个序列
往前看
上一篇Kubernetes Pod Pending 时怎么排查回到当前序列上一章上一序列缓存、消息与检索故障排查从第 1 篇开始:Redis 热 Key 突增时怎么止血和回查
往后看
下一序列基础设施与中间件故障案例从第 1 篇开始:Kubernetes Pod Pending 时怎么排查

把零散经验整理成可查、可复用、可持续更新的企业级知识门户