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 升级流程步骤
- 节点封锁(Cordon):将节点标记为不可调度,阻止新 Pod 调度到该节点。
- Pod 驱逐(Drain):优雅驱逐节点上所有 Pod(遵循 PodDisruptionBudget)。
- 节点升级:替换或原地升级节点操作系统和 kubelet 版本。
- 节点解封(Uncordon):节点就绪后,恢复调度能力。
- 下一节点:重复上述步骤,直到池内所有节点完成升级。
关键参数:
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)
下图展示了滚动升级过程中,从节点封锁到流量恢复的完整时间线,以及中断窗口的位置:
3.4 中断风险量化与评估
在升级前,建议对中断风险进行量化评估。以下公式可用于估算升级期间的最大中断时长:
最大中断时长 ≈ (DrainTimeout + NodeRebootTime) × maxUnavailable
其中:
DrainTimeout = 驱逐 Pod 的超时时间(默认 20 分钟)
NodeRebootTime = 节点重启或替换时间(通常 2-5 分钟)
maxUnavailable = 同时不可用的最大节点数(默认 1)
示例:假设集群有 10 个节点,
单节点中断窗口 = 20 + 3 = 23 分钟。
总升级时间 ≈ 10 × 23 = 230 分钟(约 4 小时)。
在此期间,始终有 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 在升级期间自动补充节点。