kube-scheduler
目录:
kube-scheduler的介绍
kube-scheduler功能比较单一,为pod选择node节点,流程也简单
- 获取未调度的Podlist
- 通过算法为pod选择node
- 数据提交到apiserver
kube-scheduler的启动
启动主要使用的Run方法
- 初始化Scheduler,
scheduler.New
- 启动事件广播
- 启动kube-scheduler
- 启动http服务
- 启动informer
- 执行sched.Run()调度逻辑
scheduler.New
- 加载scheduler配置文件
- 加载默认算法
- 创建scheduler对象
informer只监听status.phase不为succeeded和failed的pod,不为terminating的pod
informer的cache创建完,会启动sched.scheduleOne方法,流程是
- 从调度队列获取pod,如果pod不符合就跳过
- 执行sched.schedule()返回最佳的node
- 过滤算法没合适的就返回core.FitError
- core.FitError的pod是否启动抢占策略,如果启动则执行抢占策略
- 调用sched.assumeVolumes判断了是否启动VolumeScheduling策略
- 调用fwk.RunReservePlugins执行reserve plugin
- pod的spec.NodeName设置为选择的node,更新scheduler cache
- 异步写入apiserver
- 调用fwk.RunPermitPlugins执行permit plugin
- 调用fwk.RunPreBindPlugins执行prebind plugin
- 调用fwk.RunPostBindPlugins执行postbind plugin
sched.schedule()调用的sched.Algorithm.Schedule()
- 调用podPassesBasicChecks检查pod的pvc
- 调用g.framework.RunPreFilterPlugins执行prefilter plugins
- 调用g.cache.NodeTree().NumNodes()和g.snapshot获取scheduler cache
- 调用g.findNodesThatFit()预选算法
- 调用g.framework.RunPostFilterPlugins执行postfilter plugin
- 如果node为0直接返回失败的error,如果node数为1直接返回该node
- 执行g.priorityMetaProducer()计算pod的metadata,检查该node上是否有相同meta的pod
- 执行PrioritizeNodes()算法
- 执行g.selectHost()通过得分选择一个最佳的node
predicates和priorities调度算法
predicates用于过滤node
func defaultPredicates() sets.String {
return sets.NewString(
predicates.NoVolumeZoneConflictPred, //
predicates.MaxEBSVolumeCountPred,
predicates.MaxGCEPDVolumeCountPred,
predicates.MaxAzureDiskVolumeCountPred,
predicates.MaxCSIVolumeCountPred,
predicates.MatchInterPodAffinityPred,
predicates.NoDiskConflictPred,
predicates.GeneralPred,
predicates.CheckNodeMemoryPressurePred,
predicates.CheckNodeDiskPressurePred,
predicates.CheckNodePIDPressurePred,
predicates.CheckNodeConditionPred,
predicates.PodToleratesNodeTaintsPred,
predicates.CheckVolumeBindingPred,
)
}
算法主要分五类
第一类GeneralPredicates类型,这个类型会在kubelet启动pod的时候使用Admit操作再次确认
- PodFitsHost检测node是否匹配Pod的spec.nodeName
- PodFitsHostPorts检测node是否匹配Pod的spec.nodePort是否冲突
- PodMatchNodeSelector检测node是否匹配nodeSelector和nodeAffinity
- PodFitsResources检测node是否满足pod的request需求
第二类与Volume相关,包括NoDiskConflictPred、MaxGCEPDVolumeCountPred、MaxAzureDiskVolumeCountPred、MaxCSIVolumeCountPred、MaxEBSVolumeCountPred、NoVolumeZoneConflictPred、CheckVolumeBindingPred
第三类是宿主机相关的过滤规则,主要是PodToleratesNodeTaintsPred
第四类是Pod相关的过滤规则,主要是MatchInterPodAffinityPred
第五类是新增的过滤规则,与宿主机运行情况有关,包括CheckNodeCondition、 CheckNodeMemoryPressure、CheckNodePIDPressure、CheckNodeDiskPressure,如果启动了TaintNodesByCondition,则不进行以上四种,TaintNodesByCondition会为node打上pressure的taint,v1.13默认启用
预选算法会设定最多需要检查的节点数,提高效率
- 如果node节点数小于minFeasibleNodesToFind(默认100)直接返回了所有node
- 如果node节点数大于minFeasibleNodesToFind,根据percentageOfNodesToScore(默认50)百分比的节点数
- 如果百分比数目后仍然大于minFeasibleNodesToFind,则返回百分比,如果小于,则返回minFeasibleNodesToFind
最后并发执行podFitsOnNode
priorities用于给node打分
func defaultPriorities() sets.String {
return sets.NewString(
priorities.SelectorSpreadPriority,
priorities.InterPodAffinityPriority,
priorities.LeastRequestedPriority,
priorities.BalancedResourceAllocation,
priorities.NodePreferAvoidPodsPriority,
priorities.NodeAffinityPriority,
priorities.TaintTolerationPriority,
priorities.ImageLocalityPriority,
)
}
每个函数有打分0~10,并且每个函数有权重,最后返回一个加权评分
优先级和抢占机制
调度器维护了两个调度队列
- activeQ 用于新的pod调度
- unschedulableQ 用于存放调度失败,pod被更新之后就会移动到activeQ
pod调度失败后会直接执行抢占的逻辑,sched.preempt用于执行抢占的逻辑
- 获取pod的info
- 调用sched.Algorithm.Preempt()执行抢占,成功返回node和被抢占的pod
- 更新scheduler缓存,为抢占pod绑定nodeName,设定pod.Status.NominatedNodeName
- 将pod的info提交到apiserve
- 删除被抢占的pods和其上的NominatedNodeName
抢占的过程并不会直接调度到对应的node,而是设置status.nominatedNodeName,让抢占的pod进入下一个调度周期,调度不保证一定会运行在被抢占的node上
因为删除了被抢占的pod会退出,在这过程其他的node可以被调度,或者有更高优先级被pod需要进行抢占
sched.Algorithm.Preempt()调用了
- nodesWherePreemptionMightHelp 过滤
predicates
算法执行失败的node - selectNodesForPreemption 过滤出可以抢占的node列表
- pickOneNodeForPreemption 选出最佳的node
- getLowerPriorityNominatedPods 移除低优先级pod的Nominated,更新pod的状态移入activeQ队列
selectNodesForPreemption获取node上可以被抢占的pod,模拟移除低优先级的pod是否能调度成功,如果可以pod将PDB(中断预算保证pod高可用)分成violatingVictims和nonViolatingVictims,将pod根据优先级,将高优先级的模拟加回node中,直到node不能调度,返回victims和需要删除的pod数量
pickOneNodeForPreemption进行排序的原则
- node的numViolatingVictim最低
- 挑选具有高优先级较少的node
- node上所有victims的优先级进项累加,选取最小的
- 选择victims pod数最少的Node
- 具有高优先级且pod运行时间最短的
- random
kubectl get pod -o wide -w
可以看到NOMINATED NODE