当前位置:   article > 正文

K8S—调度器_k8s调度器

k8s调度器

1、K8S的集群调度

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

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

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

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

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

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

        网站:https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/assign-pod-node/

1.1、调度过程

调度分为几个部分:

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

预选有一系列的算法可以使用:

  • 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 :倾向于已经有要使用镜像的节点,镜像总大小值越大,权重越高

通过算法对所有的优先级项目和权重进行计算,得出最终的结果。

1.2、自定义调度器

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

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: annotation-second-scheduler
  5. labels:
  6. name: multischeduler-example
  7. spec:
  8. containers:
  9. - name: my-scheduler
  10. image: registry.aliyuncs.com/google_containers/pause:3.6

2、节点标签

        与很多其他 Kubernetes 对象类似,节点也有标签。 你可以手动地添加标签。 Kubernetes 也会为集群中所有节点添加一些标准的标签。

2.1、为节点添加标签

  1. [root@master ~]# kubectl get nodes                              # 查看节点
  2. NAME STATUS ROLES AGE VERSION
  3. harbor Ready <none> 3d14h v1.23.0
  4. master Ready control-plane,master 15d v1.23.0
  5. node01 Ready <none> 14d v1.23.0
  6. node02 Ready <none> 12d v1.23.0
  7. [root@master ~]# kubectl label nodes node01 disktype=ssd  # 为node01节点加上ssd标签
  8. [root@master ~]# kubectl get nodes --show-labels                 # 验证节点标
  9. NAME STATUS ROLES AGE VERSION LABELS
  10. harbor Ready <none> 3d14h v1.23.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=harbor,kubernetes.io/os=linux
  11. master Ready control-plane,master 15d v1.23.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=
  12. node01 Ready <none> 14d v1.23.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=node01,kubernetes.io/os=linux
  13. node02 Ready <none> 12d v1.23.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node02,kubernetes.io/os=linux

2.2.1、创建一个调度到选择的节点的 pod

        此 Pod 配置文件描述了一个拥有节点选择器 disktype: ssd 的 Pod。这表明该 Pod 将被调度到 有 disktype=ssd 标签的节点。

   nodeSelector 是节点选择约束的最简单推荐形式。你可以将 nodeSelector 字段添加到 Pod 的规约中设置你希望目标节点所具有的节点标签。 Kubernetes 只会将 Pod 调度到拥有你所指定的每个标签的节点上。

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4.   name: nginx
  5.   labels:
  6.     env: test
  7. spec:
  8.   containers:
  9.   - name: nginx
  10.     image: nginx
  11.     imagePullPolicy: IfNotPresent
  12.   nodeSelector:  # 节点选择器
  13.     disktype: ssd                  # 选择ssd标签节点

2.2.1、验证

  1. [root@master ~]# kubectl get pods -o wide
  2. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
  3. nginx 1/1 Running 0 9s 10.254.2.15 node01 <none> <none>

3、亲和性与反亲和性

   nodeSelector 提供了一种最简单的方法来将 Pod 约束到具有特定标签的节点上。 亲和性和反亲和性扩展了你可以定义的约束类型。使用亲和性与反亲和性的一些好处有:

  • 亲和性、反亲和性语言的表达能力更强。nodeSelector 只能选择拥有所有指定标签的节点。 亲和性、反亲和性为你提供对选择逻辑的更强控制能力。
  • 你可以标明某规则是“软需求”或者“偏好”,这样调度器在无法找到匹配节点时仍然调度该 Pod。
  • 你可以使用节点上(或其他拓扑域中)运行的其他 Pod 的标签来实施调度约束, 而不是只能使用节点本身的标签。这个能力让你能够定义规则允许哪些 Pod 可以被放置在一起。

