20221222 12. 集群调度

简介

k8s内的pod由scheduler调度,scheduler的任务是把pod分配到合适的node节点上。scheduler调度时会考虑到node节点的资源使用情况、port使用情况、volume使用情况等等。在此基础之上,我们也可以控制pod的调度。

Scheduler 是 kubernetes 调度器,主要的任务是把定义的 pod 分配到集群的节点上。但要很多要考虑的问题:

  • 公平:如何保证每个节点都能被合理分配资源,不要造成一个节点忙死,一个节点闲死局面。

  • 资源高效利用:集群所有资源最大化被使用。内存、硬盘、CPU等因素。

  • 效率:调度的性能要好,能够尽快地对大批量的 pod 完成调度工作。

  • 灵活:允许用户根据自己的需求控制调度的逻辑

Sheduler 是作为单独的程序运行,启动之后会一直与 API Server 保持通讯,获取 PodSpec.NodeName 为空的 pod,对每个 pod 都会创建一个 binding,表明该 pod 应该放到哪个节点上 。

固定节点

Pod.spec.nodeSelector

# 1. 给某一个节点打标签
kubectl label nodes k8s-node01 mariadb=mariadb

# 2. pod的控制器中增加配置属性
spec:
  nodeSelector:
    mariadb: mariadb

Pod.spec.nodeName

# 删除k8s-node01节点mariadb的label
kubectl label nodes k8s-node02 mariadb-
kubectl label nodes k8s-node02 --show-labels
spec:
  nodeName: k8s-node02

集群调度原理

Scheduler调度步骤

  1. 首先用户在通过 Kubernetes 客户端 Kubectl 提交创建 Pod 的 Yaml 的文件,向Kubernetes 系统发起资源请求,该资源请求被提交到Kubernetes 系统

  2. Kubernetes 系统中,用户通过命令行工具 Kubectl 向 Kubernetes 集群即 APIServer 用 的方式发送“POST”请求,即创建 Pod 的请求

  3. APIServer 接收到请求后把创建 Pod 的信息存储到 Etcd 中,从集群运行那一刻起,资源调度系统 Scheduler 就会定时去监控 APIServer

  4. 通过 APIServer 得到创建 Pod 的信息,Scheduler 采用 watch 机制,一旦 Etcd 存储 Pod 信息成功便会立即通知APIServer

  5. APIServer会立即把Pod创建的消息通知Scheduler,Scheduler发现 Pod 的属性中 Dest Node 为空时(Dest Node="")便会立即触发调度流程进行调度

  6. 而创建Pod对象,在调度的过程当中有3个阶段:节点预选、节点优选、节点选定,从而筛选出最佳的节点
    . 节点预选:基于一系列的预选规则对每个节点进行检查,将那些不符合条件的节点过滤,从而完成节点的预选
    . 节点优选:对预选出的节点进行优先级排序,以便选出最合适运行Pod对象的节点
    . 节点选定:从优先级排序结果中挑选出优先级最高的节点运行Pod,当这类节点多于1个时,则进行随机选择

集群调度策略

Kubernetes 调度器作为集群的大脑,在如何提高集群的资源利用率、保证集群中服务的稳定运行中也会越来越重要

Kubernetes的资源分为两种属性

  1. 可压缩资源(例如CPU循环,Disk I/O带宽)都是可以被限制和被回收的,对于一个Pod来说可以降低这些资源的使用量而不去杀掉Pod

  2. 不可压缩资源(例如内存、硬盘空间)一般来说不杀掉Pod就没法回收。未来Kubernetes会加入更多资源,如网络带宽,存储IOPS的支持

常用预选策略

预选策略 作用
CheckNodeCondition 检查是否可以在节点报告磁盘、网络不可用或未准备好时将Pod调度其上
HostName 如果Pod对象拥有spec.hostname属性,则检查节点名称字符串是否和该属性值匹配。
PodFitsHostPorts Pod有spec.hostPort属性时,检查端口是否被占用
MatchNodeSelector Pod有spec.nodeSelector属性时,检查节点标签
NoDiskConflict Pod依赖的存储卷在此节点是否可用,默认没有启用
PodFitsResources 检查节点上的资源(CPU、内存)可用性是否满足Pod对象的运行需求
PodToleratesNodeTaints Pod的spec.tolerations属性,仅关注NoSchedule和NoExecute两个效用标识的污点
PodToleratesNodeNoExecuteTaints Pod的spec.tolerations属性,是否能接纳节点的NoExecute类型污点,默认没有启用
CheckNodeLabelPresence 仅检查节点上指定的所有标签的存在性,默认没有启用
CheckServiceAffinity 将相同Service的Pod对象放置在同一个或同一类节点上以提高效率,默认没有启用
MaxEBSVolumeCount 检查节点已挂载的EBS (亚马逊弹性块存储) 存储卷数量是否超过设置的最大值,默认为39
MaxGCEPDVolumeCount 检查节点上已挂载的GCE PD(谷歌云存储) 存储卷数量是否超过最大值,默认为16
MaxAzureDiskVolumeCount 检查节点上已挂载的Azure Disk存储卷数量是否超过最大值,默认为16
CheckVolumeBinding 检查节点上已绑定和未绑定的PVC是否满足需求
NoVolumeZoneConflict 在给定区域zone限制下,检查此节点部署的Pod对象是否存在存储卷冲突
CheckNodeMemoryPressure 检查节点内存压力,如果压力过大,那就不会将pod调度至此
CheckPodePIDPressure 检查节点PID资源压力
CheckNodeDiskPressure 检查节点磁盘资源压力
MatchInterPodAffinity 检查节点是否满足Pod对象亲和性或反亲和性条件

