kubernetes 核心技术-调度器

kubernetes 核心技术-调度器

概述

一个容器平台的主要功能就是为容器分配运行时所需要的计算,存储和网络资源。 容器调度系统负责选择在最合适的主机上启动容器,并且将它们关联起来。

Scheduler是kubernetes的调度器,主要的任务是把定义好的pod分配到集群的节点上。

Kubernetes的资源分为两种属性:

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

2、不可压缩资源(例如内存、硬盘空间)一般来说不杀掉Pod就没法回收。

调度过程

scheduler是kubernetes的调度器,它的主要作用就是根据特定的调度算法和调度策略将Pod调度到合适的Node节点上去,是一个独立的二进制程序,启动之后会一直监听API Server,获取到PodSpec.NodeName为空的 Pod,对每个Pod都会创建一个binding。

调度主要分为以下几个部分:

  1. 首先是预选过程,过滤掉不满足条件的节点,这个过程称为Predicates [ˈpredɪkeɪts]。比如Pod指定了所需要的资源,那么就要过滤掉资源不够的主机。

  2. 然后是优选过程,对通过的节点按照优先级排序,称之为Priorities [praɪˈɔrətiz]

  3. 最后从中选择优先级最高的节点,如果中间任何一步骤有错误,就直接返回错误

Predicates阶段首先遍历全部节点,过滤掉不满足条件的节点,属于强制性规则, 这一阶段输出的所有满足要求的Node将被记录并作为第二阶段的输入,如果所有的节点都不满足条件,那么Pod将会一直处于Pending状态,直到有节点满足条件,在这期间调度器会不断的重试。所以我们在部署应用的时候,如果发现有Pod 一直处于Pending状态,那么就是没有满足调度条件的节点,这个时候可以去检查下节点资源是否可用。

Priorities阶段即再次对节点进行筛选,如果有多个节点都满足条件的话,那么系统会按照节点的优先级(priorites)大小对节点进行排序,最后选择优先级最高的节点来部署Pod应用。

下面是调度过程的简单示意图:

更详细的流程是这样的:

首先,客户端通过API Server的REST API或者kubectl工具创建Pod资源

API Server收到用户请求后,存储相关数据到etcd数据库中

调度器监听watch API Server查看未调度(bind)的Pod列表,循环遍历地为每个Pod尝试分配节点,这个分配过程就是我们上面提到的两个阶段:

预选阶段(Predicates),过滤节点,调度器用一组规则过滤掉不符合要求的Node 节点,比如 Pod 设置了资源的 request, 那么可用资源比 Pod 需要的资源少的主机显然就会被过滤掉。

优选阶段(Priorities),为节点的优先级打分,将上一阶段过滤出来的Node列表进行打分,调度器会考虑一些整体的优化策略,比如把 Deployment 控制的多个 Pod 副本分布到不同的主机上,使用最低负载的主机等等策略。

经过上面的阶段过滤后选择打分最高的Node节点和Pod进行binding操作,然后将结果存储到etcd中。

最后被选择出来的Node节点对应的kubelet去执行创建Pod的相关操作

其中Predicates过滤有一系列的算法可以使用,我们这里简单列举几个:

  1. PodFitsResources:节点上剩余的资源是否大于 Pod 请求的资源

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

  3. PodFitsHostPorts:节点上已经使用的 port 是否和 Pod 申请的 port 冲突

  4. PodSelectorMatches:过滤掉和 Pod 指定的 label 不匹配的节点

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

  6. CheckNodeDiskPressure:检查节点磁盘空间是否符合要求

  7. CheckNodeMemoryPressure:检查节点内存是否够用

除了这些过滤算法之外, 还有一些其他的算法, 更多更详细的我们可以查看源码文件:

k8s.io/kubernetes/pkg/scheduler/algorithm/predicates/predicates.go。

而Priorities优先级是由一系列键值对组成的,键是该优先级的名称,值是它的权重值,同样,我们这里给大家列举几个具有代表性的选项:

LeastRequestedPriority: 通过计算CPU和内存的使用率来决定权重,使用率越低权重越高,换句话说,这个优先级指标倾向于资源使用比例更低的节点,当然正常肯定也是资源使用率越低权重越高,能给别的Pod运行的可能性就越大

