ScheduleAlgorithm是一个接口负责为pod选择一个合适的node节点,本节主要解析如何实现一个可扩展、可配置的通用算法框架来实现通用调度,如何进行算法的统一注册和构建,如何进行metadata和调度流程上下文数据的传递
1. 设计思考
1.1 调度设计
1.1.1 调度与抢占
当接收到pod需要被调度后,默认首先调用schedule来进行正常的业务调度尝试从当前集群中选择一个合适的node
如果调度失败则尝试抢占调度,根据优先级抢占低优先级的pod运行高优先级pod
1.1.2 调度阶段
在k8s的调度算法运行流程中,主要分为两个阶段:预选和优选,即从当前集群中选择符合要求的node,再从这些node中选择最合适的节点
1.1.3 节点选择
随着集群的增加集群中的node数量越来越多,k8s并不是遍历所有集群资源,而是只选取部分节点,同时借助之前说的 schedulerCache来实现pod节点的分散
1.2 框架设计
1.2.1 注册表与算法工厂
针对不同的算法,声明不同的注册表,负责集群中当前所有算法的注册,从而提供给调度配置决策加载那些插件,实现算法的可扩展性
并通过工厂模式来进行统一管理,解耦算法的注册与具体调度流程中的使用,由每个算法的工厂方法来接受参数进行具体算法的创建
1.2.3 metadata与PluginContext
在调度实际运行的过程中,需要集合当前集群中的元数据信息(node和pod)来进行具体算法的决策,scheduler采用PredicateMetadataProducer和PriorityMetadataProducer来进行元数据的构建, 其次针对一些可能被多个算法都使用的数据,也会在这里完成构建,比如亲和性的pod、拓扑等
并通过PluginContext进行本次调度上下文数据的存储,用于在多个调度算法之间存储数据进行交互
1.2.4 Provider
Provider主要是封装一组具体的预选和优选算法,并通过注册来实现统一管理, 其中系统内置了DefaultProvider
1.2.5 framework
framework是一种内部的扩展机制,通过定制给定的阶段函数,进行调度流程的影响,本节先不介绍
1.2.6 extender
一种外部的扩展机制,可以根据需要进行动态的配置,其实就是外部的一个service,但是相比framework可以使用自己独立的数据存储,实现对调度器的扩展
2. 源码分析
2.1 数据结构
type genericScheduler struct {
cache internalcache.Cache
schedulingQueue internalqueue.SchedulingQueue
predicates map[string]predicates.FitPredicate
priorityMetaProducer priorities.PriorityMetadataProducer
predicateMetaProducer predicates.PredicateMetadataProducer
prio