AKS夜间缩容后如何将所有Pod调度至同一节点
实现缩容后3个Pod聚合到同一节点的落地方案
先理清当前问题的根因
默认Kubernetes和AKS组件的联动逻辑根本没法自动满足你的预期:
- 执行Deployment缩容时,控制器只会按Pod创建时间、健康状态挑要删的对象,完全不管Pod现在在哪个节点上,也不会主动把剩下正在运行的Pod重新调度到一起。
- AKS的Cluster Autoscaler只有在节点整体资源利用率低于阈值、且持续指定时间后,才会触发节点回收。哪怕节点上只剩1个该服务的Pod,只要它占着节点资源没被赶走,Autoscaler就不会认为这个节点是可以回收的,最后自然会出现3个Pod散在2-3个节点、空跑资源的情况。
具体实现步骤
1. 调整Deployment调度规则,兼顾早晚扩容/缩容的运行场景
千万别用硬亲和强制所有同服务Pod必须在同一节点,不然早间扩容到9个副本时,调度器会因为单节点根本塞不下9个Pod,直接卡得所有新Pod一直Pending。要搭配软优先级规则适配两种场景:
- 配置最高优先级的软Pod亲和:拓扑域设为
kubernetes.io/hostname,匹配当前Deployment的Pod标签,权重拉满到100。效果是只要某个节点已经跑了这个服务的Pod,后续新调度的同服务Pod会优先往这个节点凑,不会被随机打散。 - 配置松弛的拓扑分布约束:设置
maxSkew: 1,约束不满足时的规则设为ScheduleAnyway(也就是软约束)。效果是早间扩容到9个副本时,调度器会尽量把Pod均匀打散到3个节点,每个节点跑满3个,刚好匹配单节点的资源上限;晚间缩到3个副本时,软约束不会硬逼着把Pod分散到多个节点,优先服从更高权重的亲和规则。
2. 改造晚间定时缩容的执行逻辑
别直接跑kubectl scale deployment <deployment-name> --replicas=3做硬缩容,按两步走的流程执行就能实现Pod聚合:
- 缩容前先扫描所有当前跑着该Deployment Pod的节点,选已经承载最多该服务Pod、剩余资源刚好能容纳3个Pod的节点,作为目标聚合节点。
- 对其他所有承载该Deployment Pod的节点,先执行
kubectl cordon <node-name>禁止新Pod调度进来,再用带优雅停机的驱逐命令把这些节点上属于目标Deployment的Pod赶走,参考命令:kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data --grace-period=30,注意千万别误驱逐节点上其他无关的工作负载。 - 等所有Pod重新调度到目标节点、3个副本全部就绪后,再对之前cordon的节点执行
kubectl uncordon,让Cluster Autoscaler按配置的回收策略,自动把没有负载的空节点缩掉。
3. 用Descheduler做自动兜底
如果不想写复杂的缩容脚本,可以在集群内部署Descheduler组件自动优化Pod分布:
- 配置Descheduler的
RemoveDuplicates策略,仅匹配目标Deployment的标签,检测散落在其他节点的同服务Pod,执行优雅驱逐让其重新调度。 - 把Descheduler的执行时间和每日晚间缩容的时间点对齐,缩容完成后自动跑一轮调度优化,把分散的Pod聚到同一个节点。
- 记得给Descheduler配置排除规则,别影响其他有固定亲和性要求的工作负载。
避坑提醒
- 绝对不要把Pod亲和性设成硬约束,早间扩容时一定会踩坑。
- 检查AKS Cluster Autoscaler的
scale-down-unneeded-time参数,别设太长(建议10-15分钟),不然空节点占半天不回收,平白产生资源成本。 - 驱逐Pod时要设置和应用匹配的优雅停机宽限时间,别因为驱逐导致流量中断。
内容的提问来源于stack exchange,提问作者Geert
相关产品推荐
相关产品推荐

