Kubernetes Pod 状态全解析:从 Phase 到 CrashLoopBackOff

一、理解状态之前,先理解 K8s 的"三层状态模型"

Kubernetes 中并不存在一个单一的"Pod 状态字段"能解释一切。API 对象 Podstatus 中同时维护着三套互相独立、互相补充的状态信息:

层级 API 字段路径 粒度 作用
第一层:Pod 阶段(Phase) status.phase Pod 级、宏观生命周期 描述 Pod 所处的生命周期大阶段,只有 5 个取值
第二层:容器状态(Container Statuses) status.containerStatuses[](含 statelastStatereadyrestartCount 容器级 描述每个容器的 Waiting / Running / Terminated 状态及原因(reason)
第三层:Pod 状况(Conditions) status.conditions[] Pod 级、面向可用性 描述 Pod 是否被调度、是否初始化完成、容器是否就绪、整体是否 Ready

而你在 kubectl get pod 里看到的 STATUS 列,并不是其中任何一个字段的原样输出,而是 kubectl 根据上述三层信息(外加 metadata.deletionTimestamp)现场推导出来的"显示状态"。这是理解一切的关键。

1.1 第一层:Pod Phase(status.phase)

官方定义的 Phase 只有 5 个取值,且刻意地保持粗粒度,它不试图描述细节,只回答"这个 Pod 大致处在生命周期的哪一段":

  1. Pending(挂起)

    集群已经接受该 Pod 对象(API 对象已创建),但 Pod 尚未进入 Running:可能还没被调度到节点,或者正在拉取镜像、挂载卷、创建容器。即:从对象创建成功到第一个容器开始运行之前的所有时间,都属于 Pending。

  2. Running(运行中)

    Pod 已经绑定到某个节点,所有容器均已创建完成,且至少有一个容器正在运行,或正在启动/重启过程中。注意:Running 不等于健康,也不等于对外提供服务(还要看 Ready)。

  3. Succeeded(成功)

    Pod 中所有容器都已成功终止(退出码 0),且不会再被重启。典型场景:Job、CronJob 的任务 Pod。

  4. Failed(失败)

    Pod 中所有容器都已终止,且至少有一个容器以失败方式终止(非 0 退出码,或被系统信号强制终止)。被驱逐(Evicted)的 Pod 其 Phase 也是 Failed。

  5. Unknown(未知)

    由于某种原因无法获取 Pod 的状态,通常是控制面与所在节点(kubelet)通信失败:节点宕机、kubelet 进程异常、网络分区等。

请注意 Phase 的两个重要特征:

  • Phase 之间不是严格的状态机,官方文档明确说明 Phase 不保证构成一个严密的状态转移图,它只是"高层概括";
  • Phase 不包含 TerminatingCrashLoopBackOffCompletedEvicted 这些天天在 kubectl 里看到的词------它们来自下面两层和推导逻辑。

1.2 第二层:容器状态(containerStatuses\[\].state)

每个容器在任意时刻必然处于三种状态之一:

  • Waiting(等待中) :容器尚未运行,正在做启动前的准备工作,或因为某种原因无法启动。waiting.reason 会给出具体原因,这是排查"起不来"问题的第一现场,例如 ContainerCreatingImagePullBackOffCrashLoopBackOffCreateContainerConfigError 等。
  • Running(运行中) :容器正在运行。startedAt 记录启动时间;若配置了启动探针/就绪探针,还会体现到 startedready 字段。
  • Terminated(已终止) :容器执行完毕或因某种原因退出。terminated.reason(如 CompletedErrorOOMKilled)、exitCodesignalfinishedAt 是判断"怎么死的"的核心证据。

此外还有两个极易被忽视但价值极高的字段:

  • lastState :上一次容器实例的状态。当容器正在 CrashLoopBackOff 循环中、当前 state 是 Waiting 时,lastState.terminated 里保存着上一次崩溃的退出码和原因,这是事后验尸(post-mortem)的关键。
  • restartCount:该容器的重启次数,对应 kubectl 的 RESTARTS 列。

1.3 第三层:Pod Conditions(status.conditions)

Conditions 面向"可用性"而非"生命周期",标准条件有 4 个(新版本增加了第 5 个):

Condition 含义
PodScheduled Pod 已被成功调度到某个节点
Initialized 所有 Init 容器已成功完成
ContainersReady 所有容器均已通过就绪检查
Ready Pod 整体就绪,可以接入 Service 流量
DisruptionTarget(较新版本) 标记 Pod 即将被某种干扰(如驱逐)终止,并携带原因

Ready 条件直接决定了 Pod 的 IP 是否被加入 Service 的 Endpoints/EndpointSlice。一个 Pod 可以是 Running 但 Ready=False------此时它活着,但不接流量。这是"服务看起来在跑、接口却 502/无节点"这类诡异问题的根源之一。

1.4 真相:kubectl STATUS 列是"推导"出来的

kubectl 的打印器按如下优先级逻辑合成 STATUS 列(此处描述其与源码等价的语义,便于记忆):

  1. 初始值取 status.phase(如 PendingRunningFailed);
  2. status.reason 非空(如 EvictedNodeLost),则覆盖;
  3. 若存在未完成的 Init 容器,则显示 Init:i/nInit:ErrorInit:CrashLoopBackOffInit:Signal:xInit:ExitCode:x 等;
  4. Init 完成后、主容器尚未启动时,显示 PodInitializing
  5. 主容器层面:取最后一个 非正常容器的 waiting.reason(如 CrashLoopBackOffContainerCreatingImagePullBackOff)或 terminated.reason(如 CompletedErrorOOMKilled),无 reason 时显示 Signal:x / ExitCode:x
  6. 若显示为 Completed 但仍有容器在 Running,则修正回 Running
  7. 最高优先级 :只要 metadata.deletionTimestamp 非空(即对象已被发起删除),一律显示 Terminating

由此可以得出三个重要结论,请务必记住:

  • Terminating 不是 Phase ,它是"删除流程进行中"的显示态,来自 deletionTimestamp
  • Completed 不是 Phase,它是 Phase=Succeeded 的显示形式;
  • CrashLoopBackOffImagePullBackOffOOMKilled 等不是 Phase ,它们是容器级 state.reason,被 kubectl 提升显示到了 STATUS 列。

理解了这套推导逻辑,就不会再被 STATUS 列"牵着走",而是能反向定位到它背后的真实字段,从而精准排障。


二、Pod Phase 五态

2.1 Pending:卡在"出生"之前

典型停留点与成因:

  • 调度失败 :资源不足(CPU/内存不满足 requests)、节点亲和性/污点容忍不匹配、拓扑分布约束过严、PV 的节点亲和性与可用节点冲突。Events 中会出现 FailedScheduling
  • 镜像拉取慢或失败:大镜像、跨洋拉取、镜像仓库限流(如 Docker Hub 匿名限流)、凭证错误。
  • 卷挂载慢或失败:云盘 attach/mount 超时、NFS 不通、CSI 插件异常。
  • 准入/配额拦截:ResourceQuota 超限、LimitRange 默认值注入失败等(这类更多表现为创建对象失败,但部分场景会体现为调度阻塞)。

排查命令:

bash 复制代码
kubectl describe pod <pod> -n <ns>          # 重点看 Events
kubectl get events -n <ns> --sort-by='.lastTimestamp'
kubectl describe node <node>                # 看 Allocatable 与已分配量

2.2 Running:活着,但未必健康

Running 只承诺"至少一个容器在跑"。进入 Running 后仍要持续关注:

  • READY 列是否为 1/1(就绪探针是否通过);
  • RESTARTS 是否在缓慢增长(历史上是否崩溃过,是否存在 flapping);
  • lastState.terminated 是否残留 OOMKilled/Error 记录。

一个严谨的巡检习惯 :不要只看 STATUS,要看 STATUS + READY + RESTARTS + AGE 四联指标。RESTARTS 高但 STATUS 是 Running 的 Pod,往往是"带病运行",需要复盘历史崩溃原因。

2.3 Succeeded:任务型 Pod 的圆满结局

所有容器以 0 退出且不会重启。对 Job/CronJob 这是预期状态;但如果一个本应长期服务的 Deployment Pod 变成 Succeeded,反而是严重事故------通常意味着主进程"正常退出"了(例如前台进程意外 return、启动脚本执行完就结束),而重启策略又不是 Always,或镜像 ENTRYPOINT 设计错误。长期服务容器的进程必须"永不返回"。

2.4 Failed:所有容器都已终止且至少一个失败

  • 对 Job:可能是业务错误、超过 backoffLimit、超过 activeDeadlineSeconds
  • 对普通 Pod:可能是全部容器崩溃且重启策略为 Never;
  • 被驱逐的 Pod 也是 Failed ,且 status.reason=Evictedstatus.message 会写明驱逐原因(如 "The node was low on resource: memory")。

2.5 Unknown:失联

控制面在一段时间内收不到 kubelet 上报(节点状态超过 node-monitor-grace-period,默认 40s 未上报则节点被置为 NotReady/Unknown),该节点上的 Pod 会陆续显示 Unknown。后续由基于污点的驱逐机制(默认约 5 分钟)决定是否在其他节点重建。常见根因:节点宕机、kubelet 崩溃、CNI/网络分区、节点资源耗尽导致 kubelet 无响应。


三、容器状态三态与全量 reason 字典

3.1 Waiting 及常见 reason 全表

reason 含义 严重程度 第一响应
ContainerCreating 正在创建:拉镜像、挂卷、分配网络、创建沙箱 低(短暂)/高(长期卡住) describe 看 Events 卡在哪一步
PodInitializing Init 容器已完成,主容器正在初始化启动 稍等;长期不动查节点与运行时
Init:N/MInit:ErrorInit:CrashLoopBackOff Init 容器进行中/失败/崩溃循环 中~高 kubectl logs <pod> -c <init容器名>
ErrImagePull 镜像拉取立即失败(名称错、仓库拒绝、凭证错) 核对镜像名/tag/secret
ImagePullBackOff 拉取失败后进入退避重试 同上,并查节点到仓库的网络
InvalidImageName 镜像引用格式非法 修正镜像地址写法
CreateContainerConfigError 配置类错误:引用了不存在/缺键的 ConfigMap/Secret 等 describe 看 message,核对配置对象
CreateContainerError 创建容器失败:如挂载配置冲突、OCI 创建错误 describe + 节点运行时日志
RunContainerError 启动容器时出错,常见为卷挂载失败 查 Events 与节点 kubelet/CSI 日志
CrashLoopBackOff 容器启动后反复退出,kubelet 按退避策略反复重启 logs --previous + lastState

3.2 Running 的关键字段

  • startedAt:本次启动时间,结合 RESTARTS 可推算崩溃频率;
  • ready:是否通过就绪探针;
  • started:是否通过启动探针(配置了 startupProbe 时)。

3.3 Terminated 及常见 reason 全表

reason 含义 典型退出码/信号
Completed 正常执行完毕退出 0
Error 以非 0 退出码失败退出 1、2、126、127 等
OOMKilled 超出容器 memory limit,被内核 OOM Killer 杀死 137(SIGKILL)
ContainerCannotRun 容器无法运行:如入口二进制不可执行、运行时错误 126/127/128+
DeadlineExceeded 超过 Job 的 activeDeadlineSeconds 被强制终止 ---
无 reason,仅有 signal/exitCode 被信号杀死等 128+信号编号

退出码速查(容器"死因"的语言):

退出码 含义
0 正常退出
1 通用错误(业务异常、未捕获异常)
2 Shell 命令误用(常见于脚本类容器)
126 文件存在但不可执行(权限/格式问题)
127 命令/二进制不存在(ENTRYPOINT 写错、镜像缺文件)
137 SIGKILL(9):OOMKilled、liveness 强杀、grace 到期强杀
139 SIGSEGV(11):段错误,程序崩溃
143 SIGTERM(15):正常优雅终止流程
128+N 被信号 N 终止的通用表达

记住这张表,排查 CrashLoopBackOff 时看 lastState.terminated.exitCode 就能瞬间缩小根因范围:137 往内存/探针/强杀方向查,127/126 往镜像与启动命令方向查,1 往业务日志方向查。


四、kubectl STATUS 列全状态

以下按"出现频率 × 重要性"排序,每个状态给出:本质、常见成因、诊断、处置、严重度。

4.1 Running(正常态)

本质 :Phase=Running 且无删除时间戳、无异常容器 reason。

注意 :Running ≠ 可用。必须同时确认 READY=1/1。若 READY=0/1 且 STATUS=Running,说明就绪探针未通过或容器 ready=false,此时 Service 不会导流,需检查探针配置、端口、依赖服务连通性。

严重度:低。

4.2 Pending(卡住未启动)

本质 :Phase=Pending,尚未有容器运行。

常见成因FailedScheduling(资源/亲和/污点/PV 约束)、镜像拉取中、卷挂载中、Init 未开始。

诊断

bash 复制代码
kubectl describe pod <pod> -n <ns>     # Events 是核心
kubectl get events -n <ns> --field-selector reason=FailedScheduling

处置 :扩容节点或降低 requests;调整亲和/容忍;检查 StorageClass 与 PV 可用区;清理被占用的资源。

严重度:中(新建 Pod 短暂 Pending 正常,长期 Pending 为故障)。

4.3 ContainerCreating(创建中)

本质 :Waiting,reason=ContainerCreating。kubelet 正在:拉取镜像 → 创建/挂载卷 → 调用 CNI 分配网络 → 创建容器沙箱。

卡住时的定位思路:describe 的 Events 会明确停在哪个动作上------

  • 停在 "Pulling image":镜像问题(大、慢、仓库不通、限流);
  • 停在 "MountVolume.SetUp failed":卷问题(CSI、NFS、secret 卷);
  • 停在 network 相关:CNI 插件故障、IP 池耗尽;
  • 停在 sandbox 创建:容器运行时(containerd/docker)异常。

严重度:短暂为低,长期卡住为高。

4.4 Init 系列:Init:N/M、Init:Error、Init:CrashLoopBackOff、PodInitializing

本质 :Init 容器按顺序执行,全部成功后主容器才启动。任何一个 Init 容器失败,Pod 就卡在 Init 阶段。

典型场景 :等待依赖就绪的 init 脚本(如等数据库可连接)写死循环、初始化 SQL 失败、init 镜像拉取失败。

诊断

bash 复制代码
kubectl logs <pod> -n <ns> -c <init-container-name>            # 当前
kubectl logs <pod> -n <ns> -c <init-container-name> --previous # 上一次

处置 :修复 init 逻辑;为"等待依赖"类 init 容器设置超时与重试上限,避免无限 Pending 式占用。

严重度:中~高(会阻塞整个 Pod 启动)。

4.5 Completed(圆满完成)

本质 :Phase=Succeeded 的显示形式,所有容器以 0 退出且不再重启。

典型载体 :Job/CronJob。

注意

  • Completed 的 Pod 会一直留在集群中直到 TTL 控制器(ttlSecondsAfterFinished)或人工清理;
  • 若 Deployment/StatefulSet 的 Pod 出现 Completed,属于设计错误(长期服务不应"执行完就退出"),需检查镜像入口与重启策略。

严重度:对 Job 为低(预期态);对长期服务为高(异常态)。

4.6 Error(失败退出)

本质 :容器以非 0 退出,terminated.reason=Error,通常出现在重启策略为 Never/OnFailure 且已不再重启的 Pod 上,或崩溃瞬间的显示。

诊断logs --previous 看业务报错;describe 看 exitCode。

严重度:中~高,视业务而定。

4.7 CrashLoopBackOff(崩溃循环退避)★重点

本质 :容器启动后在短时间内退出,kubelet 不断重启它,且重启间隔按指数退避增长。它是一个 Waiting reason,表示"上一次尝试失败了,正在等待下一次重试"。

退避机制(务必掌握) :重试间隔依次为 10s → 20s → 40s → 80s → 160s → 320s,封顶 5 分钟 ;当容器某次成功持续运行约 10 分钟后,退避计数清零。这就是为什么崩溃越久,看到"back-off restarting failed container"的间隔越长,也是为什么"刚 kubectl logs 看不到东西,等几分钟再看又崩了"。

六大根因族

  1. 应用自身崩溃:配置错误、空指针、依赖连接失败(DB/Redis/MQ 地址错或不通)、启动即 panic;exitCode 多为 1。
  2. OOMKilled 循环 :limit 设置过小或内存泄漏;exitCode=137,lastState.terminated.reason=OOMKilled
  3. liveness 探针误杀循环:探针阈值过严/端口路径错误/应用启动慢但未配 startupProbe,导致 kubelet 反复杀容器→重启→再杀。exitCode 常为 137/143。
  4. 镜像/入口问题:ENTRYPOINT 命令不存在(127)、不可执行(126)、前台进程立即退出(0 或 1)------"容器没有常驻进程"是新手高频坑。
  5. 配置注入失败:环境变量引用的 Secret/ConfigMap 键缺失(此类更多表现为 CreateContainerConfigError,但挂载卷失败也可能导致启动即退)。
  6. 权限/安全上下文问题:非 root 用户写只读文件系统、capabilities 不足、seccomp/SELinux 拦截。

标准排查路径

bash 复制代码
# 1. 看上一次崩溃的日志(最关键一步)
kubectl logs <pod> -n <ns> --previous
# 多容器时指定容器
kubectl logs <pod> -n <ns> -c <container> --previous

# 2. 看死因:exitCode / reason / signal
kubectl get pod <pod> -n <ns> -o jsonpath='{.status.containerStatuses[*].lastState}' | jq

# 3. 看事件与探针报错
kubectl describe pod <pod> -n <ns>

# 4. 崩溃太快抓不到日志时:临时改为 sleep 启动或 kubectl debug
kubectl debug -n <ns> <pod> --copy-to=debug-pod --container=xx --image=busybox -- sh

处置 :按根因族对症处理------修配置、修依赖连通性、调大 memory limit、修正探针与 startupProbe、修复镜像入口;若由近期发布引入,优先回滚kubectl rollout undo deployment/<name> -n <ns>)。

