调度器中污点的设置

调度器中污点的设置

Taint(污点) 和 Toleration(容忍):

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

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

这句话不太好理解我给大家举一个常见的例子:

假如当年龄大了以后都会遇到一些相亲,但是比如有时候相亲的女的会提要求,比如这个男孩子打不打呼要是打呼她就会容忍不了。也就意味这如果有些男孩他的标签上会贴上打呼两个字的话,那这个女孩就没有可能和这个男孩走在一起。这个例子就是典型的一个 taint 污点和 toleration 容忍。

但是反过来再给大家举个例子,比如这个女孩她可以接受打呼,但是这些打呼的男孩就一定会和她走到一起吗。天下之大不打呼的男孩多了去了,所以不一定能够走到一起。污点和容忍的概念就是,如果你能够容忍这个污点,代表有可能这女孩和这个男孩会发生故事,但也可能不一定会发生故事。

在我们 K8S 中他依然是这个概念:

假设我有一个 pod 他不任容任何污点,但是在我们其中 node-1 节点上他有一个污点的存在,那这个 pod 就不会被调度到这个 node-1 上去。

如果这个 pod 声明了她能够容忍这个污点,难道她就会一定会运行在这个 node-1 上吗?这也不一定吧,node-2 节点可能也会运行,原因是有污点的 node 这个 pod 都能够容忍,那没有污点的凭什么我不能被运行呢?

这里 node-1 只是不会成为选择的障碍而已,并不代表一定会运行在 node-1 节点上。

