K8s-调度器

K8s-调度器


引入:Scheduler 是 kubernetes 的调度器,主要的任务是把定义的 pod 分 配到集群的节点上。听起来非常简单,但有很多要考虑的问题:

​ 公平:如何保证每个节点都能被分配资源

​ 资源高效利用:集群所有资源最大化被使用

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

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

调度过程

​ 调度分为几个部分:首先是过滤掉不满足条件的节点,这个过程称 为 预选;然后对通过的节点按照优先级排序,这个是 优选;最后从中 选择优先级最高的节点。如果中间任何一步骤有错误,就直接返回错误

预选算法

​ PodFitsResources:节点上剩余的资源是否大于 pod 请求的资源

​ PodFitsHost:如果 pod 指定了 NodeName,检查节点名称是否和 NodeName 匹配

​ PodFitsHostPorts:节点上已经使用的 port 是否和 pod 申请的 port 冲突

​ PodSelectorMatches:过滤掉和 pod 指定的 label 不匹配的节点

​ NoDiskConflict:已经 mount 的 volume 和 pod 指定的 volume 不 冲突,除非它们都是只读

注意:如果在 预选 过程中没有合适的节点,pod 会一直在 pending 状态,不 断重试调度,直到有节点满足条件。经过这个步骤,如果有多个节点满 足条件,就继续 优选 过程: 按照优先级大小对节点排序 优先级由一系列键值对组成,键是该优先级项的名称,值是它的权重 (该项的重要性)。这些优先级选项包括:

LeastRequestedPriority:通过计算 CPU 和 Memory 的使用率 来决定权重,使用率越低权重越高。换句话说,这个优先级指标倾向于资源使用比例更低的节点

BalancedResourceAllocation:节点上 CPU 和 Memory 使用率 越接近,权重越高。这个应该和上面的一起使用,不应该单独使用

ImageLocalityPriority:倾向于已经有要使用镜像的节点,镜像总 大小值越大,权重越高 通过算法对所有的优先级项目和权重进行计算,得出最终的结果

自定义调度器

​ 除了 kubernetes 自带的调度器,你也可以编写自己的调度器。通 过 spec:schedulername 参数指定调度器的名字,可以为 pod 选择某 个调度器进行调度。比如下面的 pod 选择 my-scheduler 进行调度, 而不是默认的 default-scheduler

apiVersion: v1
kind: Pod
metadata: 
  name: test-scheduler
  labels: 
    name: test-scheduler
spec: 
  schedulername: tets-scheduler
  containers: 
  - name: pod-with-second-annotation-container
    image: chenxiyanglinux/myapp:v1

调度亲和性

​ 节点亲和性

​ pod亲和性

节点亲和性

pod.spec.nodeAffinty

​ 软策略: preferredDuringSchedulingIgnoredDuringExecution--软亲和

​ 硬策略: requiredDuringSchedulingIgnoredDuringExecution--硬亲和

键值运算关系

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

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

​ Gt:label 的值大于某个值

​ Lt:label 的值小于某个值

​ Exists:某个 label 存在

​ DoesNotExist:某个 label 不存在

注意: 如果nodeSelectorTerms下面有多个选项的话,满足任何一个 条件就可以了;如果matchExpressions有多个选项的话,则必须同时 满足这些条件才能正常调度 POD

硬亲和演示,基于以下模块完成

apiVersion: v1
kind: Pod
metadata: 
  name: affinity
  labels: 
    app: node-affinity-pod
spec: 
  containers: 
  - name: with-node-affinity
    image: chenxiyanglinux/myapp:v1
  affinity: 
    nodeAffinity: 
      requireDuringSchedulingIgnoreDuringExecution: 
        nodeSelectorTerms:
        - matchExpressions: 
          - key: kuberbetes.io/hostname
            operator: NotIn
            values: 
            - k8s-node02
# 基于此文件允许,一定会被调度到node01节点            

测试,将NotIn改为In,node02改为03,看是否一直处于pending状态(并没有node03机器)

软亲和演示,基于以下模块完成

apiVersion: v1
kind: Pod
metadata: 
  name: affinity
  labels: 
    app: node-affinity-pod
spec: 
  containers: 
  - name: with-node-affinity
    image: chenxiyanglinux/myapp:v1
  affinity: 
    nodeAffinity: 
       preferredDuringSchedulingIgnoredDuringExecution: 
       - weight: 1
         preference: 
           matchExpressions: 
           - key: source
             operator: In
             values: 
             - qikqiak
# 由于K:V值表示的是主机标签,所以如果没有此标签,则随机调度
$ kubectl get node --show-labels 	#可查看节点标签         

由于主机没有该标签值,所以根据优选算法随机调度

现在测试,将两node节点标签分别更改,完成下面测试

​ kubectl label node k8s-node02 disktype=ssd

​ kubectl label node k8s-node01 disktype=hdd

验证,基于以下模板完成

