亚马逊AWS官方博客
在Amazon EKS上部署自定义scheduler实现binpack调度策略
Amazon EKS默认开启的资源调度策略是LeastRequestedPriority,意味着消耗资源最少的节点会优先被调度,这样使得集群的资源在所有节点之间分配的相对均匀。但在一些特定的批处理负载场景下(例如机器学习、数据分析),当集群配置了弹性伸缩,作业发起的Pod总是默认均匀的分布在所有集群节点上,导致很多节点运行着少量独立pod,无法被Cluster Autoscaler组件及时回收,从而造成集群资源的浪费。目前亚马逊云科技推出了 Karpenter开源伸缩组件,该组件默认采用了binpack的机制分配适当的计算资源可以解决类似的问题,具体Karpenter的实现机制本文不作涉及,本文采用另外一种方式,通过在Amazon EKS上部署自定义调度器的方式来实现binpack的调度。
所谓binpack调度,原理是调度器在调度pod到节点的时候,预期在节点上保留最少的未使用 CPU 或内存。此策略最大限度地减少了正在使用的集群节点的数量,也降低了资源碎片。
LeastRequestedPriority和binpack的调度区别可以参考下图。
通过上图可以看到,在binpack的调度策略下,pod会集中使用节点资源。这样闲置的节点(上图中的node3)会被及时的回收掉以避免浪费。
我们要想在Amazon EKS上实现上述调度策略,因为Amazon EKS当前不支持直接修改kube-scheduler的配置增加自定义的KubeSchedulerConfiguration对象配置,所以本文指导用户在Amazon EKS部署自定义的调度器来实现。
实现原理
调度框架是面向 Kubernetes 调度器的一种插件架构, 它为现有的调度器添加了一组新的“插件” API。插件会被编译到调度器之中。插件可以实现一些自定义的调度策略。同时我们可以传递KubeSchedulerConfiguration配置给到Scheduler,通过配置文件定义调度框架所支持的不同阶段执行不同的调度行为。
自定义KubeSchedulerConfiguration配置
在配置文件中,为调度器定义扩展点使用哪些插件,禁用哪些插件。
利用Kubernetes Scheduler Framework实现binpack
我们可以在Kubernetes Scheduler Framework中使用Score插件RequestedToCapacityRatio,用于优选阶段给节点打分。将节点按我们希望的方式打分。我们可以将资源利用率为0的时候,得分0分,资源利用率为100时,得分10分,资源利用率越高,得分越高,则这个行为是Binpack的资源分配方式。
如图:在Score阶段应用RequestedToCapacityRatio插件
配置多个scheduler共存
Kubernetes集群可以有多个调度器存在,默认调度器是default-scheduler,我们需要在调度器的配置文件中KubeSchedulerProfile 字段schedulerName 取个单独的名字,例如后面的my-scheduler
部署架构
如上文所述,Kubernetes支持在集群中部署多个scheduler,我们将自定义的scheduler以pod的形式部署在Amazon EKS的node上,有需要的pod部署的时候指定使用自定义scheduler实现调度,没有指定scheduler的pod将继续使用集群默认提供的default scheduler进行调度,这样我们可以将自定义的调度策略配置在单独部署的scheduler上以实现更复杂的调度来满足业务需求。
前提条件
本文使用Amazon EKS 1.21版本,不同版本配置会有差异
本地安装docker环境,用来进行镜像打包操作
方案部署步骤
构建自定义scheduler镜像
本文以官方scheduler镜像为例,首先下载Kubernetes对应版本的源码进行编译
构建scheduler 的Docker file和image
在Amazon ECR上创建repository,并将镜像push到Amazon ECR
在Amazon EKS上部署自定义scheduler
创建my-scheduler.yaml文件,修改对应的image url路径
其中我们在调度器的配置文件中,关闭了NodeResourcesLeastAllocated调度策略,开启了RequestedToCapacityRatio调度策略,从而实现binpack调度。
在Amazon EKS集群中应用yaml文件
观察scheduler是否正确部署在集群中
当显示my-scheduler的pod已经正常显示running状态为正常
验证自定义scheduler
创建 my-app.yaml文件,添加字段schedulerName: my-scheduler,指定使用my-scheduler作为调度器
在集群中创建deployment
观察调度效果(当前集群中有10台m5.4xlarge作为node,上面没有其它负载)。
删除schedulerName: my-scheduler字段,重新部署后观察效果
我们可以发现,在应用了自定义调度器的binpack调度策略后,pod会优先占满部分节点资源,而Kubernetes默认的调度策略,会将pod按最小资源使用率的方式均匀的分配在每个节点上。
需要留意的问题
维护scheduler增加了集群的复杂度,并且scheduler是个单点
EKS集群升级的时候scheduler也需要手工进行维护升级以避免兼容性问题
总结
目前Amazon EKS不支持直接修改kube-scheduler配置添加自定义的调度插件或配置,本文介绍了通过部署自定义scheduler的方式实现自定义的调度策略,针对本文中提到的binpack调度策略的需求,除了安装自定义scheduler的方式,我们也可以通过安装Karpenter、Apache yunikorn、Volcano等弹性伸缩或调度增强组件实现类似功能,具体可以参考相应的官方文档。
参考链接
https://v1-21.docs.kubernetes.io/docs/tasks/extend-kubernetes/configure-multiple-schedulers/
https://v1-21.docs.kubernetes.io/docs/concepts/scheduling-eviction/resource-bin-packing/
https://blog.cloudera.com/spark-on-kubernetes-gang-scheduling-with-yunikorn/