K8s调度器Kube-scheduler

kube-scheduler简介

    调度是容器编排的重要环节,需要经过严格的监控和控制,现实生产通常对调度有各类限制,譬如某些服务必须在业务独享的机器上运行,或者从灾备的角度考虑尽量把服务调度到不同机器,这些需求在Kubernetes集群依靠调度组件kube-scheduler满足。

    kube-scheduler是kubernetes中关键模块,扮演管家的角色遵从一套机制为Pod提供调度服务,例如基于资源的公平调度、调度Pod到指定节点、或者通信频繁的Pod调度到同一节点等。容器调度本身是一件比较复杂的事,因为要确保以下几个目标:

    1: 公平性: 在调度Pod时需要公平的进行决策, 每个节点都有被分配资源的机会,调度器需要对不同节点的使用作出平衡决策。

    2:资源高效利用: 最大化集群所有资源的利用率,使得有限的CPU、内存等资源服务更多的Pod运行

    3:效率问题:能够快速的完成对大批量Pod的调度工作,在集群规模扩增的情况下,依然可以保证调度过程的性能

    4:灵活性:在实际运作中,用户往往希望Pod的调度策略具备有可控性,从而处理大量复杂的实际问题,因此平台要允许多个调度器并行工作,同时支持定义自定义调度器

    为达到上述目标,kube-scheduler通过结合Node资源、负载情况、数据位置等各种因素进行调度判断,确保在满足场景需求的同时将Pod分配到最优节点。显然,kube-scheduler影响着Kubernetes集群的可用性与性能,Pod数量越多集群的调度能力越重要,尤其达到了数千级节点数时,优秀的调度能力将显著提升容器平台性能。

    

调度流程

kube-scheduler的根本工作任务是根据各种调度算法将Pod绑定(bind)到最合适的工作节点,整个调度流程分为两个阶段:预选策略(Predicates)和优选策略(Priorities)。

    1: 预选(predicates): 输入的所有节点,输出是满足预选条件的节点kube-scheduler根据预选策略过滤掉不满足策略的Nodes。例如,如果某节点的资源不足或者不满足预选策略的条件如“Node的label必须与Pod的Selector一致”时则无法通过预选。

    2:优选(priorities):输入是预选阶段选出的节点,优选会根据优先策略为通过预选的Nodes进行打分排名,选择得分最高的Node。例如,资源越富裕、负载越小的Node可能具有越高的排名。

    通俗点说,调度的过程就是在回答两个问题:1. 候选有哪些?2. 其中最适合的是哪个?

    值得一提的是,如果在预选阶段没有节点满足条件,Pod会一直处在Pending状态直到出现满足的节点,在此期间调度器会不断的进行重试。

    Pod的整个启动流程大致如下:

    1:资源管控中心Controller Manager 创建新的Pod, 将该Pod加入到待调度Pod列表

    2:kube-scheduler 通过API Server提供的接口监听Pods,获取待调度的Pod,经过优选和预选对各个Node节点进行打分排序,为待调度Pod列表中每个对象选择一个最优的Node

    3:kube-scheduler 将Pod与Node的绑定写入etcd

    4:节点代理服务kubelet通过API Server监听到Kube-scheduler产生的绑定信息,获取Pod列表,下载Image并启动容器,然后由kubelet 负责拉起Pod

    至此就完成Pod的调度和启动。

预选策略(predicates)

1:基于存储卷数量的判断

  • MaxEBSVolumeCount:确保已挂载的EBS存储卷数量不超过设置的最大值(默认39),调度器会检查直接或及间接使用这种类型存储的PVC,累加总数,如果卷数目超过设最大值限制,则不能调度新Pod到这个节点上。
  • MaxGCEPDVolumeCount:同上,确保已挂载的GCE存储卷数量不超过预设的最大值(默认16)。
  • MaxAzureDiskVolumeCount:同上,确保已挂载的Azure存储卷不超过设置的最大值(默认16)。

2:基于资源压力状态的判断

  • CheckNodeMemoryPressure:判断节点是否已经进入到内存压力状态,如果是则只允许调度内存为0标记的Pod。
  • CheckNodeDiskPressure:判断节点是否已经进入到磁盘压力状态,如果是,则不能调度新的Pod。

3:基于卷冲突的判断

  • NoDiskConflict:卷冲突判断,即如果该节点已经挂载了某个卷,其它同样使用相同卷的Pod将不能再调度到该节点。
  • NoVolumeZoneConflict:对于给定的某块区域,判断如果在此区域的节点上部署Pod是否存在卷冲突。
  • NoVolumeNodeConflict:对于某个指定节点,检查如果在此节点上部署Pod是否存在卷冲突。

4:基于约束关系的判断

  • MatchNodeSelector:检查节点标签(label)是否匹配Pod指定的nodeSelector,是则通过预选。
  • MatchInterPodAffinity:根据Pod之间的亲和性做判断。
  • PodToleratesNodeTaints:排斥性关系,即判断Pod不允许被调度到哪些节点。这里涉及到两个概念Taints(污点)和Toleration(容忍)。Node可以定义一或多个Taint,Pod可以定义一或多个Toleration,对于具有某个Taint的节点,只有遇到能容忍它的(即带有对应Toleration的)Pod,才允许Pod被调度到此节点,从而避免Pod被分配到不合适的节点。

