k8s默认scheduler的考虑的因素

k8s调度器根据一组规则去调度未分配Pod到相应的节点上,包括两个阶段,第一个阶段是过滤节点;第二个阶段是寻找最佳节点。[1][k8s调度器算法文档]

过滤节点

The purpose of filtering the nodes is to filter out the nodes that do not meet certain requirements of the Pod. For example, if the free resource on a node (measured by the capacity minus the sum of the resource requests of all the Pods that already run on the node) is less than the Pod’s required resource, the node should not be considered in the ranking phase so it is filtered out. Currently, there are several “predicates” implementing different filtering policies, including:

过滤节点的目的就是去掉那些不满足特定条件的节点,比如资源不足,那么这个节点将直接被过滤掉,不会进入优选阶段。目前,预选策略包括:

  • NoDiskConflict: 评估存储卷是否满足条件,并且是否已经挂载。只有支持类型的PVC才会被检测,不会检测直接挂载到pod的存储卷。
  • NoVolumeZoneConflict: 评估存储卷是否满足可用区限制
  • PodFitsResources: 检测CPU和内存是否满足Pod的要求,空闲资源是使用节点资源总量减去节点上所有Pod的请求值之和。
  • PodFitsHostPorts: 检测是否存在主机端口冲突
  • HostName: 根据NodeName字段过滤掉其他所有节点
  • MatchNodeSelector: 检测节点标签是否满足nodeSelector字段,并且同时满足nodeAffinity字段
  • MaxEBSVolumeCount: 检测单个实例挂载的EBS盘数量是否超出最大值
  • MaxGCEPDVolumeCount: 检测单个实例挂载的GCP盘数量是否超出最大值
  • CheckNodeMemoryPressure: 检测节点是否有内存压力
  • CheckNodeDiskPressure: 检测内存是否有磁盘压力

节点打分

通过第一节点过滤出来的节点可以安放Pod,而且通常有多个节点满足条件。k8s会通过优选来找到一个最合适的节点安放Pod,这通过一系列优先级函数集合实现。对于每个节点,每一个优先级函数都会给它打分,满分10分,10分代表最佳匹配,0代表不匹配。另外每个优先级函数都会有一个权重,最终的结果就是将所有权重分求和。举个例子,假设有两个优先级函数:priorityFunc1priorityFunc2,他们的权重分别是weight1weight2,那么节点NodeA的分数就是:

finalScoreNodeA = (weight1 * priorityFunc1) + (weight2 * priorityFunc2)

计算所有节点的分数,分数最高的那个Pod当选,如果有分数相同者,随便选个即可。

Currently, Kubernetes scheduler provides some practical priority functions, including:

目前,k8s调度器提供一些优选函数,包括

  • LeastRequestedPriority: 最少已请求资源优选策略,利用(总量-已存在Pod总请求量-待调度Pod请求量)/总量来计算资源空闲率,CPU和内存权重一样,结果越大,那么分数越高。
  • BalancedResourceAllocation: 用于平衡CPU和内存使用率
  • SelectorSpreadPriority: 扩展选择优先级算法,尽可能避免属于相同服务、相同rc/rs的pod在同一个节点,如果zone信息存在的话,也会尽可能分散在不同的可用区
  • CalculateAntiAffinityPriority: 反亲和性优先级调度算法,根据标签,尽可能避免特定标签Pod在相同节点上。
  • ImageLocalityPriority: 根据节点上是否已有镜像以及已有镜像大小来进行优先级调度
  • NodeAffinityPriority: (Kubernetes v1.2) 实现preferredDuringSchedulingIgnoredDuringExecution

优先级函数可以在 pkg/scheduler/algorithm/priorities查看具体实现, k8s默认使用了其中部分调度器,你可以查看pkg/scheduler/algorithmprovider/defaults/defaults.go.