常用优先函数

函数名称 详细说明
LeastRequestedPriority 节点的优先级由节点空闲资源与节点总容量的比值,即由 ((总容量-节点上Pod的容量总和-新Pod的容量)/总容量) 来决定。 CPU和内存具有相同权 重,资源空闲比越高的节点得分越高。
cpu((capacity – sum(requested)) * 10 / capacity) + memory((capacity – sum(requested)) * 10 / capacity) / 2
BalancedResourceAllocation CPU和内存使用率越接近的节点权重越高,该策略不能单独使用,必须和 LeastRequestedPriority 组合使用,尽量选择在部署Pod后各项资源更均衡 的机器。 如果请求的资源(CPU或者内存)需求大于节点的capacity,那么 该节点永远不会被调度到。
InterPodAffinityPriority 通过迭代 weightedPodAffinityTerm 的元素计算和,并且如果对该节点满足 相应的PodAffinityTerm,则将 “weight” 加到和中,具有最高和的节点是最 优选的。
SelectorSpreadPriority 为了更好的容灾,对同属于一个service、replication controller或者replica 的多个Pod副本,尽量调度到多个不同的节点上。 如果指定了区域,调度器 则会尽量把Pod分散在不同区域的不同节点上。当一个Pod的被调度时,会 先查找Pod对于的service或者replication controller, 然后查找service或 replication controller中已存在的Pod,运行Pod越少的节点的得分越高。本 质就是往运行同类pod少的节点上分配。
NodeAffinityPriority 亲和性机制。Node Selectors(调度时将pod限定在指定节点上), 支持多 种操作符(In, NotIn, Exists, DoesNotExist, Gt, Lt),而不限于对节点labels 的精确匹配。 另外支持两种类型的选择器,一种是 “hard(requiredDuringSchedulingIgnoredDuringExecution)”选择器, 它保证所选的主机必须满足所有Pod对主机的规则要求。 这种选择器更像是 之前的nodeselector,在nodeselector的基础上增加了更合适的表现语法。 另一种是“soft(preferresDuringSchedulingIgnoredDuringExecution)”选 择器, 它作为对调度器的提示,调度器会尽量但不保证满足NodeSelector的 所有要求。
NodePreferAvoidPodsPriority(权重1W) 如果 节点的 Anotation (注解信息)没有设置 key-value:scheduler. alpha.kubernetes.io/ preferAvoidPods = "...",则节点对该 policy 的得分 就是10分, 加上权重10000,那么该node对该policy的得分至少10W分。如 果Node的Anotation设置了, scheduler.alpha.kubernetes.io/preferAvoidPods = "..." ,如果该 pod 对应 的 Controller 是 ReplicationController 或 ReplicaSet, 则该 node 对该 policy 的得分就是0分。
TaintTolerationPriority 使用 Pod 中 tolerationList 与 节点 Taint 列表项进行匹配,配对成功的项越 多,则得分越低。污点越匹配,得分越低
ImageLocalityPriority 根据Node上是否存在一个pod的容器运行所需镜像大小对优先级打分,分值 为0-10。遍历全部Node, 如果某个Node上pod容器所需的镜像一个都不存 在,分值为0; 如果Node上存在Pod容器部分所需镜像,则根据满足当前需 求的镜像的大小来决定分值,镜像越大,分值就越高;如果Node上存在pod 所需全部镜像,分值为10。默认没有启用
EqualPriority 是一个优先级函数,它给予所有节点相等权重。
MostRequestedPriority 在 ClusterAutoscalerProvider 中,替换 LeastRequestedPriority,给使用 多资源的节点,更高的优先级。 计算公式为: (cpu(10 sum(requested) / capacity) + memory(10 sum(requested) / capacity)) / 2 默认没 有启用

节点亲和性调度

节点亲和性规则:

required (硬亲和性,不能商量,必须执行) 、preferred (软亲和性,可以商量,选择执行)

  • 硬亲和性规则不满足时,Pod会置于Pending状态,软亲和性规则不满足时,会选择一个不匹配的节点

  • 当节点标签改变而不再符合此节点亲和性规则时,不会将Pod从该节点移出,仅对新建的Pod对象生效