SelectorSpreadPriority: 为了更好的高可用, 对同属于一个 Deployment 或者 RC 下面的多个 Pod 副本, 尽量调度到多个不同的节点上, 当一个 Pod 被调度的时候, 会先去查找该 Pod 对应的 controller, 然后查看该 controller 下面的已存在的 Pod,运行 Pod越少的节点权重越高。

ImageLocalityPriority:倾向于已经又要使用镜像的节点,就是如果在某个节点上已经有要使用的镜像了,镜像总大小值越大,权重就越高。

NodeAffinityPriority: 这个就是根据节点的亲和性来计算一个权重值, 后面我们会详细讲解亲和性的使用方法

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

亲和性和反亲和性

亲和特性包括两种类型:node节点亲和性/反亲和性和pod亲和性/反亲和性。pod亲和性/反亲和性约束针对的是pod标签而不是节点标签。

注拓扑域是什么:多个node节点,拥有相同的label标签【节点标签的键值相同】,那么这些节点就处于同一个拓扑域。

节点亲和性

节点亲和性(nodeAffinity)主要是用来控制 Pod 要部署在哪些节点上,以及不能部署在哪些节点上的

节点亲和性规则分为:硬亲和性required、软亲和性preferred。

requiredDuringSchedulingIgnoredDuringExecution:硬策略

preferredDuringSchedulingIgnoredDuringExecution:软策略

硬亲和性表示Pod要调度到的节点必须满足规则条件,不满足则不会调度,pod会一直处于Pending状态;软亲和性表示优先调度到满足规则条件的节点,如果不能满足会选择一个不匹配的节点。

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

节点硬亲和性

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

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

1、nodeSelector

k8s非常常用的一个调度方式:nodeSelector

用户可以灵活的利用label来管理集群中的资源,比如常见的service对象通过label去匹配pod资源,而pod的调度也可以根据节点的label来进行调度

查看node的label命令

bash 复制代码
[root@master1 ~]# kubectl get nodes --show-labels

给一个节点(例如node1)增加标签

bash 复制代码
[root@master1 ~]# kubectl label nodes node1 zone=foo

node/node1 labeled



Pod yaml文件:


[root@master1 ~]# vim pod-selector-demo.yaml

apiVersion: v1

kind: Pod

metadata:

  labels:

    app: busybox-pod
    
  name: test-busybox

spec:

  containers:

  - command:

    - sleep

    - "3600"

    image: busybox

    imagePullPolicy: Always

    name: test-busybox

  nodeSelector:

    zone: foo

创建pod

bash 复制代码
[root@master1 ~]# kubectl create -f pod-selector-demo.yaml

pod/test-busybox created

查看pod

bash 复制代码
[root@master1 ~]# kubectl get pod -o wide

NAME                               READY   STATUS    RESTARTS      AGE     IP            NODE    NOMINATED NODE   READINESS GATES

test-busybox                       1/1     Running   0             61s     10.244.1.18   node1   <none>           <none>

[root@master1 ~]# kubectl describe pod test-busybox

.................................

Events:

Type    Reason     Age    From               Message

----    ------     ----   ----               -------

Normal  Scheduled  3m5s   default-scheduler  Successfully assigned default/test-busybox to node1

Normal  Pulling    3m4s   kubelet            Pulling image "busybox"

Normal  Pulled     2m32s  kubelet            Successfully pulled image "busybox" in 31.483229769s

Normal  Created    2m32s  kubelet            Created container test-busybox

Normal  Started    2m32s  kubelet            Started container test-busybox

我们可以看到Events下面的信息,我们的Pod通过默认的default-scheduler调度器被绑定到了node1节点。不过需要注意的是nodeSelector 属于强制性的,如果我们的目标节点没有可用的资源,我们的 Pod 就会一直处于 Pending 状态。

通过上面的例子我们可以感受到 nodeSelector 的方式比较直观,但是还够灵活,控制粒度偏大,接下来我们再和大家了解下更加灵活的方式:节点亲和性(nodeAffinity)。

2、pod.spec.nodeAffinity

requiredDuringSchedulingIgnoredDuringExecution:硬策略

调度至 zone = foo 的节点

先将之前在node1节点创建的label(zone=foo)删除

bash 复制代码
[root@master1 ~]# kubectl label nodes node1 zone-


Pod yaml文件


[root@master1 ~]# vim required-node-affinity-demo.yaml

apiVersion: v1

kind: Pod

metadata:

  name: with-required-nodeaffinity