严重度:高(服务不可用或能力降级)。

4.8 ErrImagePull / ImagePullBackOff / InvalidImageName(镜像三兄弟)

区别ErrImagePull 是"本次拉取立即失败";连续失败后进入退避重试即 ImagePullBackOffInvalidImageName 是镜像引用写法非法(如 tag 含大写字母等不规范字符)。

常见成因

  • 镜像名/tag 写错、镜像已被删除;
  • 私有仓库未配置 imagePullSecrets 或 secret 过期;
  • 节点到仓库网络不通、DNS 解析失败、代理/证书问题;
  • 公有仓库限流(Docker Hub 对匿名拉取限流)。

处置 :核对 image: 字段;kubectl get secret <regcred> -o yaml 校验凭证;在节点上 crictl pull/ctr pull 复现;建设私有镜像仓库与镜像预热。

严重度:高(新 Pod 完全起不来),但根因通常简单。

4.9 CreateContainerConfigError(配置注入错误)

本质:容器创建前解析配置失败,最经典的是:

复制代码
couldn't find key "DB_PASSWORD" in ConfigMap "app-config"
secret "app-secret" not found

env.valueFrom / envFrom / 卷引用指向了不存在的 ConfigMap/Secret 或其中缺失某个键。

诊断 :describe 的 Events 会直接打印缺失对象与键名。

