Kubernetes 排障手册:Pod 起不来的 10 种状态与定位路径
Pod 起不来时,kubectl get pods 只会给一行状态词。这行词背后可能是调度失败、镜像拉取失败、探针配置错误、资源超限,也可能是应用自己崩了。这篇按状态词组织,每个给出判断命令和最常见的根因。
第一层:Pod 还没被调度
1. Pending
**含义**:调度器找不到合适的节点。
**判断**:
kubectl describe pod <name> | grep -A 10 Events
**常见根因**:
| Events 里的关键词 | 根因 |
|---|---|
| Insufficient cpu / memory | 节点资源不足 |
| node(s) had taint | 节点有污点,Pod 没有 toleration |
| node(s) didn't match node selector | nodeSelector 写错 |
| node(s) didn't match Pod's node affinity | affinity 规则过严 |
| persistentvolumeclaim not found | PVC 不存在 |
| pod has unbound immediate PersistentVolumeClaims | PVC 没有绑定 PV |
**快速验证**:
# 看节点剩余资源
kubectl describe nodes | grep -A 5 "Allocated resources"
# 看节点污点
kubectl get nodes -o json | jq '.items[] | {name: .metadata.name, taints: .spec.taints}'
第二层:调度了但容器起不来
2. ImagePullBackOff / ErrImagePull
**含义**:镜像拉不下来。
**判断**:
kubectl describe pod <name> | grep -A 5 "Failed"
**四种根因**:
1. **镜像名或 tag 拼错** —— 最常见。注意 `latest` 在某些仓库被禁用
2. **私有仓库没有 imagePullSecrets**
3. **仓库凭证过期**
4. **节点无法访问仓库**(内网环境、防火墙)
**验证镜像是否可拉**:
# 在节点上直接试
crictl pull <image>
# 或
docker pull <image>
**修复私有仓库**:
kubectl create secret docker-registry regcred \
--docker-server=<registry> \
--docker-username=<user> \
--docker-password=<pass>
# Pod spec 里引用
imagePullSecrets:
- name: regcred
3. CreateContainerConfigError
**含义**:容器配置有问题,通常是引用的 ConfigMap/Secret 不存在。
**判断**:
kubectl describe pod <name> | grep -i "configmap\|secret\|error"
**常见根因**:
- ConfigMap 名字拼错
- Secret 在错误的 namespace(Secret 不能跨 namespace 引用)
- 引用的 key 不存在
**验证**:
kubectl get configmap <name> -n <ns>
kubectl get secret <name> -n <ns> -o jsonpath='{.data}'
4. RunContainerError
**含义**:容器创建成功但启动进程失败。
**判断**:
kubectl logs <name> --previous
**常见根因**:
- entrypoint 或 command 写错
- 镜像里没有该可执行文件
- 工作目录不存在
第三层:容器起来了但反复退出
5. CrashLoopBackOff
**含义**:容器启动后崩溃,kubelet 按指数退避重启(10s → 20s → 40s ... 最多 5 分钟)。
**判断顺序**:
# 1. 看当前日志
kubectl logs <name>
# 2. 看上次崩溃前的日志(关键)
kubectl logs <name> --previous
# 3. 看退出码
kubectl describe pod <name> | grep "Last State"
**退出码对照**:
| 退出码 | 含义 |
|---|---|
| 0 | 正常退出(说明进程跑完就结束了,可能是配置成 Job 而不是 Deployment) |
| 1 | 应用错误(最常见,看日志) |
| 137 | SIGKILL,通常是被 OOMKilled 或超时 |
| 143 | SIGTERM,被优雅终止 |
| 139 | 段错误 |
**最容易忽略的**:退出码 0 的 CrashLoop —— 应用正常运行完就退出了。这说明它本该是 Job/CronJob,不是 Deployment。
6. OOMKilled
**含义**:容器内存超过 limit 被杀。
**判断**:
kubectl describe pod <name> | grep -A 3 "Last State"
# 输出里会有 Reason: OOMKilled
**根因分析**:
# 看实际用了多少
kubectl top pod <name>
# 看 limit 设置
kubectl get pod <name> -o jsonpath='{.spec.containers[*].resources}'
**注意 JVM 类应用的坑**:容器 limit 是 512Mi,但 JVM 默认堆按宿主机内存算,可能开到 2G,直接被 kill。必须显式设置:
-XX:MaxRAMPercentage=75.0
7. Terminating(卡住不消失)
**含义**:Pod 收到删除请求但无法终止。
**判断**:
kubectl get pod <name> -o jsonpath='{.metadata.deletionTimestamp}'
kubectl describe pod <name> | grep -i finalizer
**三种根因**:
1. **finalizer 未清理**(最常见)
2. **preStop hook 卡住**
3. **节点失联**(NotReady 节点的 Pod 无法正常删除)
**强制删除(慎用)**:
kubectl delete pod <name> --grace-period=0 --force
强制删除后如果 Pod 仍在,说明是 API Server 与 kubelet 状态不一致,需要清理 etcd 里的记录或重启 kubelet。
第四层:Pod Running 但不可用
8. Running 但 READY 0/1
**含义**:容器在跑,但 readinessProbe 没通过,所以不接收流量。
**判断**:
kubectl describe pod <name> | grep -A 5 "Readiness"
**常见根因**:
| 现象 | 根因 |
|---|---|
| connection refused | 应用还没开始监听,initialDelaySeconds 太短 |
| HTTP 404 | probe 路径写错 |
| timeout | 应用响应慢,timeoutSeconds 太小 |
| 一直失败但应用正常 | probe 端口写错(写成了容器端口而非应用端口) |
**调试技巧**:
# 进容器手动测探针
kubectl exec -it <name> -- curl -v localhost:8080/health
9. Evicted
**含义**:节点资源压力大,kubelet 驱逐了 Pod。
**判断**:
kubectl describe pod <name> | grep -i "evict\|pressure"
kubectl get events --field-selector reason=Evicted
**根因**:节点磁盘、内存或 PID 达到驱逐阈值。
**验证**:
kubectl describe node <node> | grep -A 8 "Conditions"
# 看 MemoryPressure / DiskPressure / PIDPressure
10. Completed(意外完成)
**含义**:容器正常退出且不需要重启(restartPolicy: OnFailure 或 Never)。
**问题**:如果这是 Deployment 的 Pod,说明配置错了 —— Deployment 期望长期运行。
**修复**:改用 Job 或 CronJob。
三层排查顺序
遇到 Pod 异常,按这个顺序查,能覆盖 90% 情况:
# 第 1 层:状态和事件
kubectl get pod <name> -o wide
kubectl describe pod <name> # 看 Events 段落
# 第 2 层:日志
kubectl logs <name>
kubectl logs <name> --previous # 崩溃前的日志
# 第 3 层:进容器
kubectl exec -it <name> -- sh
kubectl debug -it <name> --image=busybox
一张速查表
| 状态 | 第一命令 | 最常见根因 |
|---|---|---|
| Pending | describe 看 Events | 资源不足 / 污点 / PVC |
| ImagePullBackOff | describe 看 Failed | 镜像名错 / 无凭证 |
| CreateContainerConfigError | describe 看 error | ConfigMap/Secret 缺失 |
| CrashLoopBackOff | logs --previous | 应用报错 / 退出码 0 |
| OOMKilled | describe 看 Last State | limit 太小 / JVM 堆 |
| Terminating | 看 finalizer | finalizer 未清理 |
| READY 0/1 | describe 看 Readiness | 探针配置错误 |
| Evicted | get events | 节点资源压力 |
小结
Pod 排障的核心不是记住 10 种状态,而是理解**三个阶段**:
1. **调度阶段**(Pending)—— 资源、亲和性、PVC
2. **启动阶段**(ImagePull / ConfigError / RunContainerError)—— 镜像、配置、命令
3. **运行阶段**(CrashLoop / OOM / Probe / Evicted)—— 应用、资源、健康检查
每个阶段的排查工具不同:调度看 Events,启动看 describe,运行看 logs。
真正省时间的做法是**先看 describe 的 Events 段落**——它直接告诉你 kubelet 的判断,比猜快得多。
- 点赞
- 收藏
- 关注作者
评论(0)