spec:

  affinity:

    nodeAffinity:

      requiredDuringSchedulingIgnoredDuringExecution:     #定义硬亲和性

        nodeSelectorTerms:

        - matchExpressions:     #集合选择器

          - {key: zone,operator: In,values: ["foo"]}

  containers:

  - name: test1-busybox

    image: busybox:1.30

    command:

    - sleep

    - "3600"

创建pod

bash 复制代码
[root@master1 ~]# kubectl create -f required-node-affinity-demo.yaml

pod/with-required-nodeaffinity created

查看Pod

bash 复制代码
[root@master1 ~]# kubectl get pod

NAME                      READY   STATUS    RESTARTS       AGE     IP            NODE     NOMINATED NODE   READINESS GATES

with-required-nodeaffinity         0/1     Pending   0              5s   <none>        <none>   <none>           <none>

发现pod的状态为pending,因为节点硬亲和性规则没有匹配zone=foo的标签的节点。

给节点Node2设置label zone=foo

bash 复制代码
[root@master1 ~]# kubectl label nodes node2 zone=foo

node/node2 labeled

查看Pod

bash 复制代码
[root@master1 ~]# kubectl get pod -o wide

NAME                               READY   STATUS    RESTARTS       AGE     IP            NODE    NOMINATED NODE   READINESS GATES

with-required-nodeaffinity         1/1     Running   0              32s     10.244.2.15   node2   <none>           <none>

节点软亲和性

preferredDuringSchedulingIgnoredDuringExecution

节点软亲和性,优先调度到满足条件的节点,如果都不满足也会调度到其他节点。

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

Pod yaml文件

bash 复制代码
[root@master1 ~]# vim preferred-node-affinity-demo.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

  name: myapp-deploy-with-node-affinity

spec:

  replicas: 2

  selector:
 
    matchLabels:

      app: myapp

  template:

    metadata:

    name: myapp-pod

    labels:

      app: myapp

  spec:

    affinity:

      nodeAffinity:

        preferredDuringSchedulingIgnoredDuringExecution:    #节点软亲和性

        - weight: 60

          preference:

            matchExpressions:

            - {key: zone,operator: In,values: ["foo"]}  #表示node标签存在zone=foo

        - weight: 30

          preference:

            matchExpressions:

            - {key: ssd,operator: Exists,values: []}

    containers:

    - name: myapp

      image: busybox:1.30

      command:

      - sleep

      - "3600"

创建pod

bash 复制代码
[root@master1 ~]# kubectl create -f preferred-node-affinity-demo.yaml

deployment.apps/myapp-deploy-with-node-affinity created

查看pod

bash 复制代码
[root@master1 ~]# kubectl get pod -o wide

NAME                                               READY   STATUS    RESTARTS        AGE     IP            NODE    NOMINATED NODE   READINESS GATES

myapp-deploy-with-node-affinity-679d97f649-clw44   1/1     Running   0               31s     10.244.2.17   node2   <none>           <none>

myapp-deploy-with-node-affinity-679d97f649-s2dv6   1/1     Running   0               31s     10.244.2.16   node2   <none>

由上可见,再根据之前打的标签,很容易推断出当前pod会优先调度在node2节点。

思考题:如果给node1节点设置标签ssd=goo,会是什么效果?

重要说明:

1、如果同时指定nodeSelector和nodeAffinity,则必须满足两个条件,才能将Pod调度到候选节点上。

2、如果在nodeAffinity类型下指定了多个nodeSelectorTerms对象【对象不能有多个,如果存在多个只有最后一个生效】,那么只有最后一个nodeSelectorTerms对象生效。

3、如果在nodeSelectorTerms下指定了多个matchExpressions列表,那么只要能满足其中一个matchExpressions,就可以将pod调度到某个节点上【针对节点硬亲和】。

4、如果在matchExpressions下有多个key列表,那么只有当所有key满足时,才能将pod调度到某个节点【针对硬亲和】。

5、在key下的values只要有一个满足条件,那么当前的key就满足条件

6、如果pod已经调度在该节点,当我们删除或修该节点的标签时,pod不会被移除。换句话说,亲和性选择只有在pod调度期间有效。

键值运算关系

节点亲和性语法支持以下运算符:In,NotIn,Exists,DoesNotExist,Gt,Lt。可以使用NotIn和DoesNotExist实现节点的反亲和行为。

运算符关系:

  1. In:label的值在某个列表中

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

  3. Gt:label的值大于某个值

  4. Lt:label的值小于某个值

  5. Exists:某个label存在

  6. DostNotExists:某个label不存在

