Skip to content

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 —— 调度问题先看这里

kubectl describe pod <pod-name> -n <namespace>

重点看底部的 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 → 节点资源不够,扩集群或减小 request
  • FailedScheduling → NodeSelector/Affinity 不匹配,检查 label
  • FailedMount → PVC 未绑定,检查 StorageClass 和 PV
  • Back-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 —— 资源限制和配置

kubectl describe pod <pod-name> -n <namespace>

除了 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 执行失败,主容器不会启动。

排查:

kubectl logs <pod> -c init-migrate-db
# 看到数据库连接失败

修复:修复 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 才能加载新配置。

修复:

kubectl rollout restart deployment/backend

案例 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 排障的核心思路是分层定位:

  1. 调度层:Pending → 看 Events → 资源/节点/存储问题
  2. 启动层:CrashLoop → 看日志 → 应用配置问题
  3. 运行层:OOM/超时 → 看资源 → 限制造型问题
  4. 网络层:Service 不可达 → 看 Endpoints → 选择器问题

记住五个命令:get、describe、logs、exec、top。这五个命令覆盖 90% 的排障场景。

最重要的是:不要只看报错就重启,先理解"为什么崩"。重启只能解决临时问题,找到根因才能防止复发。