3. Kubernetes 集群升级模型:节点池概念、滚动升级策略、升级过程中的流量中断风险

Kubernetes 集群升级是运维中最常见、风险最高的操作之一。本章聚焦升级模型的核心要素:节点池(Node Pool)、滚动升级策略以及升级过程中不可避免的流量中断风险。理解这三者的关系,是设计故障域隔离方案的前提。

3.1 节点池概念与作用

节点池(Node Pool)是集群中一组具有相同配置(如实例类型、操作系统、Kubernetes 版本、标签、污点)的节点集合。在托管集群(如 GKE、AKS、EKS)中,节点池是升级的基本操作单元。

特性 说明 升级场景价值
同质化 池内所有节点使用相同的 kubelet 版本、操作系统镜像、实例规格 升级时只需验证一种节点类型,降低测试复杂度
独立扩缩 每个节点池可独立设置最小/最大节点数、自动扩缩策略 升级期间可临时扩容其他池,维持总容量
版本解耦 不同节点池可以运行不同的 Kubernetes 次版本(patch 版本必须一致) 实现蓝绿升级、金丝雀升级,隔离故障域
标签与污点 节点池自动为节点添加特定标签和污点,用于工作负载调度 通过 nodeSelector 和 tolerations 控制哪些 Pod 进入新池
最佳实践:生产集群至少划分 3 个节点池:系统池(运行 CoreDNS、Ingress Controller 等系统组件)、业务池(运行无状态应用)、GPU/高内存池(运行特殊工作负载)。升级时先升级业务池,观察稳定后再升级系统池。

3.2 滚动升级策略

Kubernetes 集群升级默认采用滚动升级(Rolling Update)策略,即逐个或逐批替换节点,而不是一次性全部升级。滚动升级的核心参数由 kube-controller-manager 或云厂商的节点池升级控制器控制。

3.2.1 升级流程步骤

  1. 节点封锁(Cordon):将节点标记为不可调度,阻止新 Pod 调度到该节点。
  2. Pod 驱逐(Drain):优雅驱逐节点上所有 Pod(遵循 PodDisruptionBudget)。
  3. 节点升级:替换或原地升级节点操作系统和 kubelet 版本。
  4. 节点解封(Uncordon):节点就绪后,恢复调度能力。
  5. 下一节点:重复上述步骤,直到池内所有节点完成升级。
关键参数:
  • maxSurge:升级过程中允许超出期望节点数的最大节点数(默认 1)。
  • maxUnavailable:升级过程中允许不可用的最大节点数(默认 0 或 1)。
  • drainTimeout:驱逐 Pod 的超时时间(默认 20 分钟)。

3.2.2 滚动升级 vs 蓝绿升级 vs 金丝雀升级

策略 操作方式 速度 风险 适用场景
滚动升级 逐节点替换,原地升级 中等 中等(逐节点影响) 常规版本升级,节点池内节点数较多
蓝绿升级 创建新节点池(蓝),切换流量后删除旧池(绿) 慢(需额外资源) 低(全量切换前可回滚) 大版本升级、高风险变更
金丝雀升级 先升级少量节点(如 10%),验证后再升级剩余节点 慢 极低(小范围验证) 新版本稳定性未知、灰度验证
注意:滚动升级虽然速度较快,但无法在升级过程中保持完整的集群容量。如果 maxUnavailable=1,则始终有一个节点处于不可用状态。对于副本数较少的应用,可能导致服务降级。

3.3 升级过程中的流量中断风险

即使采用滚动升级,流量中断仍然可能发生。中断的根源在于Pod 驱逐与流量切换之间的时序错位。以下是三种典型的中断场景:

3.3.1 中断场景分析

场景 触发条件 影响 典型表现
连接耗尽失败 Pod 收到 SIGTERM 后,未等待现有连接处理完毕即退出 客户端收到 RST 或 502 短连接服务(如 HTTP API)出现零星超时
端点缓存延迟 EndpointSlice 更新滞后于 Pod 状态变化,Envoy/LB 仍向已终止 Pod 转发流量 请求被路由到不存在的 Pod 升级期间出现 503 或连接拒绝
PDB 阻塞 PodDisruptionBudget 设置过于严格,导致驱逐卡住 节点升级超时,升级流程停滞 节点长时间处于 Drain 状态,Pod 无法迁移

3.3.2 流量中断时间线(SVG)

下图展示了滚动升级过程中,从节点封锁到流量恢复的完整时间线,以及中断窗口的位置:

滚动升级流量中断时间线 Cordon Drain (驱逐) 节点升级 Uncordon 中断窗口 中断窗口 中断原因: Drain 阶段:Pod 终止时连接未耗尽,或 EndpointSlice 未及时更新。 节点升级阶段:节点不可用期间,若 Pod 副本数不足,服务容量下降。

3.4 中断风险量化与评估

在升级前,建议对中断风险进行量化评估。以下公式可用于估算升级期间的最大中断时长:

最大中断时长 ≈ (DrainTimeout + NodeRebootTime) × maxUnavailable
其中:
  DrainTimeout      = 驱逐 Pod 的超时时间(默认 20 分钟)
  NodeRebootTime    = 节点重启或替换时间(通常 2-5 分钟)
  maxUnavailable    = 同时不可用的最大节点数(默认 1)
示例:假设集群有 10 个节点,maxUnavailable=1,DrainTimeout=20min,NodeRebootTime=3min。
单节点中断窗口 = 20 + 3 = 23 分钟。
总升级时间 ≈ 10 × 23 = 230 分钟(约 4 小时)。
在此期间,始终有 1 个节点(10% 容量)不可用。

3.5 降低中断风险的关键措施

  • 合理设置 PodDisruptionBudget:确保关键服务(如 minAvailable: 2)在驱逐期间至少有 2 个副本可用。
  • 配置 preStop Hook:在 Pod 终止前等待 5-10 秒,让 Envoy 等代理完成连接耗尽。
  • 使用 ReadinessGate:在 EndpointSlice 中标记 Pod 为不可用,避免流量路由到正在终止的 Pod。
  • 升级前扩容:临时增加节点池大小或 Pod 副本数,补偿升级期间的容量损失。
  • 分批升级:将节点池拆分为多个子池,逐批升级,每批之间留出观察时间。
推荐工具:使用 descheduler 在升级前重新平衡 Pod 分布,避免单个节点承载过多关键 Pod;使用 cluster-autoscaler 在升级期间自动补充节点。