0%

Kubernetes调度器

在Kubernetes中,调度器的主要职责就是为一个新创建出来的Pod寻找一个合适的节点Node,其工作流程可以下图表示。

img

Kubernetes 的调度器由两个相互独立的控制循环组成。

第一个控制循环称为Informer Path,其主要目的在于启动一系列的Informer,用来监听Etcd中的Pod、Node、Service等对象的变化。例如当一个Pod被创建出来后,调度器会通过Pod Informer将待调度的Pod添加到调度队列之中。

第二个控制循环称为Scheduling Path。其作用是不断的从调度队列中出对一个Pod,调用Predicates算法进行过滤。通过这一步过滤得到的一组Node就是所有可以运行这个Pod的宿主机列表。接下来就可以调用Priorities算法为Node打分,分数从0到10,得分最高的Node就会作为本次调度的结果。在调度算法完成以后,调度器就会将Pod对象的nodeName字段修改为Node的名字,该步骤称为Bind。

Predicates

Predicates在调度过程中的作用就是从所有节点中去除一系列符合条件的节点。Kubernetes默认的调度策略有三种。

GeneralPredicates

GeneralPredicates负责最基础的调度策略,例如计算宿主机剩余的CPU和内存资源是否足够使用,检查宿主机的名字是否和Pod的spec.nodeName一致,申请的宿主机端口是否跟已经被使用的端口冲突,Pod 的 nodeSelector 或者 nodeAffinity 指定的节点,是否与待考察节点匹配。GeneralPredicates检查的是一个Pod能不能运行在Node上最基本的过滤条件。

Volume 相关的过滤规则

负责与容器持久化Volume相关的调度策略。例如多个 Pod 声明挂载的持久化 Volume 是否有冲突、一个节点上某种类型的持久化 Volume 是不是已经超过了一定数目、持久化 Volume 的 Zone(高可用域)标签,是否与待考察节点的 Zone 标签相匹配、Pod 对应的 PV 的 nodeAffinity 字段,是否跟某个节点的标签相匹配。

宿主机相关的过滤规则

检查Pod是否满足Node本身的一些条件,例如检查Pod 的Toleration字段与Node的Taint字段是否匹配,当前节点的内存是否足够。

Pod 相关的过滤规则

大部分与GeneralPredicates重合,特殊的在于还需检查待调度 Pod 与 Node 上的已有 Pod 之间的亲密(affinity)和反亲密(anti-affinity)关系。

上面四种类型的Predicates就构成了调度器确定一个 Node 可以运行待调度 Pod 的基本策略。

Priorities

Priorities阶段会根据不同Node的空闲资源,所有节点里各种资源分配最均衡,容器镜像是否存在以及容器镜像大小进行打分,打分的范围是 0-10 分,得分最高的节点就是最后被 Pod 绑定的最佳节点。

优先级和抢占机制

正常情况下,当一个Pod调度失败后,会被暂时搁置起来,直到Pod被更新或者集群状态发生变化,调度器才会对这个Pod进行重新调度。但是有时候希望一个高级别的Pod调度失败以后,该Pod并不会被搁置,而是挤走某个Node上的低优先级Pod,保证这个高优先级的Pod调度成功。

在调度其中维护着一个调度队列,当Pod拥有了优先级以后,高优先级的Pod可能会比低优先级的Pod提前出队,从而尽早地完成调度过程。

当一个高优先级的Pod调度失败的时候,调度器的抢占能力就会被出发,调度器试图从当前集群中寻找一个节点,使得当这个节点上的低优先级Pod被删除后,待调度的高优先级Pod能够被调度到该节点上,这个过程就被称为抢占。

在Kubernetes中,在调度队列的视线中有两个不同的队列,第一个队列叫做activeQ,存储在下一个调度周期需要调度的对象。第二个队列叫做unschedulableQ,专门存放调度失败的Pod。当一个 unschedulableQ 里的 Pod 被更新之后,调度器会自动把这个 Pod 移动到 activeQ 里,重新进行调度。

当发生调度失败时,该Pod就会被放到unschedulableQ中,触发调度器为抢占者寻找牺牲者的流程。首先会检查这次失败事件的原因,确认抢占是不是可以帮助抢占者找到一个新节点。如果确定抢占可以发生,那么调度器就会把自己缓存的所有节点信息复制一份,然后使用这个副本来模拟抢占过程。在模拟过程中,调度器会检查每一个节点,从节点的最低优先级的Pod开始,逐一删除这些Pod,每删除一个低优先级Pod,调度器就会检查抢占者能够运行在该Node上。调度器会在模拟的所有抢占结果中做出一个选择,判断抢占对整个系统的影响,找出最佳结果。

当得到了最佳的抢占结果后,调度器就会真正的开始抢占的操作,删除被抢占者,让抢占者在下一个调度周期重新进入调度流程,之后调度器就会通过正常的调度流程把抢占者调度成功。