Big Picture

K8S的调度说实话一般没啥人改,因为一般的体量,基于K8S内置的算法基本就满足了,但对于大体量和特殊场景来说,还是很有必要进行修改的,比如假设有好几种业务场景的pod,需要按需要调度到不同的rack上,传统做法当然可以对Node进行label,然后在不同业务的pod上做match,同样的,也可以修改调度器,在调度的时候自动进行调度,类似的场景有点像openstack的filter模块,所以理解K8S的调度还是非常有必要,毕竟先了解了,才能修改。

informer机制,调度的开始

K8S的内部通信都是基于HTTP的,一个控制器每次需要获取对象的时候都要访问 APIServer,这会给APIServer带来很高的压力,所以K8S 使用了一个叫做Informers 的内存缓存来解决这个问题,Informer可以几乎实时的监控对象的变化,而不需要轮询请求,这样就可以保证客户端的缓存数据和服务端的数据一致,就可以大大降低 APIServer 的压力了。

在这里插入图片描述

K8S的调度器会通过Informer,WATCH对于的API 对象,一旦发生有新的API对象被创建出来,且nodeName 字段为空,则Kube-scheduler任务这是个待调度的资源,变会触发上那个图的event handlers,将该API对象加到待调度队列,等待后续操作,这便是调度的第一个大循环。

筛选过程,调度的过程

在筛选过程,K8S会从待调度队列里不停的拿出Pod,然后进行筛选,筛选的逻辑,分为两个步骤,分别为预选(Predicate)和优选(Priority)

  • 预选(Predicate):

预选会对所有Node进行初步的筛选,筛选出符合基本需求的Node列表,包含大致几种类型的选择规则:

  1. 基本预选
  2. 存储预选
  3. node规则预选
  4. pod规则预选
  • 优选(Priority):

优选过程其实就是一个打分的过程,在预选过程中,kube-scheduler会选出一个列表的基本符合需求的Node列表,然后优选过程会对该列表进行循环,将每个Node提取出来进行打分,分数从0-10,得分最高的,pod就会调度过去。

  • 绑定:

上面提到,在pod被informer WATCH到是新资源的时候,他的nodename字段为空,而在上述2个筛选算法结束之后,scheduler会将这个字段改成最终计算出来的node,这个动作就是最终的bind(绑定)。

预先过程

上面提到,调度器会先进行一次初步的筛选,筛选的目的是为了选出基本符合能让pod绑定成功的node列表,需要实现该包下的方法kubernetes/plugin/pkg/scheduler/algorithm/predicates,上面标识的4种预选规则,每个规则下都会有对应的预选方法:

a.基本预选

PodFitsResources: 基本资源的筛选,对比的pod的requests字段的值

PodFitsHost: node的名字是否跟 Pod 的 spec.nodeName 一致

PodFitsHostPorts: pod使用的端口是否已被node使用

PodMatchNodeSelector: nodeSelector之类的配置是否允许该node匹配到对应pod

基本预选会在优选完成后,绑定之前,再次执行一遍,避免在计算过程中资源变化导致最终的绑定失败

b.存储预选

NoDiskConflict: 多个pod挂在同一个卷是否会冲突,有些卷只能一个pod挂一个

MaxPDVolumeCountPredicate: 单个node的某种类型的持久化volume数量超过了阈值

VolumeZonePredicate: 任何volumes的zone-labels必须与节点上的zone-labels完全匹配,这个一般用公有云的存储资源会遇到,私有云目前没见过

volumeBindingPredicate: 检查pod和pv的亲和性检查

c.node规则预选

一般是检查pod和node 的基本特性,和基本预选有点类似。

PodToleratesNodeTaints: 检查pod上Tolerates的能否容忍污点(pod.spec.tolerations)

CheckNodeMemoryPressure: 检查内存是否存在压力

CheckNodeDiskPressure: 检查磁盘IO压力是否过大

CheckNodePIDPressure: 检查pid资源是否过大

d.pod规则预选

PodAffinityPredicate: 主要就是检查下亲和性和反亲和性是否匹配。

优选过程

优选过程会进行更加细致的选择,比如以下的方法:

least_requested: 选择消耗最小的节点(根据空闲比率评估 cpu(总容量-sum(已使用)*10/总容量))

balanced_resource_allocation: 从节点列表中选出各项资源使用率最均衡的节点(CPU和内存)

node_prefer_avoid_pods: 节点倾向

taint_toleration: 将pod对象的spec.toleration与节点的taints列表项进行匹配度检查,匹配的条目越多,得分越低

selector_spreading: 与services上其他pod尽量不在同一个节点上,节点上通一个service的pod越少得分越高

interpod_affinity: 遍历node上的亲和性条目,匹配项越多的得分越高

most_requested: 选择消耗最大的节点上(尽量将一个节点上的资源用完)

node_label: 根据节点标签得分,存在标签既得分,没有标签没得分。标签越多 得分越高

image_locality: 节点上有所需要的镜像既得分,所需镜像越多得分越高。(根据已有镜像体积大小之和)

个人公众号, 分享一些日常开发,运维工作中的日常以及一些学习感悟,欢迎大家互相学习,交流

在这里插入图片描述

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