Kubernetes调度器的核心,是两个相互独立的控制循环
- Informer Path
- Scheduling Path
Informer 负责监听 etcd 中的 Pod、Node、Service 等与调度相关的API对象的变化。
Scheduling 是负责调度的主循环,主要功能是不断地从调度队列里提取Pod,然后根据 从从Scheduler Cache中或得的 节点信息 对节点进行打分 0-10,得分最高的节点作为这次调度的结果
调度算法完成之后,调度器将Pod对象的NodeName字段值修改为上述节点的名字,称作 bind
先Predicates(预选)再Priorities(优选)
Kubernetes 中默认的调度策略有以下4种
- GeneralPredicates
最基本的调度策略,例如计算cpu和内存资源是否够用
2. Volume相关的过滤规则
检查PV是否冲突等
3. 宿主机相关的规律规则
检查Node污点等
4. Pod相关过滤规则
检查Pod亲和性等
以上4种策略作为Filter,用来确定一个节点是否可以运行待调度的Pod的基本策略
为了不在关键调度路径中远程访问 API Server,Kubernetes 在默认调度器在Bind阶段只会更新 Scheduler Cache里的 Pod 和 Node 的信息。这种基于乐观假设的API对象更新方式叫做 Assume。
Assume完成之后,调度器才会创建一个Goroutine来异步地向API Server发起更新Pod的请求,来真正完成Bind操作。如果异步请求失败,等Scheduler Cache同步之后一切就会恢复正常。
在异步Bind结束之后,新的Pod真正被调度之前,该节点上的Kubelet海辉通过一个叫做admit的操作来再次验证该Pod是否可以在该节点上运行,也就是把GeneralPredicates的基本调度算法(资源是否可用、端口是否冲突)等再执行一遍,作为Kubelet的二次确认。
优选策略的工作是为这些节点打分
优选策略最长使用的打分规则是 LeastRequestedPriority
score = (cpu((capacity-sum(requested))10/capacity) + memory((capacity-sum(requested))10/capacity
与 LeastRequestedPriority 一起发挥作用的还有 BalancedResourceAllocation
score = 10 - variance(cpuFraction,memoryFraction,volumeFraction)*10
每种资源的 Fraction 的定义是 Pod 请求的资源/节点上的可用资源,variance算法的作用是计算每两种资源Fraction之间的“距离”,最后选择的是资源Fraction差距最小的节点。
BalancedResourceAllocation 选择的是所有节点里各种资源分配最均衡的那个节点,从而避免一个节点上CPU被大量分配,而内存大量剩余的情况
此外还有3种优选策略:NodeAffinityPriority、TaintTolerationPriority 和 InterPodAffinityPriority,作为优选策略,一个节点满足上述规则的字段数目越多,它的得分就会越高
在默认的优选策略里,还有一个叫做 ImageLocalPriority 的策略。它是在Kubernetes v1.12 里提供的调度规则,即如果待调度的Pod需要使用很大的镜像,并且已经存在于某些节点上,那么这些节点的得分会比较高
当然为了避免调度堆叠,调度器在计算得分时还会根据镜像的分布进行优化,即如果大镜像分布的节点数目很少,那么这些节点的权重会被调低,从而 对冲 引起调度堆叠的风险。