默认调度器中介绍了调度器使用的两组算法,这里就对这两种算法进行说明。

Predicates

负责从所有节点中选择能够运行Pod的节点,可以看作是一个过滤器,将所有不符合条件的节点进行过滤掉。 默认的调度类型有四种。

GeneralPredicates

负责最基础的调度策略,也就是宿主机的内存和cpu等资源是否充足。 例如:

  • PodFitsResources检查Pod的requests资源。
  • PodFitsHost检查宿主机的名字与nodeName字段是否一致。
  • PodFitsHostPort检查Pod申请的端口是否已被占用
  • PodMatchNodeSelector 检查的是,Pod 的 nodeSelector 或者 nodeAffinity 指定的节点,是否与待考察节点匹配,等等。

kubelet 在启动 Pod 前,会执行一个 Admit 操作来进行二次确认。这里二次确认的规则,就是执行一遍 GeneralPredicates。

Volume相关的过滤规则

这组过滤规则与持久化相关

  • NoDiskConflict 检查的条件,是多个 Pod 声明挂载的持久化 Volume 是否有冲突。
  • MaxPDVolumeCountPredicate 检查的条件,则是一个节点上某种类型的持久化 Volume 是不是已经超过了一定数目。
  • VolumeZonePredicate,则是检查持久化 Volume 的 Zone(高可用域)标签,是否与待考察节点的 Zone 标签相匹配。

宿主机相关过滤规则

主要考察待调度Pod是否满足Node本身的条件。

  • PodToleratesNodeTaints,负责检查的就是我们前面经常用到的 Node 的“污点”机制。只有当 Pod 的 Toleration 字段与 Node 的 Taint 字段能够匹配的时候,这个 Pod 才能被调度到该节点上
  • NodeMemoryPressurePredicate,检查的是当前节点的内存是不是已经不够充足,如果是的话,那么待调度 Pod 就不能被调度到该节点上。

Pod相关过滤规则

这组规则与GeneralPredicates大多数是重合的。

比较特殊的,是 PodAffinityPredicate。这个规则的作用,是检查待调度 Pod 与 Node 上的已有 Pod 之间的亲密(affinity)和反亲密(anti-affinity)关系。

在具体执行的时候, 当开始调度一个 Pod 时,Kubernetes 调度器会同时启动 16 个 Goroutine,来并发地为集群里的所有 Node 计算 Predicates,最后返回可以运行这个 Pod 的宿主机列表

调度器会按照固定的顺序来进行检查。这个顺序,是按照 Predicates 本身的含义来确定的。比如,宿主机相关的 Predicates 会被放在相对靠前的位置进行检查。要不然的话,在一台资源已经严重不足的宿主机上,上来就开始计算 PodAffinityPredicate,是没有实际意义的。

Priorities

在Predicates完成过滤之后,我们就获得了可以调度Pod的节点,接下来就是选择一个最合适的节点进行调度了。使用Priorities对节点进行打分。

最常用的一个打分规则,就是LeastRequestedPriority,计算方法可以总结为下面的公式:

score = (cpu((capacity-sum(requested))10/capacity) + memory((capacity-sum(requested))10/capacity))/2

其实就是选择CPU和内存空闲资源最多的节点。

同时一起起作用的还有BalancedResourceAllocation,可以看一下计算公式:

score = 10 - variance(cpuFraction,memoryFraction,volumeFraction)*10

每种资源的 Fraction 的定义是 :Pod 请求的资源 / 节点上的可用资源。而variance是计算每两种资源之间距离最小的,也就是选择资源Fraction差距最小的节点。

所以说,BalancedResourceAllocation 选择的,其实是调度完成后,所有节点里各种资源分配最均衡的那个节点,从而避免一个节点上 CPU 被大量分配、而 Memory 大量剩余的情况。让资源能够得到充分利用。

此外,还有 NodeAffinityPriority、TaintTolerationPriority 和 InterPodAffinityPriority 这三种 Priority。Node满足的规则越多,那么它的得分就会越高。

在实际的执行过程中,调度器里关于集群和 Pod 的信息都已经缓存化,所以这些算法的执行过程还是比较快的