5:基于适合性的判断

  • PodFitsResources:检查节点是否有足够资源(如CPU、内存、GPU等)满足Pod的运行需求。
  • PodFitsHostPorts:检查Pod容器所需的HostPort是否已被节点上其它容器或服务占用。如果已被占用,则禁止Pod调度到该节点。
  • PodFitsHost:检查Pod指定的NodeName是否匹配当前节点。

优选策略(Priorities)

优选过程会根据优选策略对每个候选节点进行打分,最终把Pod调度到分值最高的节点。kube-scheduler用一组优先级函数处理每个通过预选的节点,每个函数返回0-10的分数,各个函数有不同权重,最终得分是所有优先级函数的加权和,即节点得分。

优选的优先级函数包括:

  • LeastRequestedPriority(默认权重1):尽量将Pod调度到计算资源占用比较小的Node上,这里涉及两种计算资源:内存和CPU。计算公式如下:其中,capacity表示该节点的现有容量,requested表示Pod所请求的容量。
  • BalancedResourceAllocation(默认权重1):CPU和内存使用率越接近的节点权重越高。该策略均衡了节点CPU和内存的配比,尽量选择在部署Pod后各项资源更均衡的机器。该函数不能单独使用,必须和LeastRequestedPriority同时使用,因为如果请求的资源(CPU或者内存)大于节点的capacity,那么该节点永远不会被调度到。计算公式如下:
  • SelectorSpreadPriority(默认权重1):把属于同一个Service或者ReplicationController的Pod,尽量分散在不同的节点上,如果指定了区域,则尽量把Pod分散在该区域的不同节点。通常来说节点上已运行的Pod越少,节点分数越高。计算公式如下,是基于节点的计算和基于区域的计算的加权和,其中,maxPriority代表系数,默认为10,maxCount为节点最多允许运行的Pod数量,nodeCount为该节点已经存在的Pod数量,maxCountByZone为该区域最多允许的Pod数量,zoneCount为区域内已经运行的Pod数量。
  • NodeAffinityPriority(默认权重1):尽量调度到标签匹配Pod属性要求的节点,判断行为与预选中的MatchNodeSelector相似,未来可能会完全将其取代。

该函数提供两种选择器:requiredDuringSchedulingIgnoredDuringExecution和preferredDuringSchedulingIgnoredDuringExecution。前者是强要求,指定将Pod调度到节点上必须满足的所有规则;后者是弱要求,即尽可能调度到满足特定限制的节点,但允许不满足。计算公式如下,在节点满足requiredDuringSchedulingIgnoredDuringExecution后,该节点会累加preferredDuringSchedulingIgnoredDuringExecution中所有满足条件的规则的权值weight_i,CountWeight为preferredDuringSchedulingIgnoredDuringExecution中所有规则的权值总和:

InterPodAffinityPriority(默认权重1):叠加该节点已调度的每个Pod的权重,权重可配置文件里设定,通常亲和性越强的Pod权重越高,如果Pod满足要求则将加到权重和,具有最高权重和的节点是最优的。提供两种选择器:requiredDuringSchedulingIgnoredDuringExecution(保证所选的主机必须满足所有Pod对主机的规则要求)、preferredDuringSchedulingIgnoredDuringExecution(调度器会尽量但不保证满足NodeSelector的所有要求)。

  • 计算公式如下,其中,weight_i为节点上符合亲和性的每个Pod的权重,sumCount为节点上符合亲和性的Pod权重和,maxCount为节点上所有Pod的权重和,minCount为节点上最小的Pod权重,maxPriority是系数,默认为10。
  • NodePreferAvoidPodsPriority(默认权重10000):避免将ReplicationController或ReplicaSet调度到节点。如果Pod由RC或者RS的Controller调度,则得分为0,不对最终加权得分产生影响;如果不是,则总分为100000,意味着覆盖其他策略,直接决定最优节点。
  • TaintTolerationPriority(默认权重1):Pod与Node的排斥性判断。通过Pod的tolerationList与节点Taint进行匹配,配对失败的项越少得分越高,类似于Predicates策略中的PodToleratesNodeTaints。计算公式如下:其中,totalTaints表示Taint总个数,intolerableTaints表示配对不成功的个数。
  • ImageLocalityPriority(默认权重1):尽量调度到Pod所需镜像的节点。检查Node是否存在Pod所需镜像:如果不存在,返回0分;如果存在,则镜像越大得分越高。计算公式如下:其中,sumSize表示该节点上存在的Pod所需镜像大小总和,maxImgSize表示Pod所需镜像总大小,minImgSize表示Pod所需最小镜像的尺寸。
  • EqualPriority(默认权重1):给予所有节点相等权重,一般仅用于测试。
  • MostRequestedPriority(默认权重1):适用于动态伸缩集群环境,会优先调度Pod到使用率最高的节点,方便在伸缩集群时,先腾出空闲机器,从而进行停机处理。

  目前kube-scheduler已经提供了丰富的调度策略可供使用,一般情况下,使用kube-scheduler的默认调度策略就能满足大部分需求,并且其插件化的形式也方便于用户进行定制与二次开发。未来,我们会在此基础上对其进一步优化:包括增加cache以减少predict和prioritize阶段的重复计算,已在TOS 1.9中实现;通过scheduler-extender扩展来针对local Volume、GPU等资源实现更合理调度;适配custom-metrics-server的API来实现实时调度,使得每个节点的资源能更好的被利用。

发布了103 篇原创文章 · 获赞 10 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/CodeAsWind/article/details/104353955