3.1、亲和性

        节点亲和性概念上类似于 nodeSelector, 它使你可以根据节点上的标签来约束 Pod 可以调度到哪些节点上。 节点亲和性有两种:

  • requiredDuringSchedulingIgnoredDuringExecution: 调度器只有在规则被满足的时候才能执行调度。此功能类似于 nodeSelector, 但其语法表达能力更强。
  • preferredDuringSchedulingIgnoredDuringExecution: 调度器会尝试寻找满足对应规则的节点。如果找不到匹配的节点,调度器仍然会调度该 Pod。
  • 在上述类型中,IgnoredDuringExecution 意味着如果节点标签在 Kubernetes 调度 Pod 时发生了变更,Pod 仍将继续运行。

        使用 Pod 规约中的 .spec.affinity.nodeAffinity 字段来设置节点亲和性。 例如,考虑下面的 Pod 规约:

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: nginx
  5. labels:
  6. env: test
  7. spec:
  8. affinity:
  9. nodeAffinity:
  10. requiredDuringSchedulingIgnoredDuringExecution:
  11. nodeSelectorTerms:
  12. - matchExpressions:
  13. - key: kubernetes.io/hostname
  14. operator: In
  15. values:
  16. - harbor
  17. preferredDuringSchedulingIgnoredDuringExecution:
  18. - weight: 1
  19. preference:
  20. matchExpressions:
  21. - key: kubernetes.io/hostname
  22. operator: In
  23. values:
  24. - harbor
  25. containers:
  26. - name: nginx
  27. image: nginx:latest

        使用 operator 字段来为 Kubernetes 设置在解释规则时要使用的逻辑操作符。 你可以使用 InNotInExistsDoesNotExistGt 和 Lt 之一作为操作符。

   NotIn 和 DoesNotExist 可用来实现节点反亲和性行为。 也可以使用节点污点 将 Pod 从特定节点上驱逐。

3.1.1、验证

  1. [root@master ~]# kubectl get pods -o wide
  2. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
  3. nginx 1/1 Running 0 118m 10.254.4.3 harbor <none> <none>

 关于节点与pod亲和力策略

  • 硬限制是:我必须在某个节点或我必须不在某个节点。

  • 软限制是:我想在某个节点或我不想在某个节点,实在不行,我也可以将就。

​软硬限制结合策略

  • 策略优先级:先满足硬限制,然后满足软限制

3.2、关于亲和性总结

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

4、污点和容忍度

        节点亲和性是 Pod 的一种属性,它使 Pod 被吸引到一类特定的节点 (这可能出于一种偏好,也可能是硬性要求)。 污点(Taint)则相反——它使节点能够排斥一类特定的 Pod。

        容忍度(Toleration)是应用于 Pod 上的,允许(但并不要求)Pod 调度到带有与之匹配的污点的节点上。

        污点和容忍度(Toleration)相互配合,可以用来避免 Pod 被分配到不合适的节点上。 每个节点上都可以应用一个或多个污点,这表示对于那些不能容忍这些污点的 Pod,是不会被该节点接受的。

4.1、污点

​        使用 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 驱逐出去

4.1.1、污点的设置

  1. # 设置污点
  2. [root@master ~]# kubectl taint nodes node01 key1=value1:NoSchedule
  3. node/node01 tainted
  4. # 查看污点
  5. [root@master ~]# kubectl describe nodes | grep -P "Name:|Taints"
  6. Name: harbor
  7. Taints: <none>
  8. Name: master
  9. Taints: node-role.kubernetes.io/master:NoSchedule
  10. Name: node01
  11. Taints: <none>
  12. Name: node02
  13. Taints: <none>
  14. # 删除污点
  15. [root@master ~]# kubectl taint nodes node01 key1=valuel:NoSchedule-
  16. node/node01 untainted

4.2、容忍(Tolerations)

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

4.2.1、在node01、node02、harbor节点上设置污点

  1. [root@master ~]# kubectl taint nodes node{01,02} harbor key1=valuel:NoSchedule
  2. node/node01 tainted
  3. node/node02 tainted
  4. node/harbor tainted
  5. [root@master ~]# kubectl get pods # 创建pod,一直Pending状态
  6. NAME READY STATUS RESTARTS AGE
  7. nginx 0/1 Pending 0 8s