apiVersion: v1
kind: Pod
metadata: 
  name: affinity
  labels: 
    app: node-affinity-pod
spec: 
  containers: 
  - name: with-node-affinity
    image: chenxiyanglinux/myapp:v1
  affinity: 
    nodeAffinity: 
      requireDuringSchedulingIgnoreDuringExecution: 
        nodeSelectorTerms:
        - matchExpressions: 
          - key: disktype
            operator: NotIn
            values: 
            - ssd
# 按照模板--应该运行在hdd才符号要求--node01            

软硬亲和结合

apiVersion: v1
kind: Pod
metadata: 
  name: affinity
  labels: 
    app: node-affinity-pod
spec: 
  containers: 
  - name: with-node-affinity
    image: chenxiyanglinux/myapp:v1
  affinity: 
    nodeAffinity: 
      requireDuringSchedulingIgnoreDuringExecution: 
        nodeSelectorTerms:
        - matchExpressions: 
          - key: disktype
            operator: NotIn
            values: 
            - k8s-master01
      preferredDuringSchedulingIgnoredDuringExecution: 
        - weight: 1
          preference: 
            matchExpressions: 
            - key: disktype
              operator: In
              values: 
              - ssd     
#因目前环境只有两台环境所以一定在node02上运行,             

结论:

​ 无论是软亲和的K:V还是硬亲和的K:V,它都代表的是主机的标 签

​ 硬亲和使用,看性能是否达到不可用状态,否则一般采用软亲和 两者结合先看硬亲和,再看软亲和

​ 如果nodeSelectorTerms下面有多个选项的话,满足任何一个条件 就可以了;如果matchExpressions有多个选项的话,则必须同时满足 这些条件才能正常调度 POD

pod亲和性

​ 软策略: preferredDuringSchedulingIgnoredDuringExecution-- 软亲和

​ 硬策略: requiredDuringSchedulingIgnoredDuringExecution-- 硬亲和

注意:pod亲和性通过pod标签去确定,--- 拓扑域决定pod在哪运行

以下面模板测试硬亲和

apiVersion: v1
kind: Pod
metadata: 
  name: pod-3
  labels: 
    app: pod-3
spec: 
  containers: 
  - name: pod-3
    image: chenxiyanglinux/myapp:v1
  affinity: 
    podAffinity: 
      requireDuringSchedulingIgnoreDuringExecution: 
      - labelSelector: 
        mathExpressions: 
        - key: app
          operator: In
          values: 
          - node-affinity-pod
        topologyKey: kuberbetes.io/hostname
# 若运行在node02节点,则证明验证成功        

​ 因指定的拓扑域是node-affinity-pod是在node02节点运行,所以 pod-3一定是在node02节点运行

​ 现在再基于下面模板创建,测试如果拓扑域两个节点都有,它会在哪个 节点运行

先修改两节点标签

基于以下模板验证

apiVersion: v1
kind: Pod
metadata: 
  name: pod-4
  labels: 
    app: pod-4
spec: 
  containers: 
  - name: pod-4
    image: chenxiyanglinux/myapp:v1
  affinity: 
    podAffinity: 
      requireDuringSchedulingIgnoreDuringExecution: 
      - labelSelector: 
        mathExpressions: 
        - key: app
          operator: In
          values: 
          - node-affinity-pod
        topologyKey: level

为了方便我们抓到在哪个节点运行,我们执行以下命令

​ kubectl apply -f pod4.yaml && kubectl get pod -o wide && kubectl delete -f pod4.yaml

​ 这就能看到,拓扑域如果一样就随机调度了,还是会基于优选算法去调度

测试反亲和性--podAntiAffinity

基于以下模板完成

apiVersion: v1
kind: Pod
metadata: 
  name: pod-4
  labels: 
    app: pod-4
spec: 
  containers: 
  - name: pod-4
    image: chenxiyanglinux/myapp:v1
  affinity: 
    podAntAffinity: 
      preferredDuringSchedulingIgnoredDuringExecution: 
      - weight: 1
         podAffinityTerm: 
           labelSelector
             matchExpressions: 
             - key: app
             operator: In
             values: 
             - node-affinity-pod
           topologyKey: kuberbetes.io/hostname  
# 按照要求,则不会在node02节点运行,那只能在node01节点运行了

亲和性/反亲和性调度策略比较如下

调度策略 匹配 标签 操作符 拓扑域 支持 调度目标
nodeAffinity 主机 In, NotIn, Exists, DoesNotExist, Gt, Lt 指定主机
podAffinity POD In, NotIn, Exists, DoesNotExist POD与指定POD同一拓扑域
podAnitAffinity POD In, NotIn, Exists, DoesNotExist POD与指定POD不在同一 拓扑域

Taint(污点)和Toleration(容忍)

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

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

污点(taint)

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

  • 污点组成

​ key=value:effect

