4、节点状态同步概念

在集群节点扩容场景中,新节点加入集群后,其本地状态必须与集群控制面(Control Plane)保持一致,这个过程称为状态同步。状态同步是节点可调度、Pod 正常运行的先决条件,也是后续回滚操作的基础。

4.1 什么是状态同步

状态同步是指将节点上的运行时状态(如节点健康、Pod 生命周期、容器资源使用)上报至 API Server,并同时从 API Server 拉取期望状态(如调度决策、Pod 规约)以修正本地行为的过程。在 Containerd 环境下,kubelet 是状态同步的核心执行者,它通过 CRI(Container Runtime Interface)与 Containerd 通信,获取容器级状态并聚合为 Pod 状态和节点状态。

核心原则:状态同步不是一次性操作,而是持续进行的“调谐循环”(Reconciliation Loop)。kubelet 默认每 10 秒执行一次同步周期,确保节点状态始终逼近期望状态。

4.2 同步的维度

节点状态同步包含三个层次,从下至上依次为:容器状态、Pod 状态、节点状态。三者之间存在明确的依赖关系:容器状态是基础,Pod 状态是聚合,节点状态是全局视图。

同步维度 数据来源 同步内容 上报频率(默认)
节点状态 kubelet 本地采集 + 系统指标 节点 Ready/NotReady、磁盘压力、内存压力、PID 压力、网络可用性 每 10 秒(--node-status-update-frequency)
Pod 状态 kubelet 通过 CRI 查询 Containerd Pod Phase(Pending/Running/Succeeded/Failed/Unknown)、Pod 条件(Ready/Initialized/ContainersReady) 每 10 秒(同步周期内)
容器状态 Containerd 通过 CRI 返回 容器状态(Created/Running/Exited/Unknown)、退出码、资源使用(CPU/内存/磁盘) 每 10 秒(kubelet 主动查询)

4.2.1 节点状态

节点状态是集群调度决策的直接依据。kubelet 通过 NodeStatus 对象向 API Server 报告以下关键条件:

  • Ready:节点是否能够正常接收 Pod。如果 Containerd 服务异常或 CRI 通信超时,该条件变为 False。
  • DiskPressure:节点磁盘空间是否充足。Containerd 的镜像存储目录(默认 /var/lib/containerd)空间不足时会触发此条件。
  • MemoryPressure:节点内存是否接近耗尽。
  • PIDPressure:节点 PID 分配是否接近上限。
  • NetworkUnavailable:节点网络插件(如 CNI)是否就绪。

4.2.2 Pod 状态

Pod 状态是 kubelet 对 Pod 内所有容器状态的综合判断。kubelet 通过 CRI 调用 ListContainers 和 ContainerStatus 接口从 Containerd 获取每个容器的运行时状态,然后聚合为 Pod 的 status.phase 和 status.conditions。

关键聚合逻辑:
  • 所有容器均为 Running → Pod Phase = Running
  • 至少一个容器为 Waiting(如镜像拉取中)→ Pod Phase = Pending
  • 所有容器均为 Terminated 且退出码为 0 → Pod Phase = Succeeded
  • 至少一个容器为 Terminated 且退出码非 0 → Pod Phase = Failed
  • kubelet 无法获取容器状态(如 Containerd 宕机)→ Pod Phase = Unknown

4.2.3 容器状态

容器状态是状态同步的最小粒度。Containerd 通过 CRI 返回的容器状态包含以下字段:

  • state:CONTAINER_CREATED、CONTAINER_RUNNING、CONTAINER_EXITED、CONTAINER_UNKNOWN
  • exit_code:容器退出码(仅 Exited 状态有效)
  • reason:状态变更原因(如 OOMKilled、Error、Completed)
  • resources:容器资源使用统计(CPU 时间、内存 RSS、磁盘读写)

4.3 同步的挑战

在集群节点扩容场景中,状态同步面临以下核心挑战:

挑战 描述 典型场景 影响
网络延迟 节点与 API Server 之间的网络往返时间(RTT)导致状态上报延迟 跨地域集群、公有云节点与控制面不在同一可用区 节点状态更新滞后,调度器可能将 Pod 调度到实际已不可用的节点
数据一致性 kubelet 本地状态与 API Server 期望状态出现偏差 节点重启后 Containerd 容器状态丢失、并发调度冲突 Pod 被重复调度、孤儿 Pod、资源泄漏
状态风暴 大量节点同时加入或状态变更时,API Server 和 etcd 写入压力激增 集群扩容 100+ 节点同时上线 API Server 响应变慢,甚至触发限流导致同步失败
CRI 超时 kubelet 调用 Containerd CRI 接口超时,无法获取容器状态 Containerd 负载过高、镜像拉取阻塞、磁盘 I/O 瓶颈 Pod 状态变为 Unknown,节点可能被标记为 NotReady

4.3.1 网络延迟的应对策略

Kubernetes 通过以下机制缓解网络延迟的影响:

  • 节点租约(Node Lease):Kubernetes 1.14+ 使用 Lease API 替代心跳更新,减少 etcd 写入频率。节点每 10 秒更新一次 Lease,而非每次更新完整的 NodeStatus。
  • 节点状态容忍时间:--node-monitor-grace-period 默认 40 秒,允许节点在短暂网络中断后恢复而不被标记为 NotReady。
  • Pod 驱逐超时:--pod-eviction-timeout 默认 5 分钟,给网络恢复留出缓冲窗口。

4.3.2 数据一致性的保障机制

数据一致性是状态同步中最复杂的挑战。kubelet 采用以下策略保证最终一致性:

  • 乐观并发控制:kubelet 通过 resourceVersion 字段检测状态更新冲突,冲突时重试。
  • 本地状态持久化:kubelet 将 Pod 状态缓存到本地文件系统(/var/lib/kubelet/pods),节点重启后可从本地恢复。
  • CRI 状态查询:kubelet 定期调用 ListContainers 和 ListPodSandbox 从 Containerd 重建本地状态视图。
注意:Containerd 本身不持久化容器状态到磁盘。节点宕机后,Containerd 重启时只能从内存恢复运行中的容器。如果节点异常断电,kubelet 必须通过 CRI 重新查询所有容器的实际状态,并与 API Server 的期望状态进行比对,这个过程称为“状态重建”(State Reconciliation)。

4.4 状态同步流程总览

下图展示了节点扩容时,从节点加入集群到状态完全同步的完整流程:

节点扩容状态同步流程 1. 节点加入集群 2. kubelet 注册 Node 3. 状态采集 节点状态 Pod 状态 容器状态 4. 上报 API Server 5. 调度器分配 Pod 6. 调谐循环(持续) 7. 状态不一致 → 回滚 说明:步骤 3 中 kubelet 通过 CRI 调用 Containerd 获取容器状态,聚合为 Pod 状态和节点状态后上报 API Server。

4.5 状态同步与回滚的关系

状态同步是回滚流程的数据基础。当节点扩容过程中出现状态不一致时(如 Pod 启动失败、节点标记为 NotReady),回滚操作需要依赖同步的状态信息做出决策:

  • 回滚触发条件:节点状态持续 NotReady 超过阈值、Pod 状态长时间 Pending 或 CrashLoopBackOff、容器状态异常(如 OOM 频繁)。
  • 回滚执行依据:kubelet 本地缓存的状态快照 + API Server 中的期望状态,两者对比确定需要清理的 Pod 和容器。
  • 回滚后状态重建:回滚完成后,kubelet 重新执行状态同步,确保节点恢复到扩容前的已知状态。
关键设计原则:状态同步必须支持“幂等回滚”。即无论回滚执行多少次,最终节点状态都应收敛到同一个稳定状态。这要求 Containerd 的容器清理操作(如 RemoveContainer、StopPodSandbox)在重复调用时不会产生副作用。