
最近线上踩了个 CrashLoopBackOff 的坑,一查日志是 OOMKilled,内存配置少了 20MB 就把整个服务干掉了。这篇把常见原因和排查方法整理一下,下次遇到不用再抓瞎。
看到 kubectl get pods 显示 CrashLoopBackOff,这不是一个具体的错误,而是一种状态——容器挂了,Kubernetes 在等一会儿再重试。
为了避免进程瞬间崩溃把 API Server 和节点打挂,Kubernetes 实现了指数退避策略:第一次重启很快,后续失败会逐步增加等待时间(10秒、20秒、40秒,最大5分钟)。如果不去干预,Pod 大部分时间都在等待而不是运行,根本没法实时抓日志。
诊断 CrashLoopBackOff 需要从表象追溯到原因。在 50+ 节点的大集群里最常见,因为配置漂移很容易发生。根因大致分三个严重等级。
这类属于"快速失败"——应用启动了,发现缺了关键信息,直接退出。常见原因:
这类崩溃往往是间歇性的,或者在应用开始处理流量后才发生:
应用本身是健康的,但运行环境出了问题:
生产服务出现 CrashLoopBackOff 时,按这个优先级顺序排查,不要靠猜,用集群给的数据说话。
先看 Pod 状态和事件,判断崩溃是镜像问题、调度器问题还是应用本身的问题。
kubectl describe pod <pod-name>
重点看 Containers 部分的 Last State,里面的 Exit Code 是最关键的线索。
正常输出示例:
会看到这样的内容:
Last State: Terminated
Reason: Error
Exit Code: 137
根据 describe 得到的退出码,对应不同的处理方案:
如果 Pod 在不断崩溃,直接运行 kubectl logs <pod-name> 往往什么都没有,因为当前容器刚启动还没来得及打日志。必须查上一个失败实例的日志:
kubectl logs <pod-name> --previous
如果日志显示连接数据库超时,去检查网络策略或者 Secret 的值。如果想更快处理紧急回滚,可以用 kubectl set image 回滚到已知可用的镜像版本。
有时候日志是空的,退出码也很模糊。Kubernetes v1.23+ 可以用 kubectl debug 启动一个带调试工具的 sidecar 容器(比如 curl、dig、vim),它和崩溃的 Pod 共享同一个进程命名空间:
kubectl debug -it <pod-name> --image=busybox --target=<container-name>
进去之后可以检查 /tmp 目录、测试网络连通性、或者查看文件系统看配置文件有没有挂载错误。
预防的关键是从"出了问题再修"转向"提前加固"。这四个策略可以消除生产环境的 CrashLoopBackOff:
合理配置资源:用 Vertical Pod Autoscaler(VPA)的 Recommender 模式来获取应用的实际内存使用量。把 limits 设到 requests 的 120% 左右,留点余量应对流量高峰,避免触发 OOMKill
优雅配置探针:永远不要把 livenessProbe 和 readinessProbe 设成一样的超时时间。给应用一个覆盖最坏情况启动时间的 initialDelaySeconds。如果应用最慢需要 20 秒启动,就设 30 秒
正确处理信号:确保应用能处理 SIGTERM(退出码 143)。如果应用忽略这个信号,Kubernetes 会在 terminationGracePeriodSeconds 到期后强制用 SIGKILL(退出码 137)杀掉它
加强可观测性:如果跑的是 AI 工作负载,部署完整的监控方案能帮你判断崩溃是不是 GPU 内存耗尽或者模型加载超时导致的
修复了 ConfigMap 为什么 Pod 还是 CrashLoopBackOff?
Kubernetes 使用指数退避算法。如果 Pod 已经崩了好几次,下次重启可能要等最多 5 分钟。可以强制立即重启:kubectl delete pod <pod-name>
退出码 137 一定是 OOMKilled 吗?
绝大多数情况是,但不全都是。表示进程收到了 SIGKILL(信号 9)。虽然通常是 kubelet 在容器超内存时发送的,但也可能是外部进程或者节点的 OOM killer 杀掉的
怎么防止崩溃的 Pod 影响同一节点上的其他 Pod?
严格定义 resources.limits。没有内存限制的话,一个内存泄漏的容器可以吃光节点所有内存,触发节点级别的 OOM killer,导致不相关的 Pod 被驱逐
CrashLoopBackOff 是 Kubernetes 的安全保护机制,不是 bug。通过分析退出码和上一条日志,很快就能定位是配置错误、资源不足还是依赖失败。
要进一步加固生产环境,建议:
livenessProbes 配置,确保不会太激进--previous 猜