​ 说明: 每个污点有一个 key 和 value 作为污点的标签,其中 value 可以 为空,effect 描述污点的作用。当前 taint effect 支持如下三个选项

​ NoSchedule:表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上

​ PreferNoSchedule:表示 k8s 将尽量避免将 Pod 调度到具有该污 点的 Node 上

​ NoExecute:表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上,同时会将 Node 上已经存在的 Pod 驱逐出去,适合升级使用

  • 污点的设置、查看、去除

    • 设置污点:value1值可以没有

    • kubectl taint node node1 key1=value1:NoSchedule

      eg: kubectl taint node k8s-master01 noderole.kubernetes.io/master=:PreferNoSchedule

  • 节点说明中,查找Tains字段

    • kubectl describe node node-name
  • 去除污点

    • kubectl taint node node1 key1:NoSchedule-

      kubectl taint node k8s-master01 noderole.kubernetes.io/master:NoSched-

容忍(Tolerations)

​ 设置了污点的 Node 将根据 taint 的 effect:NoSchedule、 PreferNoSchedule、NoExecute 和 Pod 之间产生互斥的关系,Pod 将在一定程度上不会被调度到 Node 上。 但我们可以在 Pod 上设置容 忍 ( Toleration ) ,意思是设置了容忍的 Pod 将可以容忍污点的存在, 可以被调度到存在污点的 Node 上

​ Tolerations写法,即在创建pod时指定说明要在哪个污点的节点运行 pod.spec.tolerations,以下三种写法都可以

​ tolerations:

​ - key: "key1" ---此种方法最精确,完全匹配

​ operator: "Equal" ---运算符

​ value: "value1" ---值

​ effect: "NoSchedule" ---策略

​ - key: "key1"

​ operator: "Equal"

​ value: "value1"

​ effect: "NoExecute"

​ tolerationSeconds: 3600 ----清理pod的限期

​ - key: "key2"

​ operator: "Exists"

​ effect: "NoSchedule"

说明

​ 当不指定key值时,表示容忍所有的污点key

​ tolerations:

​ - operator: "Exists"

​ 当不指定effect值时,表示容忍所有的污点作用

​ tolerations:

​ - key: "key"

​ operator: "Exists"

​ 有多个Master存在时,防止资源浪费,可以做如下设

​ kubectl taint node Node-Name noderole.kubernetes.io/master=:PreferNoSchedule

​ eg:kubectl taint node k8s-master01 noderole.kubernetes.io/master=:PreferNoSchedule

实例:污点、亲和性、容忍的结合使用

如何指定在node01运行key为gpu值的deployment实例,参照以下 模板,基于node01节点已经创建了关于gpu的污点,

apiVersion: v1
kind: Pod
metadata: 
  name: nginx
  labels: 
    app: nginx
spec: 
  replicas: 100
  selector: 
    matchLabels: 
      app: nginx
  template: 
    matadata: 
      labels:
        app: nginx
    spec: 
      affinity: 
        nodeAffinity: 
          requireDuringSchedulingIgnoreDuringExecution: 
            nodeSelectorTerms:
            - matchExpressions: 
            - key: computeengine
              operator: In
                values: 
                - gpu
      tolerations: 
      - key: "computeengine"
        operator: "Equal"
        values: "GPU"
        effect: "NoSchedule"
# 如果不容忍污点,则不会被调度,如果容忍污点,则不会被污点所干扰,若结合亲和性使用,则可达到在指定的污点节点运行具体的实例        

固定节点调度

​ pod.spec.nodeName将pod直接调度到指定的Node节点上,会跳 过Scheduler的调度策略,该匹配规则是强制匹配 基于以下模板完成

apiVersion: extensions/v1beta1
kind: Deployment
metadata: 
  name: myweb
spec: 
  replicas: 7
  template: 
    metadata: 
      labels: 
        app: myweb
    spec: 
      nodeName: k8s-node01
      containers: 
      - name: myweb
        image: chenxiyanglinux/myqpp:v1
        ports: 
        - containerPort: 80

Pod.spec.nodeSelector:通过 kubernetes 的 label-selector (标签 选择器)机制选择节点,由调度器调度策略匹配 label,而后调度 Pod 到 目标节点,该匹配规则属于强制约束

基于以下模板完成

apiVersion: extensions/v1beta1
kind: Deployment
metadata: 
  name: mywe1
spec: 
  replicas: 10
  template: 
    metadata: 
      labels: 
        app: myweb
    spec: 
      nodeSelector: 
        type: backEndNode1
      containers: 
      - name: myweb
        image: chenxiyanglinux/myqpp:v1
        ports: 
        - containerPort: 80

:因指定的标签选择器不存在,所以一直处于pending状态,正验证了此实验

或着将node01节点的标签改一下,做此次实验

再将模板中的标签替换成刚该的标签

验证完成

posted @ 2022-07-26 11:12  Sunset_cloud  阅读(156)  评论(0编辑  收藏  举报