【Kubernetes】Pod 之 Scheduler 策略

203 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情

一、预选策略 (Predicates Policies)

预选策略的主要目的是过滤掉不符合条件的 Node 节点,预选策略大体上可以分为如下 4 类:

  • GeneralPredicates:负责最基础的调度策略

  • Volume 相关的过滤规则:负责与容器持久化 Volume 相关的调度策略

  • Node 相关的过滤规则:负责考察待调度 Pod 是否满足 Node 本身的一些条件

  • 与已运行 Pod 相关的过滤规则:负责检查待调度 PodNode 上已有 Pod 之间的亲和性关系

当开始调度 Pod 时,调度器会同时开启多个协程并发进行 Predicates 过滤,每个协程按照固定的顺序进行过滤,最后返回过滤后可以运行 PodNode 列表。

(1)GeneralPredicates

是最基础的调度策略,这个接口也会被其它组件直接调用,比如 kubelet 在启动 Pod 前会再执行一遍 GeneralPredicates 用于二次确认。

它包含的具体策略有:

  • PodFitsResources:计算 NodeCPU、内存、扩展资源(如 GPU)是否够用
  • PodFitsHost:检查 Node 的名字是否跟 Podspec.nodeName 匹配
  • PodFitsHostPorts:检查 Pod 申请的 Node 端口是否冲突
  • PodMatchNodeSelector:检查 Node 是否能匹配 PodnodeSelectornodeAffinity

(2)与 Volume 相关的过滤规则

它包含的具体策略有:

  • NoDiskConflict:检查 Node 上所有的 Pods 是否与待调度 Pod 的 Volume 有冲突,比如 AWS、GCE 的

  • Volume 不能被两个 Pod 同时使用

  • VolumeZonePredicate:检查 Pod Volume 的 zone 标签是否与节点的 zone 标签匹配,如果 Node 没有 zone 标签就认定为匹配

  • MaxPDVolumeCountPredicate:检查 Node 上某种类型的 Volume 是否已经超过指定数目

  • CSIMaxVolumeCountPredicate:检查 CSI Volume 相关的限制

  • VolumeBindingPredicate:检查 Pod 对应的 Local PV 的 nodeAffinity 字段,是否跟某个 Node 标签相匹配。如果该 Pod PVC 还没有绑定 PV,调度器要检查所有待绑定的 PV,且该 PV 的 nodeAffinity 是否与 Node 标签匹配

(3)与 Node 相关的过滤规则

它包含的具体策略有:

NodeConditionPredicate:检查 Node 是否还未准备好或处于 NodeOutOfDiskNodeNetworkUnavailable 状态,或者 Nodespec.Unschedulable 设置为 true,如果出现以上的情况,该 Node 都无法被调度 PodTolerateNodeTaints:检查 Nodetaint(污点)机制,只有当 PodTolerationNodeTaint 匹配时,Pod 才能调度到该 NodeNodeMemoryPressurePredicate:检查 Node 的内存是否不够使用 NodeDiskPressurePredicate:检查 Node 的磁盘是否不够使用 NodePIDPressurePredicate:检查 NodePID 是否不够使用

(4)与已运行 Pod 相关的过滤规则

它包含的具体策略主要是:PodAffinityPredicate,用于检查待调度 PodNode 上已有 Pod 之间的亲和性与反亲和性关系。


二、优选策略 (Priorites Policies)

通过前面预选策略过滤出来的 Node 列表,会再一次使用优选策略为这些 Node 打分,最终得分最高的 Node 会作为该 Pod 的调度对象。

有多个优选策略就相当于有多个打分函数,那么总得分的计算公式为:

总分 = (打分函数 1 * 权重 1) + (打分函数 2 * 权重 2) + ... + (打分函数 3 * 权重 3),打分函数的打分范围为 0 - 10 分,0 表示非常不合适,10 表示非常合适。每个打分函数都可以配置对应的权重,默认权重值为 1,如果某个打分函数特别重要就可以增加该权重值。

常用的优选策略有:

  • LeastRequestedPriority:选出空闲资源(CPU & Memory)最多的 Node

  • BalancedResourceAllocation:主要用于资源平衡,选出各项资源分配最均衡的 Node,避免出现某些 Node CPU 被大量分配,而 Memory 大量剩余的情况

  • SelectorSpreadPriority:为了更好容灾,对属于同一个 Service 或是 RC 的多个 Pod 副本,尽量调度到多个不同的 Node 上

  • InterPodAffinityPriority:优先将 Pod 调度到相同的拓扑上(如同一个节点、Rack、Zone 等)

  • NodeAffinityPriority:优先调度到匹配 NodeAffinity 的 Node 上

  • TaintTolerationPriority:优先调度到匹配 TaintToleration 的 Node 上

  • ImageLocalityPriority:优先选择已经存在 Pod 所需 Image 的 Node(已注册但默认未使用)

  • MostRequestedPriority:优先选择已经使用过的 Node,适用于 cluster-autoscaler(已注册但默认未使用)


三、自定义调度器

除了使用集群自带的调度器,也可以编写自定义的调度器,然后在 Pod YAML 文件中通过参数 spec.schedulername 指定调度器的名称,这样在 Pod 创建时就会使用自定义的调度器而不是集群默认的调度器。

比如:

apiVersion: v1
kind: Pod
metadata:
  name: Pod-example
spec:

使用自定义调度器 my-scheduler

schedulername: my-scheduler
containers:
  - name: nginx
    image: nginx

而自定义调度器的实现逻辑依然是:读取 API ServerPod 列表,通过特定算法找到最适合的 Node,然后把调度结果写回到 API Server