9.3.1 污点(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 驱逐。

其实在 K8s 上默认他就已经设置了污点了,我们可以通过以下命令看一下。

[09:58:44 root@master-1 ~]#kubectl describe node master-1 
Taints:             node-role.kubernetes.io/master:NoSchedule

# 会发现有一个污点, node-role.kubernetes.io/master 为键名,值为空。effect 达到的目的是 NoSchedule,不会将 pod 调度到具有该污点的 node 上。

这也就是为什么我们的 K8S 在运行一些 pod 的时候,都会被分配至 node 节点上不会被分配到 master 节点上的原因,因为 master 节点天生就打了这么一个污点

9.3.2 设置污点,查看和去除

# 设置污点
kubectl taint nodes node-1 key1=value1:NoSchedule

# 节点说明中,查找 Taints 字段
kuebctl describe pod pod-name

# 去除污点
kubectl taint nodes node1 key1:NoSchedule-

9.3.2.1 设置污点范例:

想要设置污点的话就用下面的命令

[09:58:58 root@master-1 ~]#kubectl taint node node-1 key1=value1:NoSchedule

kubectl taint:          # 指定设置污点
node node-1 :           # node 选择这里选择的是 node-1 的节点
key1=value1:NoSchedule: # 键值的选择,并且标签选择的是 NoSchedule 不会将 pod 调度到有该节点的 node上

实现范例:

那我们可以看一下效果。

1、通过kubectl get pod -o wide查看 pod 的详细信息,会发现所有的 pod 都运行在 node-1 的节点上

[10:05:46 root@master-1 ~]#kubectl get pod -o wide
NAME     READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
node02   1/1     Running   1          36h   10.10.1.113   node-1   <none>           <none>
pod-3    1/1     Running   1          36h   10.10.1.112   node-1   <none>           <none>

2、那我们现在可以给 node-1 这个节点打一个标签,我们打的这个标签是 驱逐的标签。

[10:05:49 root@master-1 ~]#kubectl taint node node-1 check=zhangguiyuan:NoExecute

kubectl taint :                 # 指定设置污点
node node-1:                    # node 选择是我们的 master 节点
check=zhangguiyuan:NoExecute:   # 键值为 check,键名为 zhangguiyuan 执行的 effect 是我们的 NoExecute 驱逐。

3、再次通过kubectl get pod -o wide查看,就会发现已经没有任何 pod 的存在。刚才两个运行的 pod 都是运行在 node-1 节点上的。

[10:11:41 root@master-1 ~]#kubectl get pod -o wide
No resources found in default namespace.

原因是我们在添加污点 node 的时候打的 effect 标签是 NoExecute代表的含义就是把这个 node 上面的 pod 全部驱逐。

因为这个 pod 是一个自主式 pod 没有控制器控制的 pod 所以会发现驱逐完成之后 pod 就不存在了。如果是我们 deployment或者是 statefulset的这么一个控制器的 pod 就会在我们的 node-2 节点上创建这两个 pod 。因为控制器 pod 需要维持它的副本数目,而自主式 pod 是不用管他的 pod 副本数。

我们先不删除该 pod ,我们通过下面容忍性的实验来演示容忍性的作用。

9.3.3. 容忍(Tolerations)

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

接下来我通过下面的操作设置我们容忍看一下效果。

pod.spec.tolerations 字段详解:

  • 其中 key、value、effect 要与 Node 上设置的 taint 保持一致,一个错误的都不行

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

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

    • 这个含义就是即使 pod 会被驱逐,但是该 pod 能够继续保证时间为多少秒。比如我写个 6000 秒那该 pod 在 6000 秒之后就会被驱离了。

tolerations:                        # 定义了一个 tolerations 容忍
- key: "key1"                       # 键名为 key1
  operator: "Equal"                 # 运算关系
  value: "value1"                   # 键值为 value1
  effect: "NoSchedule"              # effect 标签效果是 NoSchedule 不会把 pod 调度到该 node 上
  tolerationSeconds: 3600           # 容忍的这么一个期限时间为 3600
- key: "key1"                       # 
  operator: "Equal"
  value: "value1"
  effect: "NoExecute"
- key: "key2"
  operator: "Exists"
  effect: "NoSchedule"

注意:

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

tolerations:
- operator: "Exists"

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

tolerations:
- key: "key"
  operator: "Exists"

3、有多个 master 存在时,防止资源浪费,可以如下设置

kubectl taint nodes Node-name node-role.kubernetes.io/master=:PreferNoSchedule

kubectl taint:                  # 打上污点
nodes Node-name:                # 给 node 主节点上打一个标签
node-role.kubernetes.io/master: # 标签的键名
=                                # 值为空
PreferNoSchedule:               # 这个参数的含义是尽可能不在该节点上运行,也就是当我们后面所有的 pod 都出现了一个所谓的资源不够用的问题,这时候我们就可以在 master 节点上运行所对应的 pod 了

9.3.3.1 容忍性实现范例:

1、比如现在给我们的 node-2 节点也打上污点。

[10:46:55 root@master-1 ~]#kubectl taint node node-2 check=zhangguiyuan:NoExecute

kubectl taint:                  # 打上污点
node node-2:                    # 需要打上污点的节点的是我们的 node-2
check=zhangguiyuan:NoExecute:   # 键值为 check,键名为 zhangguiyuan 执行的 effect 是我们的 NoExecute 驱逐。

2、通过kubectl apply声明式创建运行一个 pod

[10:48:44 root@master-1 affi]#kubectl apply -f pod1.yaml 

3、通过kubectl get pod 可以观察该 pod 的状态为 pending 等待。因为现在 node-1 和 node-2 两个节点都有污点,所以该 pod 就没有被调度到任何一个 node 上运行,只能是一个 pending 等待状态

[10:48:48 root@master-1 affi]#kubectl get pod
NAME     READY   STATUS    RESTARTS   AGE
node02   0/1     Pending   0          17s

4、那现在我们去编写一个容忍污点的 yaml文件。

[11:22:03 root@master-1 affi]#vim pod3.yaml 

apiVersion: v1                      # api 版本为 v1
kind: Pod                           # kinde 类型为 pod
metadata:                           # 元数据信息
  name: pod-3                       # 这个 pod 名称为 pod-3
  labels:                           # 匹配标签
    app: pod-3                      # 匹配 app=pod-3 的标签
spec:                               # 该 pod 的描述字段
  containers:                       # 使用的容器信息
  - name: pod-3                     # 这个容器名为 pod-3
    image: nginx                    # 使用的镜像 nginx
  tolerations:                      # 容忍信息 
  - key: "check"                    # 容忍 key 为 check 的污点
    operator: "Equal"               # 运算关系
    value: "zhangguiyuan"           # 容忍 value 为 zhangguiyuan 的污点
    effect: "NoExecute"             # 容忍的 effect 标签为 NoExecute 的标签
    tolerationSeconds: 3600     # 容忍期限为 3600 秒

5、通过kubectl apply声明式创建 pod

[11:31:01 root@master-1 affi]#kubectl apply -f pod3.yaml 

6、通过kubectl get查看 pod 信息 pod-3 的状态已经为 running 运行状态

NAME     READY   STATUS    RESTARTS   AGE
node02   0/1     Pending   0          42m
pod-3    1/1     Running   0          28s           # 已经运行

7、通过kubectl get pod -o wide查看 pod 的详细信息,它已经运行在了 node-1 节点上,但是在我们的 node-1 和 node-2 两个节点信息中都有污点。

原因:

虽然这两个 node 节点上有污点,但是我们在创建 pod-3 的 yaml 文件中明确指定了污点的 key:volume 和 effectcheck:zhangguiyaun effect=NoExecute所以它会运行在 node-1 的节点上。

[11:31:33 root@master-1 affi]#kubectl get pod -o wide
NAME     READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
node02   0/1     Pending   0          44m     <none>        <none>   <none>           <none>
pod-3    1/1     Running   0          2m22s   10.10.1.115   node-1   <none>           <none>

这就是污点和容忍之间的关系

9.3.3.2 在 master 节点上运行 pod

有多个 master 存在时,防止资源浪费,可以如下设置

kubectl taint node Node-name node-role.kubernetes.io/master=:PreferNoSchedule

kubectl taint:                  # 打上污点
node Node-name:             # 给 node 主节点上打一个标签
node-role.kubernetes.io/master: # 标签的键名
=                                # 值为空
PreferNoSchedule:               # 这个参数的含义是尽可能不在该节点上运行,也就是当我们后面所有的 pod 都出现了一个所谓的资源不够用的问题,这时候我们就可以在 master 节点上运行所对应的 pod 了

演示范例:

1、现在我就可以在我的 master-1 节点上运行该标签,这样的话如果有一天所有的 node 节点资源都不够用的话,这些 pod 就会在我们的 master 节点上运行。

[14:39:29 root@master-1 affi]#kubectl taint node master-1 node-role.kubernetes.io/master=:PreferNoSchedule

9.3.4 污点的去除

我们在的 node-1 和 node-2 节点上面打了一些污点,现在我们将这些污点给他去除了,因为上面的实验做完了。

去除污点,我们只需要使用设置污点的命令最后面加一个 -减号即可

去除我们所有节点的污点

[14:40:26 root@master-1 affi]#kubectl taint node master-1 node-role.kubernetes.io/master=:PreferNoSchedule-
node/master-1 untainted             # 提示 master-1 无污点,已经去除了污点
[14:47:48 root@master-1 affi]#kubectl taint node node-1 check=zhangguiyuan:NoExecute-
node/node-1 untainted               # 提示 node-1 无污点,已经去除了污点
[14:48:44 root@master-1 affi]#kubectl taint node node-2 check=zhangguiyuan:NoExecute-
node/node-2 untainted               # 提示 node-2 无污点,已经去除了污点

9.3.5 总结

以上的操作就是我们的污点,其实在不经意间我也给大家讲了运维的关系,如果有一天后端的 node-2 节点需要被维护,需要去更新他的一些组件或者一些策略,那这时候在 node-2 这个节点上运行很多的 pod ,如果我直接将这个 node 节点给他关闭的话,可能会造成我们服务访问的一些影响。那在这种情况下我们就可以先对我们的 node-2 节点去打一个污点,打一个NoExecute的这么一个污点,那这样运行在 node-2 节点上的 pod 就会被驱离,驱离完成之后我们在将 node-2 这个节点从 kubernetes 集群中去除,最后我们就能够对 node-2 这个节点进行所谓的更新了。

点赞