重新审视计算扩展
背景介绍
在我们之前的博客文章《使用基于属性的实例选择微调AWS ASG》中提到,我们最近开始了一段激动人心的旅程,旨在增强Kubernetes集群的节点自动扩展基础设施。在这篇博客中,我们将深入探讨从内部开发的Clusterman自动扩展器迁移到AWS Karpenter的原因。
Clusterman及其挑战
在Yelp,我们使用Clusterman来处理Kubernetes集群中节点的自动扩展。这是一个我们最初为Mesos集群设计、后来适配Kubernetes的开源工具。Clusterman不管理整个集群,而是专注于池的管理,每个池由AWS自动扩展组支持的节点组组成。
尽管功能强大,Clusterman仍面临挑战:
- 设置点难题:寻找完美的设置点是一项棘手的任务
- 资源管理循环:节点删除和创建可能导致无休止的扩展循环
- 工作负载需求不匹配:无法考虑待处理Pod的特定需求
- 速度问题:基于间隔的逻辑难以跟上快速变化的工作负载需求
- 定制化困难:自定义回收标准需要修改代码
替代自动扩展器
需求收集
我们收集了在Kubernetes上运行工作负载的各团队的需求:
- 能够识别有状态待处理Pod卷的可用区并在相应区域启动新实例
- 支持具有不同GPU要求的多样化机器学习工作负载
- 适应工作负载约束,如拓扑分布约束和亲和性
选项评估
我们评估了两个主要选项:Kubernetes Cluster Autoscaler和Karpenter。
Karpenter的优势:
- 更好的装箱:通过创建待处理Pod批次并在启动实例前考虑工作负载资源需求
- 基于池的隔离:使用nodepools提供更好的迁移路径
- 可自定义TTL:支持为节点指定生存时间
- 成本优化:自动删除节点、替换按需实例、终止实例以替换为更大实例
- 增强的调度:使用有用标签丰富节点
- Spot市场回退机制:在同一池中运行Spot和按需实例
- 有洞察力的指标:提供有用的指标套件
迁移策略
我们决定通过逐步缩减ASG容量来替换节点。虽然节点删除导致池中出现不可调度的Pod,但Karpenter有效检测到这些Pod并快速扩展必要资源。
我们之前为所有工作负载添加的Pod中断预算在迁移过程中发挥了关键作用。
监控仪表板
我们开发了全面的仪表板来监控迁移过程:
- ASG容量与Karpenter容量对比
- 每小时资源成本
- Spot中断率
- 自动扩展器支出效率
- 扩展事件
- 不可调度Pod和Pod调度时间洞察
- 工作负载错误率
经验教训
Spot实例分配策略
Karpenter使用价格容量优化分配策略,虽然最初担心成本增加,但实际使用中发现它不仅显著减少了Spot中断,而且具有成本效益。
为关键服务HPA保留空闲资源
我们通过运行具有特定PriorityClass的虚拟Pod来确保始终为高优先级工作负载提供缓冲容量。
使Karpenter与集群配置实践保持一致
我们遇到了临时存储需求高的工作负载问题,因为Karpenter无法识别启动模板中的存储修改。通过使用NodeClass中的blockDeviceMappings解决了这个问题。
性能和可扩展性
AWS Karpenter比Clusterman更快:
- Clusterman依赖定期检查,导致检测和响应不可调度Pod的延迟
- Karpenter利用Kubernetes事件的力量,实时检测和响应不可调度Pod
在可扩展性方面:
- Clusterman存储所有Pod和节点信息的方法面临内存挑战
- Karpenter仅存储内存中的基本信息,避免从kube-apiserver读取所有资源的性能瓶颈
我们创建的新指标显示,Karpenter在所有池中平均提高了25%的支出效率。
结论
最初,Clusterman对Yelp来说是最优且实用的解决方案,特别是在从Mesos迁移到Kubernetes期间。但随着所有工作负载迁移到Kubernetes,维护Clusterman变得开销很大,并且缺乏运行当前工作负载所需的关键功能。