kubernete污点和容忍Taint&Toleration

[TOC]

一、前言

​ 在K8S中,如果Pod能容忍某个节点上的污点,那么Pod就可以调度到该节点。如果不能容忍,那就无法调度到该节点。污点和容忍度就像谈恋爱的小情侣,你情我愿,女生知道男生的缺点,却依然选择容忍,这样他们可以生活在一起。如果女生容忍不了男生的缺点,那就没法生活在一起。二话不说“分手

​ 污点它让Node拒绝Pod的运行。简单地说,被标记为Taint的节点就是存在问题的节点,比如磁盘要满、资源不足、存在安全隐患要进行升级维护,希望新的Pod不会被调度过来,但被标记为Taint的节点并非故障节点,仍是有效的工作节点,所以仍需将某些Pod调度到这些节点上时,可以通过使用Toleration属性来实现。 在默认情况下,在Node上设置一个或多个Taint之后,除非Pod明确声明能够容忍这些污点,否则无法在这些Node上运行。

image-20240926102844522

二、简介

污点(Taint): 它使节点能够排斥一类特定的 Pod。定义在节点上,用于拒绝Pod调度到此节点,除非该Pod具有该节点上的污点容忍度。被标记有Taints的节点并不是故障节点。

容忍度(Toleration): 是应用于 Pod 上的。容忍度允许调度器调度带有对应污点的 Pod。用于配置Pod可容忍的节点污点,K8S调度器只能将Pod调度到该Pod能够容忍的污点的节点上。

污点和容忍度(Toleration)相互配合,可以用来避免 Pod 被分配到不合适的节点上。 每个节点上都可以应用一个或多个污点,这表示对于那些不能容忍这些污点的 Pod, 是不会被该节点接受的。Taint在一类服务器上打上污点,让不能容忍这个污点的Pod不能部署在打了污点的服务器上。Toleration是让Pod容忍节点上配置的污点,可以让一些需要特殊配置的Pod能够调用到具有污点和特殊配置的节点上。Taint是作用在节点上;Toleration是作用在Pod上,Taint相当于一把“锁”,Toleration相当于一把“钥匙”。
官网:Taints and Tolerations | Kubernetes

image-20240926094837445

==注意:生产环境的调度并非随便调用,需要结合服务器配置,pod资源信息等情况考虑==

三、Taint配置解析

==注意:一个节点可以配置多个污点;key名相同但是effect不一致也可以使用,代表不同的污点==

1
2
3
4
5
6
7
8
9
#>>> 创建一个污点:
$ kubectl taint nodes node1 key1=value1:PreferNoSchedule
$ kubectl taint nodes node1 key1=value1:NoExecute
$ kubectl taint nodes node1 key2=value2:NoSchedule
# 示例:
$ kubectl taint nodes k8s-node01 ssd=true:PreferNoSchedule

#>>> 取消污点
$ kubectl taint nodes k8s-node01 ssd=true:PreferNoSchedule-

污点是以key=value的形式配置,但是生产环境中也可以使用单独key的形式配置;value可以为空,例如ssd:PreferNoSchedule。

四、Taint排斥等级

  • NoExecute:没有配置此污点容忍度的新Pod对象不能调度到此节点,节点上现存的Pod会被驱逐。 如果 Pod 不能忍受这类污点,Pod 会马上被驱逐。如果 Pod 能够忍受这类污点,但是在容忍度定义中没有指定 tolerationSeconds(容忍时间), 则 Pod 还会一直在这个节点上运行。如果 Pod 能够忍受这类污点,而且指定了 tolerationSeconds, 则 Pod 还能在这个节点上继续运行这个指定的时间长度。
  • NoSchedule:没有配置此污点容忍度的新Pod不能调度到此节点,节点上现存的Pod不受影响。
  • PreferNoSchedule:没有配置此污点容忍度的新Pod尽量不要调度到此节点,如果找不到合适的节点,依然会调度到此节点。

五、Toleration配置解析

​ 配置在Pod中和containers同一级别

方式一 :精准匹配

​ key名和value值必须和节点设置的污点内容一致,才可调度到该节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
tolerations: 
- key: "GPU" #key名
operator: "Equal" #等于
value: "taintValue" #value值
effect: "NoSchedule" #effect污点类型

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

---
apiVersion: v1
kind: Pod
metadata:
name: tolerant-pod
spec:
tolerations:
- key: "key" # key
operator: "Equal" # 精准匹配
value: "value" # value值
effect: "NoSchedule" # effect污点类型
containers:
- name: nginx
image: registry.cn-hangzhou.aliyuncs.com/hujiaming/nginx:1.24.0

方式二:非精准匹配

​ 当多个节点都存在GPU但是有的效率高,有的效率低时,且pod没有硬性要求部署在那个GPU的节点,只要是GPU的节点都可以容忍该节点的污点,就会用到非精准匹配。只需要匹配Key和effect的值就行,value不用设置(需要为空)。

1
2
3
4
tolerations:
- key: "GPU"
operator: "Exists"
effect: "NoSchedule"

方式三:大范围匹配(不推荐key为内置Taint)

​ 不需要匹配effect的值,只需要匹配Key值就行,不管该节点的污点effect设置的什么类型,我都可以部署上边。

1
2
- key: "GPU"
operator: "Exists"

