3、集群自动伸缩:Cluster Autoscaler原理、节点池配置、弹性伸缩策略
说到集群自动伸缩,我猜你第一反应就是「省成本」。没错,这是 FinOps 里最立竿见影的手段之一。但说实话,我在不少项目里见过「伸缩没配好,反而更贵」的案例。今天咱们就把 Cluster Autoscaler 掰开揉碎,看看它到底怎么工作,怎么配才不踩坑。
3.1 Cluster Autoscaler 的工作原理
Cluster Autoscaler(简称 CA)说白了就是一个「看菜下饭」的组件。它盯着集群里那些 Pending 状态的 Pod,一旦发现有 Pod 因为资源不够而卡住,它就去找云厂商的 API,申请加一台新节点进来。
反过来,当节点利用率很低,并且上面的 Pod 可以被调度到其他节点上时,CA 就会把节点缩掉。嗯,这里有个关键点:它不会随便缩容,得确保 Pod 能安全迁移。
核心逻辑就三步:
- 扫描:每隔 10 秒(默认)检查一次集群状态
- 判断:有没有 Pod 处于 Pending 状态?节点利用率是否低于阈值?
- 执行:调用云厂商接口,扩容或缩容节点
我个人习惯把 CA 比作「自动挡汽车」。你不需要手动换挡(加节点),它自己会判断什么时候该升档、什么时候该降档。但自动挡也有脾气——比如你油门踩到底(创建大量 Pod),它得反应几秒钟才能降档提速。
3.2 节点池配置:别把所有鸡蛋放一个篮子里
节点池(Node Pool)这个概念,我建议你把它理解成「不同规格的服务器分组」。比如你有一组 4C8G 的通用节点,另一组 8C16G 的计算优化节点,还有一组带 GPU 的节点。
为什么要分池?我在项目中遇到过这样一个坑:所有节点混在一个池子里,结果 GPU 任务把普通 CPU 节点占满了,导致普通业务 Pod 排队等资源。明明 GPU 节点还有空,但 Pod 调度不过去——因为没打对应的 toleration。
我的配置建议:
- 按业务类型分池:在线服务、离线任务、GPU 任务各一个池
- 按规格分池:通用型、计算型、内存型分开
- 每个池设置独立的伸缩策略:比如在线服务池保留 2 个节点作为缓冲
配置节点池时,记得给每个池打上标签(labels)。这样你的 Pod 可以通过 nodeSelector 或 nodeAffinity 精确匹配到对应的池子。你想想看,如果 Pod 没有指定节点池,CA 可能会把它调度到最便宜的节点上,结果性能不够,反而拖慢整个业务。
3.3 弹性伸缩策略:什么时候扩,什么时候缩
弹性伸缩策略,说白了就是「扩缩容的规矩」。CA 默认的扩缩容逻辑其实挺保守的,但我们可以通过参数调优让它更符合业务场景。
3.3.1 扩容策略
扩容相对简单。当 Pod 因为资源不足而 Pending 时,CA 会计算需要加多少节点。默认情况下,它一次最多扩 10 个节点(可以通过 --max-nodes-per-scale-up 调整)。
我曾经遇到过一个场景:大促期间流量突然暴增,Pod 副本数从 10 个涨到 200 个。CA 一次只扩 10 个节点,结果扩容速度跟不上流量增长,导致部分请求超时。后来我把 --max-nodes-per-scale-up 调到了 50,同时配合 HPA(水平 Pod 自动伸缩)一起用,才解决了问题。
注意:扩容速度不是越快越好。云厂商的 API 有频率限制,一次创建太多节点可能导致 API 限流。我建议根据业务峰值流量做压测,找到合适的扩容步长。
3.3.2 缩容策略
缩容比扩容复杂得多。CA 不会因为节点利用率低就立刻缩掉它,它得确保缩容后 Pod 能正常调度到其他节点上。
默认情况下,CA 会等待节点利用率低于 50% 且持续 10 分钟,才会考虑缩容。这个阈值可以通过 --scale-down-utilization-threshold 调整。
我个人习惯把缩容阈值设到 40%,并且把 --scale-down-delay-after-add 设为 15 分钟。为什么?因为新加的节点刚启动时,Pod 还在初始化,利用率看起来很低。如果立刻缩容,就会造成「刚加就缩」的抖动。等 15 分钟,让 Pod 稳定运行后再评估,更合理。
3.4 避坑指南:我曾经踩过的三个坑
做 FinOps 这些年,我在 CA 上栽过不少跟头。挑三个最典型的分享给你:
坑一:节点池没配亲和性,导致 Pod 调度混乱
有一次我把所有节点放在一个池子里,结果 GPU 任务被调度到了普通节点上,Pod 一直 Pending。CA 以为是资源不够,疯狂加普通节点,最后 GPU 节点空转,普通节点堆了一堆。浪费了大概 30% 的成本。
解决方案:给每个节点池打标签,Pod 用 nodeSelector 精确匹配。
坑二:缩容策略太激进,导致服务中断
我曾经把缩容阈值设到 30%,想着省更多钱。结果业务低峰期,CA 把节点缩得只剩 1 个。突然来了一波流量,Pod 扩容需要时间,新节点还没就绪,服务就挂了。
解决方案:设置最小节点数,比如在线服务池至少保留 2 个节点。同时配合 PDB(Pod 中断预算)保护关键 Pod。
坑三:忽略云厂商的实例库存限制
有一次大促,CA 尝试扩容 50 个节点,但云厂商那边某种实例类型库存不足,只创建了 20 个。剩下的 Pod 继续 Pending,CA 反复重试,浪费了大量 API 调用次数。
解决方案:节点池里配置多种实例类型(比如同时支持 ecs.g6.xlarge 和 ecs.c6.xlarge),CA 会按优先级尝试。如果一种实例没货,自动切换到另一种。
3.5 实战配置示例
最后,给你一个我常用的 CA 配置模板。这是基于阿里云 ACK 的配置,其他云厂商大同小异:
# Cluster Autoscaler 部署配置(部分关键参数)
command:
- ./cluster-autoscaler
- --v=4
- --stderrthreshold=info
- --cloud-provider=alicloud
- --nodes=0:10:ecs.g6.xlarge # 最小0,最大10,实例类型
- --nodes=0:5:ecs.g6.2xlarge # 第二个节点池
- --scale-down-enabled=true
- --scale-down-delay-after-add=15m
- --scale-down-delay-after-delete=10m
- --scale-down-delay-after-failure=3m
- --scale-down-utilization-threshold=0.4
- --max-nodes-per-scale-up=30
- --balance-similar-node-groups=true
- --skip-nodes-with-system-pods=false
这里有个参数我想特别提一下:--balance-similar-node-groups。开启后,CA 会尽量让多个节点池的节点数保持均衡。比如你有两个规格相似的节点池,CA 不会只往一个池子里加节点,而是分散开。这样做的好处是,如果一个池子的实例库存不足,另一个池子还能顶上。
小技巧:如果你用的是 Spot 实例(抢占式实例),建议把 --scale-down-unneeded-time 设短一点,比如 5 分钟。因为 Spot 实例随时可能被回收,没必要长期保留。但记得配合 --max-node-provision-time 设置合理的超时时间,避免因实例创建慢导致 Pod 长时间 Pending。
好了,关于 Cluster Autoscaler 的原理、节点池配置和弹性伸缩策略,咱们就聊到这儿。说白了,自动伸缩是个好东西,但得「因地制宜」。每个业务的流量模型不一样,你得根据自己的情况调参、试错、优化。别指望一套配置打天下——我在不同项目里用的参数几乎都不一样。
下一章咱们聊聊 HPA 和 VPA 的配合使用,到时候你会发现,自动伸缩这件事,组合拳比单打独斗强得多。