4. Pod 故障域:Pod 生命周期与状态机
Pod 是 Kubernetes 中最小的调度与故障单元。理解 Pod 的状态机转换,是定位容器级故障的前提。本章从架构视角拆解 Pending → Running → Failed 的完整路径,并重点分析 Sidecar 模式下的多容器故障隔离策略。
4.1 Pod 状态机与故障注入点
Pod 的状态由 status.phase 字段定义,共 5 个阶段。SRE 排错时,需要根据当前阶段快速定位故障域:
| Phase | 含义 | 常见故障原因 | kubectl debug 切入点 |
|---|---|---|---|
| Pending | Pod 已被 API Server 接受,但尚未调度或镜像拉取中 | 资源不足、PVC 绑定失败、镜像不存在、节点选择器不匹配 | kubectl describe pod 查看 Events |
| Running | 至少一个容器正在运行,或正在启动/重启 | 容器 CrashLoopBackOff、Readiness 探测失败、OOMKill | kubectl logs --previous + kubectl exec |
| Succeeded | 所有容器正常退出(退出码 0) | Job 完成,通常无需排错 | — |
| Failed | 至少一个容器以非零退出码终止 | 应用崩溃、配置错误、资源耗尽 | kubectl logs --tail=50 + 查看 exit code |
| Unknown | 节点失联或 kubelet 未上报状态 | 节点宕机、网络分区、kubelet 挂死 | kubectl get node + 节点级排查 |
排错黄金法则: 先看
kubectl get pod -o wide 确认 Pod 所在节点与 IP,再用 kubectl describe pod 检查 Conditions 与 Events 字段。80% 的 Pending 故障在 Events 中直接暴露原因。
4.2 Pending 阶段:调度与初始化故障域
Pod 停留在 Pending 阶段,意味着调度器尚未将 Pod 分配到节点,或 kubelet 在启动容器前被阻塞。故障域分为两层:
- 调度层(Scheduler): 节点资源不足(CPU/Memory/GPU)、节点亲和性/反亲和性不满足、污点容忍度缺失、PVC 未绑定。
- 初始化层(kubelet): 镜像拉取失败(ImagePullBackOff)、Secret 不存在、卷挂载失败、Init 容器异常退出。
快速定位技巧: 使用
kubectl get events --field-selector involvedObject.name=<pod-name> --sort-by=.lastTimestamp 按时间排序事件,第一条 Warning 事件通常就是根因。
4.3 Running 阶段:容器运行时故障域
Pod 进入 Running 阶段后,故障域从调度层转移到容器运行时层。此时需要区分 临时故障 与 永久故障:
| 故障模式 | kubectl 观测指标 | 典型根因 | 隔离手段 |
|---|---|---|---|
| CrashLoopBackOff | kubectl logs --previous 显示退出码非 0 |
应用初始化失败、配置错误、依赖服务不可用 | 临时副本替换 + 保留旧 Pod 日志 |
| OOMKilled | kubectl describe pod 显示 OOMKilled 状态 |
内存 limit 设置过小、内存泄漏 | 调整 resources.limits.memory |
| Readiness 探测失败 | Pod 状态 Running 但 Ready 列为 0/1 | 应用未就绪、健康检查路径错误 | kubectl exec 手动探测端点 |
| Liveness 探测失败 | Pod 频繁重启,restarts 计数递增 | 应用死锁、goroutine 泄漏、死循环 | 临时关闭探测 + 抓取堆栈 |
4.4 Pod 生命周期状态机 SVG
下图展示了 Pod 从创建到终止的完整状态转换路径,以及每个阶段对应的故障注入点:
4.5 Pod 内多容器故障隔离:Sidecar 模式
生产环境中,Pod 内常包含多个容器(Sidecar 模式),例如日志采集、指标暴露、网络代理等辅助容器。多容器共享同一网络命名空间与存储卷,但 故障域相互独立。
4.6 Sidecar 故障隔离原则
- 进程级隔离: 每个容器拥有独立的 PID 命名空间(默认不共享),一个容器的 OOM 或崩溃不会直接杀死其他容器。
- 资源隔离: 每个容器独立设置
resources.requests/limits,Sidecar 的 CPU 争抢不会导致主容器饥饿。 - 健康检查独立: Liveness/Readiness 探测按容器配置,Sidecar 挂死不影响主容器的 Ready 状态(除非自定义 Readiness 聚合)。
- 日志与监控隔离: 使用
kubectl logs -c <container-name>按容器过滤日志,避免 Sidecar 日志淹没主容器错误。
常见陷阱: 部分团队将 Sidecar 与主容器放在同一个
securityContext 下,或错误地共享 shareProcessNamespace: true,导致 Sidecar 崩溃后主容器也被迫重启。除非明确需要进程间通信,否则不要开启进程命名空间共享。
4.7 多容器故障隔离 SVG
下图展示了 Sidecar 模式下,主容器与辅助容器的故障隔离边界:
4.8 Sidecar 故障场景与排错命令
| 故障场景 | 现象 | 排错命令 | 隔离效果 |
|---|---|---|---|
| Sidecar OOMKilled | 主容器正常运行,Sidecar 不断重启 | kubectl logs -c sidecar --previous |
主容器无影响,仅 Sidecar 重启 |
| Sidecar 死锁导致 Liveness 失败 | Sidecar 被 kubelet 重启,主容器不受影响 | kubectl describe pod 查看 Sidecar 容器状态 |
主容器继续服务,Sidecar 自动恢复 |
| 主容器崩溃退出 | Pod 进入 CrashLoopBackOff,Sidecar 也被迫停止 | kubectl logs --previous -c main |
Pod 整体重启,Sidecar 随 Pod 重建 |
| Sidecar 日志阻塞磁盘 | 主容器写日志失败,但进程未崩溃 | kubectl exec -c sidecar -- df -h |
共享卷写满,影响所有容器 |
架构建议: 对于关键 Sidecar(如 Istio Proxy、日志采集器),应设置独立的
resources.requests 与 resources.limits,并配置 restartPolicy: Always。同时使用 kubectl top pod --containers 按容器维度监控资源消耗,避免 Sidecar 资源泄漏影响主容器。
4.9 排错流程总结
- 确定 Pod Phase:
kubectl get pod <name> -o jsonpath='{.status.phase}' - 检查 Events:
kubectl describe pod <name> | grep -A 10 Events - 按容器过滤日志:
kubectl logs <name> -c <container> --tail=100 - 检查容器退出码:
kubectl get pod <name> -o jsonpath='{.status.containerStatuses[*].state.terminated.exitCode}' - 资源隔离验证:
kubectl exec -c main -- cat /sys/fs/cgroup/memory/memory.limit_in_bytes - 网络隔离验证:
kubectl exec -c sidecar -- curl localhost:8080/healthz
生产级排错技巧: 在 Sidecar 容器中预装
curl、tcpdump、strace 等调试工具,并暴露一个专用的调试端口(如 10001),避免在主容器中安装额外二进制。使用 kubectl debug -c sidecar --image=nicolaka/netshoot:latest --target=sidecar 启动临时调试容器,不污染生产容器。