处置 :补齐配置对象;在 CI/CD 中加入配置清单校验;对可选配置使用 optional: true

严重度:高但修复快。

4.10 CreateContainerError / RunContainerError(运行时创建/启动错误)

本质 :OCI 运行时创建容器或启动容器时报错。常见于:卷挂载配置冲突(同路径重复挂载)、hostPath 不存在且类型校验失败、运行时(containerd/runc)异常、节点磁盘满导致无法写容器层。

诊断 :describe Events + 节点上 journalctl -u kubeletjournalctl -u containerd

处置 :修正卷配置;清理节点磁盘;修复运行时。

严重度:高,且常为节点级问题,可能批量影响。

4.11 OOMKilled(内存超限被杀)★重点

本质 :容器内存使用超过 resources.limits.memory,触发 cgroup 级 OOM,内核杀死容器进程,terminated.reason=OOMKilled,exitCode=137。

三个易混淆概念

  • 节点级 OOM:节点整体内存不足,内核 OOM Killer 按 oom_score 杀进程,可能杀任意进程,不一定体现为 OOMKilled reason;
  • cgroup 级 OOM(本文的 OOMKilled):只杀超限容器,reason 明确;
  • Evicted:kubelet 基于驱逐阈值的主动驱逐,Pod 级事件,Phase=Failed、reason=Evicted。

