调度流程
kube-scheduler
是 kubernetes 的调度器,它的主要作用就是根据特定的调度算法和调度策略将 Pod 调度到合适的 Node 节点上去,是一个独立的二进制程序,启动之后会一直监听 API Server,获取到 PodSpec.NodeName 为空的 Pod,对每个 Pod 都会创建一个 binding。
1 | 调度器需要充分考虑诸多的因素: |
调度主要分为以下几个部分:
- 首先是预选过程,过滤掉不满足条件的节点,这个过程称为
Predicates
- 然后是优选过程,对通过的节点按照优先级排序,称之为
Priorities
- 最后从中选择优先级最高的节点,如果中间任何一步骤有错误,就直接返回错误
Predicates
Predicates
阶段首先遍历全部节点,过滤掉不满足条件的节点,属于强制性规则,这一阶段输出的所有满足要求的 Node 将被记录并作为第二阶段的输入,如果所有的节点都不满足条件,那么 Pod 将会一直处于 Pending 状态,直到有节点满足条件,在这期间调度器会不断的重试。
Priorities
Priorities
阶段即再次对节点进行筛选,如果有多个节点都满足条件的话,那么系统会按照节点的优先级(priorites)大小对节点进行排序,最后选择优先级最高的节点来部署 Pod 应用。
流程
1 | 1、首先,客户端通过 API Server 的 REST API 或者 kubectl 工具创建 Pod 资源 |
其中Predicates
过滤有一系列的算法可以使用:
- PodFitsResources:节点上剩余的资源是否大于 Pod 请求的资源
- PodFitsHost:如果 Pod 指定了 NodeName,检查节点名称是否和 NodeName 匹配
- PodFitsHostPorts:节点上已经使用的 port 是否和 Pod 申请的 port 冲突
- PodSelectorMatches:过滤掉和 Pod 指定的 label 不匹配的节点
- NoDiskConflict:已经 mount 的 volume 和 Pod 指定的 volume 不冲突,除非它们都是只读的
- CheckNodeDiskPressure:检查节点磁盘空间是否符合要求
- CheckNodeMemoryPressure:检查节点内存是否够用
Priorities
优先级是由一系列键值对组成的,键是该优先级的名称,值是它的权重值:
- LeastRequestedPriority:通过计算 CPU 和内存的使用率来决定权重,使用率越低权重越高,当然正常肯定也是资源是使用率越低权重越高,能给别的 Pod 运行的可能性就越大
- SelectorSpreadPriority:为了更好的高可用,对同属于一个 Deployment 或者 RC 下面的多个 Pod 副本,尽量调度到多个不同的节点上,当一个 Pod 被调度的时候,会先去查找该 Pod 对应的 controller,然后查看该 controller 下面的已存在的 Pod,运行 Pod 越少的节点权重越高
- ImageLocalityPriority:就是如果在某个节点上已经有要使用的镜像节点了,镜像总大小值越大,权重就越高
- NodeAffinityPriority:这个就是根据节点的亲和性来计算一个权重值,后面我们会详细讲解亲和性的使用方法
优先级源码函数:
1 | finalScoreNode = (weight1 * priorityFunc1) + (weight2 * priorityFunc2) + … + (weightn * priorityFuncn) |
自定义调度
调度器扩展
kube-scheduler
在启动的时候可以通过 --policy-config-file
参数来指定调度策略文件,我们可以根据我们自己的需要来组装Predicates
和Priority
函数。选择不同的过滤函数和优先级函数、控制优先级函数的权重、调整过滤函数的顺序都会影响调度过程。
下面是官方的 Policy 文件示例:
1 | { |
自定义调度
自定义调度器主要的功能是查询未调度的 Pod,按照自定义的调度策略选择新的 Node,并将其更新到 Pod 的 Node Binding 上。
比如,一个最简单的调度器可以用 shell 来编写(假设 Kubernetes 监听在 localhost:8001
):
1 | #!/bin/bash |
使用自定义调度器
1 | apiVersion: v1 |
优先级调度
Pod优先级、抢占功能,在kubernetes v1.8引入,在v1.11版本进入beta状态,并在v1.14版本进入GA阶段,已经是一个成熟的特性了。
顾名思义,Pod优先级、抢占功能,通过将应用细分为不同的优先级,将资源优先提供给高优先级的应用,从而提高了资源可用率,同时保障了高优先级的服务质量。
我们先来简单使用下Pod优先级、抢占功能。
我的集群版本是 v1.14,因此feature PodPriority
默认是开启的。抢占模式的使用分为两步:
- 定义PriorityClass,不同PriorityClass的value不同,value越大优先级越高。
- 创建Pod,并设置Pod的priorityClassName字段为期待的PriorityClass。
查看当前系统默认的优先级:
1 | [root@master101 scripts]# kubectl get priorityclasses.scheduling.k8s.io |
在指定 Pod 的优先级之前需要先定义一个 PriorityClass(非 namespace 资源),如
1 | apiVersion: v1 |
其中
value
为 32 位整数的优先级,该值越大,优先级越高globalDefault
用于未配置 PriorityClassName 的 Pod,整个集群中应该只有一个 PriorityClass 将其设置为 true
然后,在 PodSpec 中通过 PriorityClassName 设置 Pod 的优先级:
1 | apiVersion: v1 |