Pod 亲和性与反亲和性

Pod对象间亲和性,将一些Pod对象组织在相近的位置(同一节点、机架、区域、地区)

Pod对象间反亲和性,将一些Pod在运行位置上隔开

pod亲和性主要解决pod可以和哪些pod部署在同一个拓扑域中的问题(其中拓扑域用主机标签实现,可以是单个主机,也可以是多个主机组成的cluster、zone等等),而pod反亲和性主要是解决pod不能和哪些pod部署在同一个拓扑域中的问题,它们都是处理的pod与pod之间的关系,比如一个pod在一个节点上了,那么我这个也得在这个节点,或者你这个pod在节点上了,那么我就不想和你待在同一个节点上。

Pod亲和性/反亲和性语法支持以下运算符:In,NotIn,Exists,DoesNotExist

准备环境

由于我们这里只有一个集群,并没有区域或者机房的概念,所以我们这里直接使用主机名来作为拓扑域,把 pod 创建在同一个主机上面。

bash 复制代码
[root@master1 ~]# kubectl get nodes --show-labels

通过deployment运行一个pod,或者直接运行一个pod也可以。为后续的Pod亲和性与反亲和性测验做基础。

Yaml文件

bash 复制代码
[root@master1 ~]# vim pod_deplay.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

  name: pod-deploy

  labels:

    app: pod-deploy

spec:

  replicas: 1

  selector:

    matchLabels:

      app: app-pod

  template:

    metadata:

      labels:

        app: app-pod

        version: v1

    spec:

      containers:

      - name: app-pod

        image: busybox:1.30

        imagePullPolicy: IfNotPresent

        command:

        - sleep

        - "3600"

创建pod

bash 复制代码
[root@master1 ~]# kubectl create -f pod_deplay.yaml

deployment.apps/pod-deploy created

查看pod

bash 复制代码
[root@master1 ~]# kubectl get pod -o wide --show-labels

NAME                               READY   STATUS    RESTARTS     AGE     IP            NODE    NOMINATED NODE   READINESS GATES   LABELS

pod-deploy-68549d8f54-lcw54        1/1     Running   0            3m41s   10.244.2.26   node2   <none>           <none>            app=app-pod,pod-template-hash=68549d8f54,version=v1

当前pod在node2节点,其中pod的标签app=app-pod,version=v1,会在后面pod亲和性/反亲和性示例中使用。

Pod 硬亲和性

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

requiredDuringSchedulingIgnoredDuringExecution #硬亲和性策略

对于硬亲和性,如果不满足则pod会一直处于Pending状态。

要运行的yaml文件

bash 复制代码
[root@master1 ~]# vim pod_required_affinity.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

  name: pod-podaffinity-deploy

  labels:

    app: podaffinity-deploy

spec:

  replicas: 2

  selector:

    matchLabels:

    app: myapp

template:

  metadata:

    labels:

      app: myapp

  spec:

    containers:

    - name: myapp-pod

      image: busybox:1.30

      imagePullPolicy: IfNotPresent

      command:

        - sleep

        - "3600"

    affinity:

      podAffinity:

        requiredDuringSchedulingIgnoredDuringExecution:

        - labelSelector:

            # 由于是Pod亲和性/反亲和性;因此这里匹配规则写的是被依赖Pod的标签信息

            matchExpressions:

            #- {key: app,operator: In,values: ["app-pod"]}

            - key: app

              operator: In

              values:

              - app-pod

          # 拓扑域,若多个node节点具有相同的标签信息【标签键值相同】,则表示这些node节点就在同一拓扑域

          topologyKey: kubernetes.io/hostname

运行yaml文件并查看状态

bash 复制代码
[root@master1 ~]# kubectl create -f pod_required_affinity.yaml

deployment.apps/pod-podaffinity-deploy created

查看pod

bash 复制代码
[root@master1 ~]# kubectl get pod -o wide

NAME                                     READY   STATUS    RESTARTS   AGE   IP            NODE    NOMINATED NODE   READINESS GATES

pod-deploy-68549d8f54-lcw54              1/1     Running   0          33m   10.244.2.26   node2   <none>           <none>

pod-podaffinity-deploy-b7cf97b44-55vwg   1/1     Running   0          44s   10.244.2.27   node2   <none>           <none>