排查

bash 复制代码
kubectl top pod -n <ns>                      # 需 metrics-server
kubectl describe pod <pod> -n <ns>           # Limits 与 lastState
# 监控侧看 container_memory_working_set_bytes 曲线

处置与预防 :按工作集(working set)而非 RSS 估算内存;limit 预留 20%~50% 余量;Java 类应用务必设置堆外与容器感知参数(如 -XX:MaxRAMPercentage);修复内存泄漏;为关键服务设置 Guaranteed/Burstable 的合理 QoS,降低被优先驱逐概率。

严重度:高;若伴随 CrashLoopBackOff(反复 OOM)则为紧急。

4.12 Evicted(被驱逐)

本质:节点资源压力(内存、磁盘、inode、PID)触发 kubelet 驱逐机制,Pod 被终止,Phase=Failed,reason=Evicted,message 指明低压资源。

默认硬阈值(典型值)memory.available < 100Minodefs.available < 10%imagefs.available < 15%nodefs.inodesFree < 5%

驱逐顺序与 QoS 强相关:BestEffort 最先死,Burstable 次之,Guaranteed 最后(且 Guaranteed 通常只在自己超限时才被杀)。这也是为什么"裸奔"(不写 requests/limits)的 Pod 在节点出事时总是第一批牺牲。

