title: Kubernetes Pod 排障决策树:CrashLoopBackOff / ImagePullBackOff / Pending 五步定位法
description: K8s 生产环境 Pod 常见问题排障:CrashLoopBackOff 根因分析、ImagePullBackOff 镜像拉取失败、Pending 调度失败、OOMKilled 内存超限、Service 不可达。附 kubectl 诊断命令速查表和六个翻车案例。
tags: [kubernetes, k8s, troubleshooting, pod, crashloop, ops]
lang: zh
date: 2026-10-22
original: true
answer: |
K8s Pod 排障核心是"分层定位":先看 Events 看调度问题,再看 Logs 看应用崩溃,最后看 Describe 看资源限制。
五个最常见状态:CrashLoopBackOff(应用崩了)、ImagePullBackOff(镜像拉不到)、Pending(调度不上)、OOMKilled(内存超了)、ContainerCreating(启动中卡住)。
kubectl describe pod 和 kubectl logs --previous 是最快定位工具。
faq:
- q: Pod 一直 CrashLoopBackOff 怎么办?
a: 三步:① kubectl logs <pod> --previous 看上一次崩溃的日志;② kubectl describe pod 看 Events 里有没有 OOMKilled 或 Exit Code;③ 检查环境变量、ConfigMap、Secret 是否配置正确。
最常见原因:应用启动命令写错、缺少必要环境变量、资源 limit 设太小导致 OOM。
- q: ImagePullBackOff 和 ErrImagePull 有什么区别?
a: ImagePullBackOff 是"重试拉取中",ErrImagePull 是"最后一次拉取失败"。
前者通常是网络问题或镜像仓库限流(Docker Hub 未登录每分钟 100 次),后者通常是镜像名/标签写错或私有仓库认证失败。
修复:检查 image name 拼写,私仓加 imagePullSecrets,国内用镜像加速器。
- q: Pod 一直 Pending 怎么排查?
a: kubectl describe pod 看 Events,常见原因三选一:① 资源不足(Insufficient cpu/memory)→ 扩节点或减 request;
② NodeSelector/Affinity 不匹配 → 检查 label;③ PVC 未绑定 → 检查 StorageClass 和 PV 是否存在。
- q: OOMKilled 后怎么调内存 limit?
a: 先看应用实际峰值:kubectl top pod 看当前 usage,然后 limit 设成峰值的 1.5 倍。
Java 应用特别注意:Xmx 要小于 container limit,否则 JVM 还没启动就被 OOM Kill 了。
长期方案:Profile 内存泄漏,而不是盲目加 limit。
- q: kubectl 命令怎么快速诊断 Pod 问题?
a: 五步法:① kubectl get pods 看状态;② kubectl describe pod <name> 看 Events;
③ kubectl logs <pod> 看应用日志;④ kubectl logs <pod> --previous 看上一次崩溃日志;
⑤ kubectl exec -it <pod> -- sh 进容器调试。这五步覆盖 90% 的问题。
Kubernetes Pod 排障决策树:CrashLoopBackOff / ImagePullBackOff / Pending 五步定位法
生产环境凌晨 2 点收到 K8s Pod CrashLoopBackOff 告警,这种场景每个运维都经历过。问题不是"怎么重启",而是"为什么崩"。这篇把 K8s Pod 最常见的五种故障状态拆解清楚,给你一个五步定位法,下次遇到不再慌。
五种最常见 Pod 状态
| 状态 | 含义 | 最常见原因 |
|---|---|---|
CrashLoopBackOff |
容器反复崩溃重启 | 应用代码异常、环境变量缺失、资源不足 OOM |
ImagePullBackOff |
拉取镜像重试中 | 镜像名错误、私有仓库认证失败、网络问题 |
Pending |
调度器无法分配节点 | 资源不足、NodeSelector 不匹配、PVC 未绑定 |
OOMKilled |
内存超限被杀 | limit 设太小、内存泄漏 |
ContainerCreating |
启动中卡住 | 挂载卷权限、镜像拉取慢、Init Container 失败 |
下面按这个顺序排查。
第一步:看 Events —— 调度问题先看这里
重点看底部的 Events 区域:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning Failed 2m default-scheduler 0/3 nodes are available: 3 Insufficient memory.
Warning FailedMount 1m mounter Unable to attach or mount volumes: pvc-xxx not found
常见 Events 解读:
Insufficient memory/cpu→ 节点资源不够,扩集群或减小 requestFailedScheduling→ NodeSelector/Affinity 不匹配,检查 labelFailedMount→ PVC 未绑定,检查 StorageClass 和 PVBack-off pulling image→ 镜像拉取失败,检查网络和认证
第二步:看 Logs —— 应用崩溃先看日志
# 当前运行容器的日志
kubectl logs <pod-name> -n <namespace>
# 上一次崩溃容器的日志(CrashLoopBackOff 必备)
kubectl logs <pod-name> -n <namespace> --previous
# 多容器 Pod 指定容器
kubectl logs <pod-name> -c <container-name> -n <namespace>
CrashLoopBackOff 常见日志特征:
# 环境变量缺失
Error: DATABASE_URL not found
at Object.<anonymous> (/app/server.js:12:11)
# 端口占用
Error: listen EADDRINUSE: address already in use 0.0.0.0:8080
# 权限问题
Error: EACCES: permission denied, open '/data/app.log'
# 依赖服务连不上
Error: connect ECONNREFUSED 10.0.0.5:5432
第三步:看 Describe —— 资源限制和配置
除了 Events,重点看:
Limits:
cpu: 500m
memory: 256Mi
Requests:
cpu: 250m
memory: 128Mi
Status: OOMKilled # ← 这里显示崩溃原因
Exit Code: 137 # ← 137 = SIGKILL = OOM
Exit Code 对照表:
| Code | 含义 | 排查方向 |
|---|---|---|
| 0 | 正常退出 | 可能是 readiness probe 失败 |
| 1 | 应用异常 | 检查日志 |
| 137 | OOMKilled | 增大 memory limit |
| 143 | SIGTERM | 正常终止,检查 Grace Period |
第四步:进容器 —— 手动调试
# 进入容器 shell
kubectl exec -it <pod-name> -n <namespace> -- sh
# 或者指定命令测试
kubectl run debug --rm -it --restart=Never --image=busybox -- sh
容器内常用调试命令:
# 测试网络连通性
curl -v http://backend:8080/health
# 检查环境变量
env | grep DATABASE
# 检查文件权限
ls -la /data
# 查看进程
ps aux
# 查看内存使用
free -h
第五步:查资源 —— 集群层面问题
# 查看节点资源
kubectl top nodes
# 查看 Pod 资源使用
kubectl top pods -n <namespace>
# 查看资源配额
kubectl describe quota -n <namespace>
# 查看 Namespace 限制
kubectl describe namespace <namespace>
五个实战场景
场景 A:CrashLoopBackOff —— 环境变量缺失
# 现象
kubectl get pods
NAME READY STATUS RESTARTS AGE
backend-xyz123 0/1 CrashLoopBackOff 5 10m
# 排查
kubectl logs backend-xyz123 --previous
# 输出:Error: DATABASE_URL not found
# 修复
kubectl set env deployment/backend DATABASE_URL=postgres://...
# 或者更新 ConfigMap/Secret 后 rollout restart
kubectl rollout restart deployment/backend
场景 B:ImagePullBackOff —— 私有仓库认证
# 现象
Events:
Warning Failed 1m kubelet Failed to pull image "registry.example.com/app:v1.0": unauthorized: authentication required
# 修复
kubectl create secret docker-registry reg-cred \
--docker-server=registry.example.com \
--docker-username=user \
--docker-password=pass \
--docker-email=[email protected]
# 更新 Deployment
kubectl patch deployment backend -p '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"reg-cred"}]}}}}'
场景 C:Pending —— 资源不足
# 现象
Events:
Warning FailedScheduling 2m default-scheduler 0/3 nodes are available: 3 Insufficient memory.
# 修复方案一:减小 request
kubectl patch deployment backend -p '{"spec":{"template":{"spec":{"containers":[{"name":"backend","resources":{"requests":{"memory":"128Mi"}}]}}}}}'
# 修复方案二:扩容节点
kubectl scale nodes 3 → 5
# 修复方案三:清理不用的 Pod
kubectl delete pods --field-selector status.phase!=Running
场景 D:OOMKilled —— 内存超限
# 现象
kubectl describe pod
Last State: Terminated
Reason: OOMKilled
Exit Code: 137
# 短期修复:增大 limit
kubectl set resources deployment/backend -c backend --limits=memory=512Mi
# 长期修复:Profile 内存泄漏
# Java: jmap -heap <pid>
# Python: import tracemalloc
场景 E:Service 不可达
# 现象
kubectl logs backend
# Error: connect ECONNREFUSED 10.96.0.10:5432
# 排查 Service
kubectl get svc
kubectl describe svc postgres
kubectl get endpoints postgres
# 常见问题:
# 1. Service 没有 Endpoints(Pod 没 Ready)
# 2. Selector 不匹配
# 3. Namespace 不同
# 修复
kubectl get pods -l app=postgres
kubectl describe pod postgres-xxx # 看 Readiness Probe
翻车案例复盘
案例 1:Resource Quota 限制导致 Pod 起不来
现象:Deployment 正常,但 Pod 一直 Pending。
根因:Namespace 有 Resource Quota,memory request 总和超过配额。
修复:
kubectl describe quota -n production
# 看到 memory request: 10Gi, used: 9.8Gi
kubectl edit quota main-quota -n production
# 调大配额或减小 Pod request
案例 2:Init Container 失败导致主容器不启动
现象:Pod 一直处于 ContainerCreating,日志无输出。
根因:Init Container 执行失败,主容器不会启动。
排查:
修复:修复 init container 的配置或依赖服务。
案例 3:liveness probe 过于激进导致 Pod 反复重启
现象:Pod 每 30 秒重启一次,但应用正常运行。
根因:liveness probe 的 timeout 设太短,应用偶尔慢响应就被判不健康。
修复:
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 60 # 给应用启动时间
periodSeconds: 30
timeoutSeconds: 10 # 放宽超时
failureThreshold: 3 # 允许 3 次失败
案例 4:ConfigMap 更新后 Pod 不生效
现象:更新 ConfigMap 后,Pod 还是用旧配置。
根因:ConfigMap 挂载是只读的,需要重启 Pod 才能加载新配置。
修复:
案例 5:PVC 绑定失败导致 Pod Pending
现象:Pod 一直 Pending,Events 显示 storageclass "fast-ssd" not found。
根因:StorageClass 名称写错或删除了。
修复:
kubectl get storageclass
# 确认正确的 StorageClass 名称
kubectl patch pvc data-pvc -p '{"spec":{"storageClassName":"standard"}}'
案例 6:Node Affinity 导致 Pod 无法调度
现象:只有 2 个节点符合 label,但需要 3 个 Pod。
根因:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
修复:增加带 disktype=ssd label 的节点,或改用 preferredDuringScheduling。
诊断命令速查表
| 问题 | 命令 |
|---|---|
| 看 Pod 状态 | kubectl get pods -A |
| 看具体 Pod 详情 | kubectl describe pod <name> -n <ns> |
| 看应用日志 | kubectl logs <pod> -n <ns> |
| 看上次崩溃日志 | kubectl logs <pod> --previous -n <ns> |
| 进容器调试 | kubectl exec -it <pod> -- sh |
| 看节点资源 | kubectl top nodes |
| 看 Pod 资源 | kubectl top pods -n <ns> |
| 重启 Deployment | kubectl rollout restart deployment/<name> |
| 回滚版本 | kubectl rollout undo deployment/<name> |
写在最后
K8s Pod 排障的核心思路是分层定位:
- 调度层:Pending → 看 Events → 资源/节点/存储问题
- 启动层:CrashLoop → 看日志 → 应用配置问题
- 运行层:OOM/超时 → 看资源 → 限制造型问题
- 网络层:Service 不可达 → 看 Endpoints → 选择器问题
记住五个命令:get、describe、logs、exec、top。这五个命令覆盖 90% 的排障场景。
最重要的是:不要只看报错就重启,先理解"为什么崩"。重启只能解决临时问题,找到根因才能防止复发。