节点硬亲和性

requiredDuringSchedulingIgnoredDuringExecution

  • 方式一:Pod使用 spec.nodeSelector (基于等值关系) ;Pod使用 spec.nodeName

  • 方式二:Pod使用 spec.affinity 支持 matchExpressions 属性 (复杂标签选择机制)

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/hostname   #node节点的标签
            operator: In
            values:
              - k8s-node02    #集群真实节点名称
# 可以先使用命令获得节点标签及真实节点名称:
kubectl get nodes --show-labels

键值运算关系

  • In:label 的值在某个列表中

  • NotIn:label 的值不在某个列表中

  • Gt:label 的值大于某个值

  • Lt:label 的值小于某个值

  • Exists:某个 label 存在

  • DoesNotExist:某个 label 不存在

节点软亲和性

preferredDuringSchedulingIgnoredDuringExecution

  • 柔性控制逻辑,当条件不满足时,能接受被编排于其他不符合条件的节点之上

  • 权重 weight 定义优先级,1-100 值越大优先级越高

affinity:
  nodeAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
      - preference:
        matchExpressions:
          - key: kubernetes.io/hostname
            operator: In
            values:
              - k8s-node02
        weight: 1

Pod 资源亲和调度

Pod 硬亲和调度

requiredDuringSchedulingIgnoredDuringExecution

Pod亲和性描述一个Pod与具有某特征的现存Pod运行位置的依赖关系;即需要事先存在被依赖的Pod对象

Pod 软亲和调度

Pod软亲和调度用于分散同一类应用,调度至不同的区域、机架或节点等.将

spec.affinity.podAffinity 替换为 spec.affinity.podAntiAffinity 。软亲和调度也分为柔性约束和强制约束

污点和容忍度

污点 taints 是定义在node节点上的键值型属性数据,用于让节点拒绝将Pod调度运行于其上,除非Pod有接纳节点污点的容忍度。

容忍度 tolerations 是定义在 Pod 上的键值属性数据,用于配置可容忍的污点,且调度器将Pod调度至其能容忍该节点污点的节点上或没有污点的节点上 。

对于nodeAffinity无论是硬策略(硬亲和)还是软策略(软亲和)方式,都是调度 pod 到预期节点上,而Taints恰好与之相反,如果一个节点标记为 Taints ,除非 pod 也被标识为可以容忍污点节点,否则该Taints 节点不会被调度 pod。

节点亲和性,是 pod 的一种属性(偏好或硬性要求),它使 pod 被吸引到一类特定的节点。Taint 则相反,它使节点 能够 排斥 一类特定的 pod

Taint 和 toleration 相互配合,可以用来避免 pod 被分配到不合适的节点上。每个节点上都可以应用一个或多个 taint ,这表示对于那些不能容忍这些 taint 的 pod,是不会被该节点接受的。如果将 toleration 应用于 pod 上,则表示这些 pod 可以(但不要求)被调度到具有匹配 taint 的节点上定义污点和容忍度

污点定义于 nodes.spec.taints 属性。容忍度定义于 pods.spec.tolerations 属性。

使用 kubectl taint 命令可以给某个 Node 节点设置污点,Node 被设置上污点之后就和 Pod 之间存在了一种相斥的关系,可以让 Node 拒绝 Pod 的调度执行,甚至将 Node 已经存在的 Pod 驱逐出去 。

语法: key=value:effect

# 查看node节点名称
kubectl get nodes

# 查看master节点详细信息:通过观taints察属性,发现master节点默认被打上一个污点。
kubectl describe nodes k8s-master01

effect 定义排斥等级:

  • NoSchedule ,不能容忍,但仅影响调度过程,已调度上去的pod不受影响,仅对新增加的pod生效。

    解释说明:表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上 。

  • PreferNoSchedule ,柔性约束,节点现存Pod不受影响,如果实在是没有符合的节点,也可以调度上来。 解释说明:表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上

  • NoExecute ,不能容忍,当污点变动时,Pod对象会被驱逐。

    解释说明:表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上,同时会将 Node 上已经存在的Pod 驱逐出去

语法规则

# 创建污点:语法规则
kubectl taint nodes node1 key1=value1:NoSchedule

# 删除污点:语法规则
kubectl taint nodes node1 key1:NoSchedule-

# 在某一个节点创建污点并驱逐pod
kubectl taint nodes k8s-node03 offline=testtaint:NoExecute

# 查看节点污点信息
kubectl describe nodes k8s-node03

在Pod上定义容忍度时:

  1. 等值比较 容忍度与污点在key、value、effect三者完全匹配

  2. 存在性判断 key、effect完全匹配,value使用空值

一个节点可配置多个污点,一个Pod也可有多个容忍度

posted @ 2022-12-22 14:49  流星<。)#)))≦  阅读(18)  评论(0编辑  收藏  举报