处置 :扩容或削峰;清理节点磁盘(日志、镜像 GC 策略 imageGCHighThresholdPercent);为业务补齐 resources;对关键服务提高 QoS 等级并配合 PDB。

严重度:中~高(单 Pod 被驱逐是保护机制,批量驱逐是容量事故)。

4.13 Terminating(删除进行中)★重点

本质metadata.deletionTimestamp 已设置,Pod 进入优雅终止流程。它不是 Phase,而是"正在退场"的显示态。

标准删除时间线

  1. 用户/控制器发起删除,API Server 写入 deletionTimestamp(对象进入"只读待删"状态);
  2. 端点控制器将 Pod 从 Service 的 Endpoints 中摘除(停止导流);
  3. kubelet 执行本地清理:若配置了 preStop 钩子先执行它,然后发送 SIGTERM;
  4. terminationGracePeriodSeconds(默认 30s)内等待容器自行退出;到期未退出的容器被 SIGKILL 强杀;
  5. kubelet 确认容器全部终止、卷卸载完成,向 API Server 确认,对象被真正移除。

"大量 Terminating"的两种语义

  • 正常语义:滚动更新、缩容、节点排水时,旧 Pod 批量进入 Terminating,数十秒内消失;
  • 异常语义 :Terminating 长时间不消失(分钟级甚至天级),即"卡 Terminating"。