pod-podaffinity-deploy-b7cf97b44-rsh6x   1/1     Running   0          44s   10.244.2.28   node2   <none>           <none>

我们看到这个 pod-deploy 运行在了 node2 的节点上面,所以按照上面的亲和性来说,上面我们部署的2个 pod 副本也应该运行在 node2 节点上。

Pod 软亲和性

preferredDuringSchedulingIgnoredDuringExecution #pod软亲和性策略

要运行的yaml文件

bash 复制代码
[root@master1 ~]# vim pod_preferred_affinity.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

  name: pod-podaffinity-deploy1

  labels:

    app: podaffinity-deploy1

spec:

  replicas: 2

  selector:

    matchLabels:

      app: myapp1

  template:

    metadata:

      labels:

        app: myapp1
        
    spec:

      containers:

      - name: myapp-pod1

        image: busybox:1.30

        imagePullPolicy: IfNotPresent

        command:

          - sleep

          - "3600"

      affinity:

        podAffinity:

          preferredDuringSchedulingIgnoredDuringExecution:

          - weight: 100

            podAffinityTerm:

              labelSelector:

                matchExpressions:

                #- {key: app,operator: In,values: ["app-pod"]}

                - key: app

                  operator: In

                  values:

                  - app-pod

                  topologyKey: kubernetes.io/hostname

创建pod

bash 复制代码
[root@master1 ~]# kubectl create -f pod_preferred_affinity.yaml

deployment.apps/pod-podaffinity-deploy1 created

查看pod

bash 复制代码
[root@master1 ~]# kubectl get pod -o wide

NAME                                       READY   STATUS    RESTARTS   AGE   IP            NODE    NOMINATED NODE   READINESS GATES

pod-deploy-68549d8f54-lcw54                1/1     Running   0          57m   10.244.2.26   node2   <none>           <none>

pod-podaffinity-deploy1-677899589b-4zf8t   1/1     Running   0          8s    10.244.2.30   node2   <none>           <none>

pod-podaffinity-deploy1-677899589b-5ttx5   1/1     Running   0          8s    10.244.2.29   node2   <none>           <none>

由上可见,很容易推断出当前pod会优先调度在node2节点。

Pod 硬反亲和性

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

将spec.affinity.podAffinity替换为spec.affinity.podAntiAffinity

反亲和调度也分为硬反亲和性与软反亲和性

比如一个节点上运行了某个 pod,那么我们的 pod 则希望被调度到其他节点上去,同样我们把上面的 podAffinity 直接改成 podAntiAffinity

Yaml文件

bash 复制代码
[root@master1 ~]# vim pod_required_antiaffinity.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

  name: pod-podantiaffinity-deploy

  labels:

    app: podantiaffinity-deploy

spec:

  replicas: 3

  selector:

    matchLabels:

      app: myapp1

  template:

  metadata:

    labels:

      app: myapp1

  spec:

    containers:

    - name: myapp-pod1

      image: busybox:1.30

      imagePullPolicy: IfNotPresent
    
      command:

        - sleep

        - "3600"

    affinity:

      podAntiAffinity:

        requiredDuringSchedulingIgnoredDuringExecution:

        - labelSelector:

            matchExpressions:

            #- {key: app,operator: In,values: ["app-pod"]}

            - key: app

              operator: In

              values:

              - app-pod

            # 拓扑域,若多个node节点具有相同的标签信息【标签键值相同】,则表示这些node节点就在同一拓扑域

            topologyKey: kubernetes.io/hostname

创建pod

bash 复制代码
[root@master1 ~]# kubectl create -f pod_required_antiaffinity.yaml

deployment.apps/pod-podantiaffinity-deploy created

查看pod

bash 复制代码
[root@master1 ~]# kubectl get pod -o wide

NAME                                          READY   STATUS    RESTARTS   AGE     IP            NODE    NOMINATED NODE   READINESS GATES

pod-deploy-68549d8f54-k2h9f                   1/1     Running   0          7m45s   10.244.2.32   node2   <none>           <none>

pod-podantiaffinity-deploy-565f575c7d-qv697   1/1     Running   0          7s      10.244.1.27   node1   <none>           <none>

pod-podantiaffinity-deploy-565f575c7d-rbd26   1/1     Running   0          7s      10.244.1.28   node1   <none>           <none>

pod-podantiaffinity-deploy-565f575c7d-xm44n   1/1     Running   0          7s      10.244.1.29   node1   <none>           <none>