4.2.2、下面给pod设置污点容忍

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: nginx
  5. labels:
  6. env: test
  7. spec:
  8. containers:
  9. - name: nginx
  10. image: nginx
  11. imagePullPolicy: IfNotPresent
  12. tolerations:
  13. - key: "key1"
  14. operator: "Exists"
  15. effect: "NoSchedule"

 4.2.3、验证Pod

  1. [root@master ~]# kubectl get pods
  2. NAME READY STATUS RESTARTS AGE
  3. nginx 1/1 Running 0 2s

  operator 的默认值是 Equal

        一个容忍度和一个污点相“匹配”是指它们有一样的键名和效果,并且:

  • 如果 operator 是 Exists (此时容忍度不能指定 value),或者
  • 如果 operator 是 Equal ,则它们的 value 应该相等
  • 存在两种特殊情况:

            如果一个容忍度的 key 为空且 operator 为 Exists, 表示这个容忍度与任意的 key 、value 和 effect 都匹配,即这个容忍度能容忍任意 taint。如果 effect 为空,则可以与所有键名 key1 的效果相匹配。

  1. tolerations:
  2. - key: "key1"
  3. operator: "Equal"
  4. value: "value1"
  5. effect: "NoExecute"
  6. tolerationSeconds: 3600

说明:

        # 其中 key, vaule, effect 要与 Node 上设置的 taint 保持一致

        # operator 的值为 Exists 将会忽略 value 值

        # tolerationSeconds 用于描述当 Pod 需要被驱逐时可以在 node 上继续保留运行的时间

4.3、指定pod运行在固定节点

4.3.1、指定固定节点:Pod.spec.nodeName

        Pod.spec.nodeName 将 Pod 直接调度到指定的 Node 节点上,会跳过 Scheduler 的调度策略,该匹配规则是强制匹配。

        案例:正常情况下,创建 6 个副本,应该是每个节点进行平分,因为我们指定了具体的运行节点,所以全部在 node01 上进行了创建。

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: myweb
  5. spec:
  6. selector:
  7. matchLabels:
  8. app: myweb
  9. replicas: 6
  10. template:
  11. metadata:
  12. labels:
  13. app: myweb
  14. spec:
  15. nodeName: node01 # 指定固定的节点
  16. containers:
  17. - name: myweb
  18. image: nginx
  19. ports:
  20. - containerPort: 80
  1. [root@master ~]# kubectl get pods -o wide
  2. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
  3. myweb-765c5f6574-4kqwp 1/1 Running 0 2m12s 10.254.5.4 node01 <none> <none>
  4. myweb-765c5f6574-5swqk 1/1 Running 0 2m12s 10.254.5.8 node01 <none> <none>
  5. myweb-765c5f6574-jrwcz 1/1 Running 0 2m12s 10.254.5.7 node01 <none> <none>
  6. myweb-765c5f6574-sqnfb 1/1 Running 0 2m12s 10.254.5.9 node01 <none> <none>
  7. myweb-765c5f6574-znhmd 1/1 Running 0 2m12s 10.254.5.6 node01 <none> <none>
  8. myweb-765c5f6574-zsglr 1/1 Running 0 2m12s 10.254.5.5 node01 <none> <none>

 4.3.2、指定固定节点标签:Pod.spec.nodeSelector

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

        案例:给 node-2 创建一个 “ name:test ” 这样的一个标签后,给Pod指定固定标签节点运行。

1)创建标签

[root@master ~]# kubectl label nodes node02 name=test

2)创建yaml文件

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: myweb
  5. spec:
  6. selector:
  7. matchLabels:
  8. app: myweb
  9. replicas: 4
  10. template:
  11. metadata:
  12. labels:
  13. app: myweb
  14. spec:
  15. nodeSelector:
  16. name: test
  17. containers:
  18. - name: myweb
  19. image: nginx
  20. ports:
  21. - containerPort: 80

 3)验证结果

  1. [root@master ~]# kubectl get pods -o wide
  2. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
  3. myweb-f64b97bf5-6j5m9 1/1 Running 0 15m 10.254.4.9 node02 <none> <none>
  4. myweb-f64b97bf5-6jb27 1/1 Running 0 15m 10.254.4.10 node02 <none> <none>
  5. myweb-f64b97bf5-mfbjw 1/1 Running 0 15m 10.254.4.8 node02 <none> <none>
  6. myweb-f64b97bf5-nnfb4 1/1 Running 0 15m 10.254.4.7 node02 <none> <none>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/40870?site
推荐阅读
相关标签
  

闽ICP备14008679号