来源:kubernetes · 原文

核心结论

这篇 ACK 文档把 Kubernetes 节点伸缩讲得比“CPU 高了就加机器”更准确。它强调:Kubernetes 的节点伸缩不是传统 IDC 里按平均利用率拍脑袋扩容,而是围绕不可调度 Pod做容量补充。

这点对我很关键。节点层的弹性不是为了直接缓解某个正在忙的 Pod,而是为了让调度器有地方放下新的或被扩出来的 Pod。真正改变业务处理能力的,通常还得靠工作负载层面的副本变化。

为什么不能只看节点利用率

文档先批判了传统阈值模型,我觉得这段很值得记住。

如果按集群平均利用率扩容,热点节点会被平均值掩盖;如果按最高节点利用率扩容,又容易因为局部热点造成整体资源浪费。更麻烦的是,即使扩出新节点,原来高负载 Pod 的副本数和 limit 没变,压力也不会自动转移。

所以 Kubernetes 节点伸缩的触发点更自然地落在调度失败上:当 Pod 因资源不足 Pending,伸缩组件模拟调度,判断哪个开启弹性的节点池能承载这些 Pod,再驱动节点池扩容。

扩容和缩容的真实边界

扩容时,开启弹性的节点池会被抽象成候选节点:节点池规格变成 CPU、内存或 GPU 容量,节点池上的 Label、Taint 也进入模拟调度。只有 Pod 的调度约束能匹配这个抽象节点,扩容才有意义。

缩容则不是简单删除低利用率节点。ACK 会逐个判断弹性节点池中的节点,模拟驱逐其上的负载,确认是否能安全排水。像 kube-system 下的非 DaemonSet Pod、受 PDB 控制的 Pod 等,可能会阻止某个节点成为缩容候选。

我会把这里记成一句话:节点伸缩是在和调度器、PDB、taint / label、节点池库存一起工作,不是一个孤立的云主机数量开关。

自动伸缩与即时弹性

ACK 在节点层给了两种方案:

  • 节点自动伸缩:基于 cluster-autoscaler,轮询维护集群状态,发现扩缩容条件后调整节点;
  • 节点即时弹性:事件驱动的节点伸缩控制器,在大规模节点池、多节点池、连续扩容等场景下更强调速度、成功率和资源碎片控制。

文档给出的取舍很清楚。节点即时弹性在大规模和连续弹性场景里更适合,理论伸缩速度约 45s,成功率可达 99%,并能综合库存和成本选择规格;但它也有边界,例如不支持极速模式、单个节点池单批扩容不能超过 180 个节点,抢占式库存检查也有限制。

我不会把这解读成“即时弹性永远更好”。更准确的判断是:如果集群规模较小、弹性诉求不尖锐、已有 cluster-autoscaler 够用,那节点自动伸缩仍然简单;如果节点池多、连续扩容频繁、库存不确定性高,就要认真评估节点即时弹性。

成功率来自节点池设计

这篇文档还给了一个非常实用的提醒:弹性成功率很大程度取决于节点池是否真的能接住 Pod。

两个检查尤其重要:

  • 调度策略是否匹配:Pod 的 nodeSelector、affinity、taint toleration、拓扑约束是否能落到弹性节点池;
  • 资源库存是否充分:节点池要配置多个可用区、多个实例规格,避免某个规格缺货导致扩容失败。

这让我更愿意把“弹性伸缩”看成一种调度设计,而不是后期补上的运维功能。Pod 约束写得越窄,节点池规格越单一,弹性系统可选择的空间就越小。

对我的启发

ACK 这篇文章把节点伸缩拉回了 Kubernetes 的核心事实:调度是第一现场。节点扩容不是为了追某个利用率曲线,而是为不可调度 Pod 提供可落点;节点缩容也不是为了凑一个低水位数字,而是要证明节点上的负载可以被安全迁走。

这对生产系统很有提醒意义。真正稳的弹性设计,应该同时看 workload 层的 HPA / VPA / KEDA,node 层的节点池容量,以及 Pod 约束和 PDB 这些调度语义。只看其中一层,往往会把“弹性”做成一个看起来自动、实际经常卡住的系统。


相关页面:kubernetes-autoscaling · kubernetes-autoscaling-workloads · kubernetes