卡 Terminating 的六大根因

  1. Finalizers 未清除:某个控制器(或人为误加)持有 finalizer 且未释放,API 对象无法最终删除;
  2. 卷卸载失败:存储插件异常、远端存储不可达,kubelet 等待 unmount;
  3. kubelet/节点异常:节点 NotReady、kubelet 挂死,无人执行本地清理;
  4. 容器处于 D 状态(不可中断睡眠,多为 IO 卡死),SIGKILL 也无法立即生效;
  5. preStop 钩子阻塞:写了超长 sleep 或死循环的 preStop,占满甚至超过 grace 期;
  6. 容器运行时异常:containerd 卡死,无法完成 kill/remove。

处置 SOP

bash 复制代码
# 1. 看卡在哪:事件与 finalizers
kubectl describe pod <pod> -n <ns>
kubectl get pod <pod> -n <ns> -o jsonpath='{.metadata.finalizers}'

# 2. 节点/kubelet 是否健康
kubectl get node
# 节点上:journalctl -u kubelet -u containerd

# 3. 确认业务已无流量、无数据写入风险后,方可兜底:
#    a) 清除 finalizer(仅当确认对应控制器已无需收尾)
kubectl patch pod <pod> -n <ns> -p '{"metadata":{"finalizers":null}}'
#    b) 强制删除(API 层立即移除,kubelet 侧异步清理)
kubectl delete pod <pod> -n <ns> --force --grace-period=0

强制删除的风险警告 :对 StatefulSet Pod、挂载了 ReadWriteOnce 云盘的 Pod,强删可能造成"旧容器实际还活着 + 新 Pod 抢挂同一卷"的双写/脑裂风险;对数据库类有状态服务,强删前必须确认节点与运行时状态,必要时先隔离节点。

