Kubernetes 里最常见的一种状态就是 CrashLoopBackOff:Pod 启动、崩溃、重启,然后再次崩溃,循环往复。它本身不是错误原因,而是一个症状。要修好它,必须先找出容器为什么起不来。
常见根因速查
| 现象 | 最可能原因 | 优先排查命令 |
|---|---|---|
| 启动几秒后退出 | 应用启动报错、配置缺失 | kubectl logs --previous |
状态 OOMKilled |
内存限制太小 | kubectl describe pod |
一直 ImagePullBackOff |
镜像名/标签写错或鉴权失败 | kubectl describe pod |
| 健康检查失败 | 探针路径/端口配置错误 | kubectl get events |
四步排错法
1. 看日志,优先加上 –previous
容器已经崩溃时,当前日志可能是空的,必须用 --previous 看上一次运行的日志。
kubectl logs deployment/myapp --previous
kubectl logs -p pod/myapp-xxx-yyy
2. 用 describe 看事件和退出码
kubectl describe pod 会显示 Last State 和 Exit Code,对判断是应用报错还是资源不足非常关键。
kubectl describe pod myapp-xxx-yyy | grep -A 5 "Last State"
3. 检查资源限制
如果 Exit Code: 137,基本就是 SIGKILL,多半来自 OOM。把 memory limit 调大,或优化应用内存。
kubectl get pod myapp-xxx-yyy -o yaml | grep -A 4 resources
4. 本地复现镜像
把相同镜像在本地用同样的 entrypoint 启动一次,是最快的验证方式:
docker run --rm -it your-image:latest
踩坑实录
之前给一个 Spring Boot 服务写 Deployment,参考网上示例把 resources.limits.memory 设成了 128Mi。镜像启动后立刻 CrashLoopBackOff,kubectl logs --previous 只看到 JVM 报 OutOfMemoryError: Java heap space。
我一开始以为是代码内存泄漏,花了半小时看 heap dump。后来执行 kubectl describe pod 发现:
Last State: Terminated
Reason: OOMKilled
Exit Code: 137
原来是限制给得太低。把 limit 从 128Mi 调到 512Mi,Pod 稳定运行。这个坑说明:日志里看到的报错不一定反映真实原因,describe 里的 Reason 往往更直接。
让容器稳定运行的配置建议
- 合理设置 requests 和 limits。 requests 用来调度,limits 是硬顶。给得太低会被 OOM,给得太高浪费资源。
- 不要随便复制探针配置。 网上很多示例把
initialDelaySeconds设得很短,应用还没启动完就被判为不健康。 - 滚动更新前先做副本数冗余。 用
minReadySeconds和maxSurge控制更新节奏,避免新版本崩溃导致服务全挂。
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
常见问题
Q:CrashLoopBackOff 会一直重启吗?
A:会,但重启间隔会指数退避,最长可能到 5 分钟。修好后第一次启动成功,状态就会恢复正常。
Q:怎么看容器是不是被 OOMKilled?
A:kubectl describe pod 里 Last State 显示 Reason: OOMKilled,且 Exit Code: 137。
Q:应用日志正常但状态还是 CrashLoopBackOff?
A:检查 entrypoint 是否执行完就退出。容器里必须有一个长期运行的前台进程,否则 Kubernetes 认为它结束了。
你在 K8s 排障时还遇到过哪些奇怪的 CrashLoopBackOff 场景?欢迎在 fenij.com 留言交流。