【云原生Kubernetes】15-Kubernetes的污点(Taint)和容忍(Toleration)详解
文章目录
简介
污点(Taint)是指标记节点的一种机制,用于告诉 Kubernetes 集群这个节点上的 Pod 是有问题的,例如某些节点资源已经不足等。当节点被标记为污点时,Kubernetes 调度器将不会将新的 Pod 分配到这个节点上,除非这个 Pod 明确地声明了它可以容忍这个节点上的污点。污点通常用于保证某些节点上运行的应用程序不会被新的 Pod 占用。
容忍度(Toleration)是指告诉 Kubernetes 集群一个 Pod 可以容忍哪些节点上存在的污点。当一个 Pod 被标记为可以容忍某些污点时,Kubernetes 调度器将在为该 Pod 分配节点时考虑这些容忍度信息。只有节点上存在被 Pod 容忍的污点时,该节点才会被考虑作为该 Pod 的运行节点。
污点和容忍度(Toleration)相互配合,可以用来避免 Pod 被分配到不合适的节点上。 每个节点上都可以应用一个或多个污点,这表示对于那些不能容忍这些污点的 Pod, 是不会被该节点接受的。
默认情况下Pod是不会调度到含有污点的Node上的
基本用法
设置污点
kubectl taint node [node] key=value[effect]
其中[effect] 可取值: [ NoSchedule | PreferNoSchedule | NoExecute ]
NoSchedule :一定不能被调度。
PreferNoSchedule:尽量不要调度。
NoExecute:不仅不会调度,还会驱逐Node上已有的Pod。
-
给192.168.194.130Node上添加污点
#示例: kubectl taint node 192.168.194.130 test=xhz:NoSchedule
去除污点
#比如设置污点:
kubectl taint node 192.168.194.130 test=16:NoSchedule
kubectl taint node 192.168.194.130test=16:NoExecute
#去除指定key及其effect:
kubectl taint nodes node_name key:[effect]- #(这里的key不用指定value)
#去除指定key所有的effect:
kubectl taint nodes node_name key-
#示例:
kubectl taint node 192.168.194.130 test:NoSchedule-
kubectl taint node 192.168.194.130 test:NoExecute-
kubectl taint node 192.168.194.130 test-
示例
- 在node1上加一个Taint,该Taint的键为key,值为value,Taint的效果是NoSchedule。这意味着除非pod明确声明可以容忍这个Taint,否则就不会被调度到node1上。
-
设置污点
[root@master ~]# kubectl taint node 192.168.194.130 key1=value1:NoSchedule
node/192.168.194.130 tainted
[root@master ~]# -
创建pod,设置pod可以容忍污点key1()
pod可以容忍节点上的污点key1,并不代表着pod一定会调度到该节点
apiVersion: v1
kind: Pod
metadata:
name: pod-taints
spec:
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
containers:
- name: pod-taints
image: busybox:latest
也可以这样写:
tolerations:
- key: "key1"
operator: "Exists"
effect: "NoSchedule"
operator
的默认值是 Equal
。
一个容忍度和一个污点相"匹配"是指它们有一样的键名和效果,并且:
- 如果
operator
是Exists
(此时容忍度不能指定value
),或者 - 如果
operator
是Equal
,则它们的value
应该相等。
存在两种特殊情况:
如果一个容忍度的
key
为空且operator
为Exists
, 表示这个容忍度与任意的 key、value 和 effect 都匹配,即这个容忍度能容忍任何污点。如果
effect
为空,则可以与所有键名key1
的效果相匹配。
effect说明
上面的例子中effect的取值为NoSchedule,下面对effect的值作下简单说明:
- NoSchedule: 如果一个pod没有声明容忍这个Taint,则系统不会把该Pod调度到有这个Taint的node上。
- PreferNoSchedule:NoSchedule的软限制版本,如果一个Pod没有声明容忍这个Taint,则系统会尽量避免把这个pod调度到这一节点上去,但不是强制的。例如当Pod没有容忍该污点,但是其他节点的资源已经无法在调度Pod,此时Pod还是会被调度到该节点上。
- NoExecute:定义pod的驱逐行为,以应对节点故障。NoExecute这个Taint效果对节点上正在运行的pod有以下影响:
- 没有设置Toleration的Pod会被立刻驱逐
- 配置了对应Toleration的pod,如果没有为tolerationSeconds赋值,则会一直留在这一节点中
- 配置了对应Toleration的pod且指定了tolerationSeconds值,则会在指定时间后驱逐
- 从kubernetes 1.6版本开始引入了一个alpha版本的功能,即把节点故障标记为Taint(目前只针对node unreachable及node not ready,相应的NodeCondition "Ready"的值为Unknown和False)。激活TaintBasedEvictions功能后(在--feature-gates参数中加入TaintBasedEvictions=true),NodeController会自动为Node设置Taint,而状态为"Ready"的Node上之前设置过的普通驱逐逻辑将会被禁用。注意,在节点故障情况下,为了保持现存的pod驱逐的限速设置,系统将会以限速的模式逐步给node设置Taint,这就能防止在一些特定情况下(比如master暂时失联)造成的大量pod被驱逐的后果。这一功能兼容于tolerationSeconds,允许pod定义节点故障时持续多久才被逐出。
多污点与多容忍配置
系统允许在同一个node上设置多个taint,也可以在pod上设置多个Toleration。Kubernetes调度器处理多个Taint和Toleration能够匹配的部分,剩下的没有忽略掉的Taint就是对Pod的效果了。下面是几种特殊情况:
- 如果剩余的Taint中存在effect=NoSchedule,则调度器不会把该pod调度到这一节点上。
- 如果剩余的Taint中没有NoSchedule的效果,但是有PreferNoSchedule效果,则调度器会尝试不会pod指派给这个节点
- 如果剩余Taint的效果有NoExecute的,并且这个pod已经在该节点运行,则会被驱逐;如果没有在该节点运行,也不会再被调度到该节点上。
例如,假设你给一个节点添加了如下污点:
kubectl taint nodes node1 key1=value1:NoSchedule
kubectl taint nodes node1 key1=value1:NoExecute
kubectl taint nodes node1 key2=value2:NoSchedule
假定某个 Pod 有两个容忍度:
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
在这种情况下,上述 Pod 不会被调度到上述节点,因为其没有容忍度和第三个污点相匹配。 但是如果在给节点添加上述污点之前,该 Pod 已经在上述节点运行, 那么它还可以继续运行在该节点上,因为第三个污点是三个污点中唯一不能被这个 Pod 容忍的,且该污点effect: "NoSchedule",是允许已经调度到该节点的Pod继续运行的。
常情况下,如果给一个节点添加了一个 effect 值为 NoExecute
的污点, 则任何不能忍受这个污点的 Pod 都会马上被驱逐,任何可以忍受这个污点的 Pod 都不会被驱逐。 但是,如果 Pod 存在一个 effect 值为 NoExecute
的容忍度指定了可选属性 tolerationSeconds
的值,则表示在给节点添加了上述污点之后, Pod 还能继续在节点上运行的时间。例如,
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
tolerationSeconds: 3600
这表示如果这个 Pod 正在运行,同时一个匹配的污点被添加到其所在的节点, 那么 Pod 还将继续在节点上运行 3600 秒,然后被驱逐。 如果在此之前上述污点被删除了,则 Pod 不会被驱逐。
常用场景
节点独占
如果想要拿出一部分节点,专门给特定的应用使用,则可以为节点添加这样的Taint
kubectl taint nodes nodename dedicated=groupName:NoSchedule
然后给这些应用的pod加入相应的toleration,则带有合适toleration的pod就会被允许同使用其他节点一样使用有taint的节点。然后再将这些node打上指定的标签,再通过nodeSelector或者亲和性调度的方式,要求这些pod必须运行在指定标签的节点上。
配备了特殊硬件的节点
在部分节点配备了特殊硬件(比如 GPU)的集群中, 我们希望不需要这类硬件的 Pod 不要被调度到这些特殊节点,以便为后继需要这类硬件的 Pod 保留资源。 要达到这个目的,可以先给配备了特殊硬件的节点添加污点:
kubectl taint nodes nodename special=true:NoSchedule
或
kubectl taint nodes nodename special=true:PreferNoSchedule
然后在pod中利用对应的toleration来保障特定的pod能够使用特定的硬件。然后同样的,我们也可以使用标签或者其他的一些特征来判断这些pod,将其调度到这些特定硬件的服务器上。
基于污点的驱逐
之前说到,在节点故障时,可以通过TaintBasedEvictions功能自动将节点设置Taint,然后将pod驱逐。但是在一些场景下,比如说网络故障造成的master与node失联,而这个node上运行了很多本地状态的应用即使网络故障,也仍然希望能够持续在该节点上运行,期望网络能够快速恢复,从而避免从这个node上被驱逐。Pod的Toleration可以这样定义:
tolerations:
- key: "node.alpha.kubernetes.io/unreachable"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 6000
前文提到过污点的效果值 NoExecute
会影响已经在节点上运行的如下 Pod:
- 如果 Pod 不能忍受这类污点,Pod 会马上被驱逐。
- 如果 Pod 能够忍受这类污点,但是在容忍度定义中没有指定
tolerationSeconds
, 则 Pod 还会一直在这个节点上运行。 - 如果 Pod 能够忍受这类污点,而且指定了
tolerationSeconds
, 则 Pod 还能在这个节点上继续运行这个指定的时间长度。
当某种条件为真时,节点控制器会自动给节点添加一个污点。当前内置的污点包括:
node.kubernetes.io/not-ready
:节点未准备好。这相当于节点状况Ready
的值为 "False
"。node.kubernetes.io/unreachable
:节点控制器访问不到节点. 这相当于节点状况Ready
的值为 "Unknown
"。node.kubernetes.io/memory-pressure
:节点存在内存压力。node.kubernetes.io/disk-pressure
:节点存在磁盘压力。node.kubernetes.io/pid-pressure
: 节点的 PID 压力。node.kubernetes.io/network-unavailable
:节点网络不可用。node.kubernetes.io/unschedulable
: 节点不可调度。node.cloudprovider.kubernetes.io/uninitialized
:如果 kubelet 启动时指定了一个"外部"云平台驱动, 它将给当前节点添加一个污点将其标志为不可用。在 cloud-controller-manager 的一个控制器初始化这个节点后,kubelet 将删除这个污点。
在节点被驱逐时,节点控制器或者 kubelet 会添加带有 NoExecute
效果的相关污点。 如果异常状态恢复正常,kubelet 或节点控制器能够移除相关的污点。
在某些情况下,当节点不可达时,API 服务器无法与节点上的 kubelet 进行通信。 在与 API 服务器的通信被重新建立之前,删除 Pod 的决定无法传递到 kubelet。 同时,被调度进行删除的那些 Pod 可能会继续运行在分区后的节点上。
说明:
控制面会限制向节点添加新污点的速率。这一速率限制可以管理多个节点同时不可达时 (例如出现网络中断的情况),可能触发的驱逐的数量。
基于节点状态添加污点
控制平面使用节点控制器自动创建 与节点状况对应的、效果为 NoSchedule
的污点。
调度器在进行调度时检查污点,而不是检查节点状况。这确保节点状况不会直接影响调度。 例如,如果 DiskPressure
节点状况处于活跃状态,则控制平面添加 node.kubernetes.io/disk-pressure
污点并且不会调度新的 Pod 到受影响的节点。 如果 MemoryPressure
节点状况处于活跃状态,则控制平面添加 node.kubernetes.io/memory-pressure
污点。
对于新创建的 Pod,可以通过添加相应的 Pod 容忍度来忽略节点状况。 控制平面还在具有除 BestEffort
之外的 QoS 类的 Pod 上添加 node.kubernetes.io/memory-pressure
容忍度。 这是因为 Kubernetes 将 Guaranteed
或 Burstable
QoS 类中的 Pod(甚至没有设置内存请求的 Pod) 视为能够应对内存压力,而新创建的 BestEffort
Pod 不会被调度到受影响的节点上。
总结
- 默认情况下,Pod不会调度到含有污点的节点上;
- 节点可以配置多个污点,各个污点直接是逻辑与的关系,因此设置容忍度的时候需要容忍所有污点;
- Pod容忍了节点上的污点,并不代表Pod一定会被调度到该节点上;
- 必须理解设置污点时effect对应的三个参数的含义(PreferNoSchedule,NoSchedule,NoExecute);
建的BestEffort
Pod 不会被调度到受影响的节点上。