污点和容忍

概述

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

总结:节点亲和性使得Pod对象被吸引到一类特定的节点 (nodeSelector 和 affinity),污点提供让节点排斥特定 Pod 对象的能力

比如用户希望把Master节点保留给Kubernetes系统组件使用,或者把一组具有特殊资源预留给某些Pod,则污点就很有用了,Pod不会再被调度到taints标记过的节点。我们使用 kubeadm 搭建的集群默认就给master节点添加了一个污点标记,所以我们看到我们平时的Pod都没有被调度到master上去:

bash 复制代码
[root@master1 ~]# kubectl describe node master1

..................

Taints:             node-role.kubernetes.io/master:NoSchedule

.................

我们可以使用上面的命令查看master节点的信息,其中有一条关于Taints的信息:node-role.kubernetes.io/master:NoSchedule,就表示master节点打了一个污点的标记,其中影响的参数是NoSchedule,表示Pod不会被调度到标记为taints的节点,除了NoSchedule外,还有另外两个选项:

PreferNoSchedule:NoSchedule的软策略版本,表示尽量不调度到污点节点上去。

NoExecute:该选项意味着一旦Taints生效,如该节点内正在运行的Pod没有对应容忍(tolerations)设置,则会直接被逐出。

污点taints是定义在节点上的键值型属性数据,用于让节点拒绝将 Pod 调度运行于其上,除非Pod有接纳节点污点的容忍度,容忍度tolerations[ˌtɑːləˈreɪʃn]是定义在Pod上的键值属性数据,用于配置可容忍的污点,且调度器将Pod调度至其能容忍污点的节点上或没有污点的节点上。

污点和容忍的设置

污点 taint 标记节点

污点taints标记节点的命令如下:

(1)定义污点

污点定义于 nodes.spec.taints

语法:key=value:effect

(2)effect定义排斥等级

  1. NoSchedule,表示k8s不会将pod调度到具有该污点的node上,但仅影响调度过程,已调度上去的pod不受影响,仅对新增加的pod生效。

  2. PreferNoSchedule,柔性约束,表示k8s尽量避免将pod调度到具有该污点的node上,如果实在是没有符合的节点,也可以调度上来。节点现存Pod不受影响

  3. NoExecute,表示k8s不会将pod调度到具有该污点的Node上,同时会将node上已经存在的Pod驱逐出去。

(3)管理节点的污点

同一个键值数据,effect不同,也属于不同的污点

给节点添加污点:

语法:kubectl taint node <node-name> <key>=<value>:<effect>

bash 复制代码
[root@master1 ~]# kubectl taint node node2 node-type=production:NoSchedule

node/node2 tainted

查看节点污点

bash 复制代码
[root@master1 ~]# kubectl get nodes node2 -o go-template={{.spec.taints}}

[map[effect:NoSchedule key:node-type value:production]]

也可以describe说明中,查找Taints字段

bash 复制代码
[root@master1 ~]# kubectl describe node node2

.................

Taints:             node-type=production:NoSchedule

..................

删除节点污点

语法:

kubectl taint node <node-name> <key>[:<effect>]-

kubectl patch nodes <node-name> -p '{"spec":{"taints":[]}}'

删除key为node-type,effect为NoSchedule的污点

bash 复制代码
[root@master1 ~]# kubectl taint node node2 node-type:NoSchedule-

node/node2 untainted

删除key为node-type的所有污点

bash 复制代码
[root@master1 ~]# kubectl taint node node2 node-type-

删除所有污点

bash 复制代码
[root@master1 ~]# kubectl patch nodes node2 -p '{"spec": {"taints": []}}'

pod设置容忍tolerations

容忍度定义于pods.spec.tolerations

(1)等值判断

tolerations:

  • key: "key1"

operator: "Equal" #判断条件为 Equal

value: "value1"

effect: "NoExecute"

tolerationSeconds: 3600 #用于定义延迟驱逐Pod的时长

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

如果不指定operator属性,则默认值为Equal

(2)存在性判断

tolerations:

  • key: "key1"

operator: "Exists" #存在性判断,只要污点键存在,就可以匹配

effect: "NoExecute"

tolerationSeconds: 3600

存在性判断容忍度与污点在key、effect完全匹配,value使用空值

(3)但不指定key时,表示容忍所有的污点key

tolerations:

  • operator: "Exists"

(4)但不指定effect时,表示容忍所有的污点effect