方式四:匹配所有(不推荐)

1
2
tolerations:
- operator: "Exists"

停留时间配置:
​ 当你部署pod的该节点故障了,系统默认是300s后开始迁移。可以通过tolerationSeconds设置pod迁移时间,达到节点故障pod快速迁移和故障恢复;如果不设置时间且该节点的污点effect值设置的NoExecute。pod则不迁移,因为pod容忍该污点。

1
2
3
4
5
6
7
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
tolerationSeconds: 3600
以指定当节点失效或者不响应时, Pod 维系与该节点间绑定关系的时长

==注意事项==:

注意:当创建一个pod的时候,该节点打了一个GPU=true的label标签,并且该节点也打了GPU=true: NoSchedule的污点。且在pod的yaml文件中没有设置Toleration的容忍设置,则不会部署到该节点上。此外,yaml中只设置了node的标签选择器,且没有设置容忍该节点的污点也不会部署到该节点,pod会一直处于pending状态,describe该pod会提示该节点存在污点,该pod没有容忍该污点。nodeSelector是强制性部署到该节点上,而Toleration是累加在该基础上的,并非强制性。同样有两台节点,一台没有打任何污点,另外一台则打了GPU=true: NoSchedule的污点,yaml文件中设置了容忍该污点的相关信息。但是pod在创建的时候不一定会部署在有污点的节点上。一般生产环境Tains配合label标签一起使用。

==注意:DaemonSet类型的pod,在创建时默认容忍所有污点,因为它是在每一个节点都部署一个pod,就算驱逐了,也无法迁移在其他的节点上。==

DaemonSet 控制器自动为所有守护进程添加如下 NoSchedule 容忍度,以防 DaemonSet 崩溃:

  • node.kubernetes.io/memory-pressure

  • node.kubernetes.io/disk-pressure

  • node.kubernetes.io/pid-pressure (1.14 或更高版本)

  • node.kubernetes.io/unschedulable (1.10 或更高版本)

  • node.kubernetes.io/network-unavailable (只适合主机网络配置)

六、集群内置污点

  • node.kubernetes.io/not-ready:节点未准备好,相当于节点状态Ready的值为False。
  • node.kubernetes.io/unreachable:Node Controller访问不到节点,相当于节点状态Ready的值为Unknown。
  • node.kubernetes.io/out-of-disk:节点磁盘耗尽。
  • node.kubernetes.io/memory-pressure:节点存在内存压力。
  • node.kubernetes.io/disk-pressure:节点存在磁盘压力。
  • node.kubernetes.io/network-unavailable:节点网络不可达。
  • node.kubernetes.io/unschedulable:节点不可调度。

示例:节点不健康,6000秒后再驱逐(默认是300秒)
​ 为 Pod 设置 tolerationSeconds,以指定当节点失效或者不响应时, Pod 维系与该节点间绑定关系的时长。比如,你可能希望在出现网络分裂事件时,对于一个与节点本地状态有着深度绑定的应用而言, 仍然停留在当前节点上运行一段较长的时间,以等待网络恢复以避免被驱逐。 你为这种 Pod 所设置的容忍度看起来可能是这样:

1
2
3
4
5
tolerations: 
- key: "node.kubernetes.io/unreachable"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 6000

==注意:==

​ 当大范围匹配时,不能使用内置污点的key值,因为当节点故障时,系统会自动默认给该节点打上故障污点,此时,如果yaml文件设置的key值和内置污点的key值一致,系统判定pod会容忍这个故障污点;当该节点出现故障时,则pod不会被驱逐,导致业务容器宕机。此外,设置容忍时间,要根据实际生产情况。因为有时候会有突发因素导致网络波动,节点会处于短暂的故障,无法通信。这时容忍时间设置过短会导致该节点的pod瞬间被迁移走。而且实际生产的容忍时间肯定大于yaml文件设置的容忍时间,因为节点在故障时,系统先给故障节点打上内置污点,然后容忍时间才开始计时。==在节点被驱逐时,节点控制器或者 kubelet 会添加带有 NoExecute 效果的相关污点。 如果异常状态恢复正常,kubelet 或节点控制器能够移除相关的污点。==

七、案例

  1. 一个节点是纯GPU节点,现需要只有一些需要计算的Pod调度到此节点。
1
2
3
4
5
6
7
8
9
10
11
12
13
#>>> 给节点打上污点和标签
#>>> step 1:驱逐该节点不能容忍此污点的Pod
$ kubectl taint nodes k8s-node02 gpu=true:NoExecute
node/k8s-node02 tainted
#>>> step 2:禁止后续创建没有容忍此污点的Pod调度此节点
$ kubectl taint nodes k8s-node02 gpu=true:NoSchedule
node/k8s-node02 tainted
#>>> step 3:给当前节点打上标签
$ kubectl label node k8s-node02 gpu=true
node/k8s-node02 labeled

#>>> 查看节点的污点
$ kubectl describe node k8s-node02
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#>>> 配置Pod资源清单
---
apiVersion: v1
kind: Pod
metadata:
name: tolerant-pod
spec:
tolerations:
- key: "gpu" # key
operator: "Exists"
nodeSelector:
gpu: "true"
containers:
- name: nginx
image: registry.cn-hangzhou.aliyuncs.com/hujiaming/nginx:1.24.0