严重度:滚动更新中的短暂 Terminating 为低;长期卡住为高(占用资源、阻塞 StatefulSet 有序重建、掩盖底层存储/节点故障)。

4.14 Unknown / NodeLost / ContainerStatusUnknown(失联族)

本质 :控制面拿不到 Pod 真实状态。NodeLost 场景下 kubectl 可能显示 Unknown;较新版本中容器级还可能出现 ContainerStatusUnknown(如节点异常时 kubelet 无法确认容器状态)。

根因 :节点宕机、kubelet 崩溃、网络分区、节点负载过高导致上报超时。

处置 :先治节点(重启 kubelet、修复网络、下线坏节点),Pod 侧由控制器在驱逐超时后自动重建;不要对 Unknown Pod 盲目 force delete,先确认节点是否真的"死了"。

严重度:高(通常是节点级故障的信号)。

4.15 Running 但 READY 0/1(就绪未通过)

本质 :容器在跑,但 ready=false,Pod Condition Ready=False,Endpoints 中无此 Pod。

常见成因 :就绪探针端口/路径/协议配错;应用启动慢但 readiness 阈值过严;应用依赖(DB/配置中心)不可用导致健康检查返回非 200;容器内监听地址为 127.0.0.1 而探针走 Pod IP。

影响 :发布时新 Pod 永远不接流 → 滚动更新卡住(deployment waiting for rollout);或运行中依赖抖动导致流量被摘除。

处置 :手动模拟探针请求(进入容器 curl);校准探针参数;区分 startupProbe(管启动慢)与 readinessProbe(管运行期就绪)。

严重度:中~高。


五、重启策略、工作负载与状态行为的矩阵

restartPolicy 决定"容器退出后 kubelet 怎么办",它与工作负载类型强绑定:

restartPolicy 容器成功退出(0) 容器失败退出(非0) 适用工作负载
Always(默认) 重启 重启(反复失败则 CrashLoopBackOff) Deployment/StatefulSet/DaemonSet
OnFailure 不重启 重启 Job
Never 不重启 不重启(Pod 停留 Error/Failed) Job(特殊场景)

配套机制:

  • Deployment 等长期负载只允许 Always,因此它们的 Pod 不会"自然 Completed",出现 Completed 即设计错误;
  • Job 的 backoffLimit 控制失败重试上限,超限后 Job 标记 Failed;activeDeadlineSeconds 控制总时长,超时容器被以 DeadlineExceeded 终止;
  • RESTARTS 列 是容器级 restartCount 之和;4 (338d ago) 表示累计重启 4 次、最后一次发生在 338 天前------这是判断"老毛病还是新故障"的时间锚点;
  • CrashLoopBackOff 的退避与 Job 的失败重试是两套独立机制,不要混淆。

六、Ready 机制深潜:为什么"Running ≠ 可用"

一次完整的"可用"判定链条是:

复制代码
容器进程存活(Running)
   → startupProbe 通过(若配置)→ started=true
   → readinessProbe 通过 → ready=true
   → ContainersReady=True → Ready=True
   → EndpointSlice 纳入该 Pod IP
   → kube-proxy/Service 开始导流

链条上任何一环断裂,都会产生"看起来在跑、实际不服务"或"流量打进来了、实际没准备好"的事故。两个经典反模式:

  1. liveness 配得像 readiness 一样严:依赖一抖动容器就被杀,人为制造 CrashLoopBackOff。liveness 只应回答"进程是否死锁/不可恢复",不应检查业务依赖;
  2. 不配 startupProbe 且 readiness 过早开始探测:慢启动应用(JVM、大数据量加载)在启动期被判定不就绪甚至被 liveness 杀掉。正确姿势是 startupProbe 兜底启动期,ready 后再接流。

同时记住删除侧的配合:Pod 被删除时 Endpoints 摘除与 SIGTERM 几乎同时发生,若客户端/网关有连接粘性与缓存,可能出现"Pod 已 Terminating 仍收到流量"的短暂窗口,标准解法是 preStop: sleep 若干秒 或端点更新感知的优雅下线设计。


七、排障方法论:从"看到异常"到"定位根因"

第一原则:先看三层模型,再看显示状态。 即:status.phase 定大方向 → containerStatuses 定死因 → conditions 定可用性 → Events 定过程 → logs 定细节。