tolerations:

  • operator: "Exists"

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

污点、容忍应用案例

在node2上加污点,不允许pod调度到node2节点

root@master1 \~\]# kubectl taint node node2 node-type=production:NoSchedule node/node2 tainted

编写Pod部署的yaml文件

bash 复制代码
[root@master1 ~]# vim taint-demo.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

  name: taint

  labels:

    app: taint

spec:

  replicas: 3

  selector:

    matchLabels:

      app: taint

  template:

    metadata:

      labels:

        app: taint

    spec:

      containers:

      - name: busybox

        image: busybox:1.30

        command:

        - sleep

        - "3600"

创建pod

bash 复制代码
[root@master1 ~]# kubectl create -f taint-demo.yaml

deployment.apps/taint created

查看pod

bash 复制代码
[root@master1 ~]# kubectl get pod -o wide

NAME                                          READY   STATUS    RESTARTS      AGE   IP            NODE    NOMINATED NODE   READINESS GATES

taint-5f968d8c4f-lxnb6                        1/1     Running   0             8s    10.244.1.32   node1   <none>           <none>

taint-5f968d8c4f-lzhv7                        1/1     Running   0             8s    10.244.1.31   node1   <none>           <none>

taint-5f968d8c4f-wzmmd                        1/1     Running   0             8s    10.244.1.30   node1   <none>           <none>

由上面可以看到,3个pod的副本都调度到了node1节点,而node2节点没有调度pod。

删除pod

bash 复制代码
[root@master1 ~]# kubectl delete -f taint-demo.yaml

deployment.apps "taint" deleted

接下来在pod上加容忍

由于node2节点被标记为了污点,所以我们这里要想Pod能够调度到该节点去,就需要增加容忍的声明:

修改taint-demo.yaml文件,添加pod容忍

bash 复制代码
apiVersion: apps/v1

kind: Deployment

metadata:

  name: taint

  labels:

    app: taint

spec:

  replicas: 3

  selector:

    matchLabels:

      app: taint

  template:

    metadata:

      labels:

        app: taint

    spec:

      containers:

      - name: busybox

        image: busybox:1.30

        command:

        - sleep

        - "3600"

      tolerations:

      - key: "node-type"

        operator: "Equal"

        value: "production"

        effect: "NoSchedule"

创建Pod

bash 复制代码
[root@master1 ~]# kubectl create -f taint-demo.yaml

deployment.apps/taint created

查看pod

bash 复制代码
[root@master1 ~]# kubectl get pod -o wide

NAME                     READY   STATUS    RESTARTS   AGE   IP            NODE    NOMINATED NODE   READINESS GATES

taint-5d74f4c548-crdpg   1/1     Running   0          8s    10.244.1.39   node1   <none>           <none>

taint-5d74f4c548-cvqzf   1/1     Running   0          8s    10.244.2.34   node2   <none>           <none>

taint-5d74f4c548-ksvtk   1/1     Running   0          8s    10.244.2.33   node2   <none>           <none>

我们可以看到有Pod副本被调度到了node2节点,这就是容忍的使用方法。

注:有多个master节点存在时,为了防止资源浪费,可以加如下设置

bash 复制代码
[root@master1 ~]# kubectl taint node nodename node-role.kubernetes.io/master=:PreferNoSchedule
相关推荐
@hdd2 小时前
控制平面组件详解:API Server、etcd、Scheduler 与 Controller Manager
kubernetes
A-刘晨阳2 小时前
K8S 之 Taints(污点)与 Tolerations(容忍)
运维·云原生·容器·kubernetes·k8s污点·k8s容忍
likeGhee2 小时前
bridge 模式下docker容器无法访问,curl: (56) Recv failure: Connection reset by peer
运维·docker·容器
@hdd3 小时前
Kubernetes 集群架构概述
容器·架构·kubernetes
市安4 小时前
基于Debain构建Ngxin镜像
运维·nginx·docker·云原生·容器·debian·镜像
AI逐月4 小时前
Mac 轻量安装 Docker 完整指南(Docker + Colima + Kubernetes)
macos·docker·kubernetes
Aric_Jones5 小时前
博客音乐播放器实现全解析
java·运维·数据库·人工智能·docker·容器·eclipse
sanyii3131315 小时前
k8s核心资源Pod-主容器之钩子函数
云原生·容器·kubernetes
处女座_三月5 小时前
docker 运行项目配置cuda
运维·docker·容器