标准 SOP(按顺序执行):

bash 复制代码
# 0. 全局快照与过滤
kubectl get pod -A
kubectl get pod -A --field-selector=status.phase!=Running   # 快速捞出非 Running
kubectl get pod -A -o wide                                  # 补节点信息

# 1. 事件(过程证据,注意事件默认只保留 1 小时)
kubectl describe pod <pod> -n <ns>
kubectl get events -n <ns> --sort-by='.lastTimestamp'

# 2. 日志(当前与上一次)
kubectl logs <pod> -n <ns> -c <container> --previous --tail=200

# 3. 结构化死因(退出码/信号/lastState/ready/restartCount)
kubectl get pod <pod> -n <ns> -o yaml | yq '.status.containerStatuses'

# 4. 资源视角(OOM/容量)
kubectl top pod -n <ns>
kubectl top node
kubectl describe node <node> | sed -n '/Allocated resources/,$p'

# 5. 运行时视角(节点上)
journalctl -u kubelet --since "1h ago"
journalctl -u containerd --since "1h ago"
crictl ps -a && crictl logs <container-id>

# 6. 抓不住的崩溃:调试容器
kubectl debug -n <ns> <pod> --copy-to=dbg --image=busybox:1.36 --target=<container> -- sh

经验法则

  • exitCode=1 看业务日志;=137 看内存与探针;=127/126 看镜像入口;
  • 批量同状态 → 往"共性变更/共性依赖"方向查(发布、配置中心、DB、网络、节点);
  • 单点异常 → 往"个体差异"方向查(所在节点、卷、副本参数);
  • RESTARTS 的"最后一次重启时间"是判断故障起点的第一线索。

八、减少异常状态的工程最佳实践

  1. 探针三件套规范化:startupProbe 兜底慢启动;liveness 只判死锁不判依赖;readiness 真实反映可服务能力;阈值经过压测校准。
  2. 资源治理:所有 Pod 声明 requests/limits;以监控中的 working set 分位数定容量;关键服务争取更高 QoS 等级。
  3. 优雅终止 :应用捕获 SIGTERM 做连接排空;terminationGracePeriodSeconds 按真实排空时长设置(而非默认 30s);必要时 preStop 补偿端点摘除窗口。
  4. 镜像与配置防线 :私有仓库 + 不可变 tag;CI 校验 ConfigMap/Secret 键完整性;杜绝 latest 在生产漂移。
  5. 容量与驱逐防线:节点水位告警;日志/镜像 GC 策略明确;磁盘与内存阈值纳入监控。
  6. 变更防线:发布分批 + 自动回滚条件(崩溃次数、就绪失败);对"批量 Terminating + 批量 CrashLoopBackOff 同时出现"这类发布事故特征设置组合告警。
  7. 可观测性 :对 kube_pod_container_status_restarts_totalkube_pod_status_phasekube_pod_container_status_waiting_reason 建立告警,让 CrashLoopBackOff/ImagePullBackOff/Evicted 在 IM 里第一时间被看见,而不是在巡检时才被发现。
  8. 有状态服务特殊照顾:数据库类 StatefulSet 慎用强删;PDB 保护自愿性驱逐;存储健康独立监控。
相关推荐
suijishengchengde2 小时前
k8s deployment或statefulset分组关停
运维·kubernetes
张洛闻Eren2 小时前
云原生k8s【第二课】:K8s 部署与架构
云原生·架构·kubernetes
用户6919026813392 小时前
Docker基本概念
后端·docker·容器
江湖有缘3 小时前
从零搭建私有云相册:使用 Docker 一键部署 Damselfly全攻略
运维·docker·容器
SLD_Allen13 小时前
NVIDIA KAI Scheduler深度解析——Kubernetes原生AI调度器的架构、原理与实践
人工智能·架构·kubernetes
艾伦_耶格宇14 小时前
【DOCKER进阶】-3 cgroups
docker·容器·eureka
ltl14 小时前
nodeSelector 与节点放置:Filter、亲和性与拓扑打散
kubernetes
ltl14 小时前
Envoy Gateway 排障:未 Accepted、空 IR、xDS NACK 与旧快照
kubernetes
ltl15 小时前
Envoy Gateway 南北向全景:附着、IR、xDS 与东西向交界
kubernetes