【云原生Kubernetes】15-Kubernetes的污点(Taint)和容忍(Toleration)详解

文章目录

  • 【云原生Kubernetes】15-Kubernetes的污点(Taint)和容忍(Toleration)详解
    • 简介
    • 基本用法
      • 设置污点
      • 去除污点
      • 示例
      • effect说明
    • 多污点与多容忍配置
    • 常用场景
      • 节点独占
      • 配备了特殊硬件的节点
      • 基于污点的驱逐
    • 基于节点状态添加污点
    • 总结

简介

​ 污点(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-

示例

  1. 在node1上加一个Taint,该Taint的键为key,值为value,Taint的效果是NoSchedule。这意味着除非pod明确声明可以容忍这个Taint,否则就不会被调度到node1上。
  • 设置污点
[root@master ~]# kubectl taint node 192.168.194.130 key1=value1:NoSchedulenode/192.168.194.130 tainted[root@master ~]#
  • 创建pod,设置pod可以容忍污点key1()

pod可以容忍节点上的污点key1,并不代表着pod一定会调度到该节点

apiVersion: v1kind: Podmetadata:name: pod-taintsspec:tolerations:- key: "key1"operator: "Equal"value: "value1"effect: "NoSchedule"containers:- name: pod-taintsimage: busybox:latest

也可以这样写:

tolerations:- key: "key1"operator: "Exists"effect: "NoSchedule"

operator 的默认值是 Equal

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

  • 如果 operatorExists(此时容忍度不能指定 value),或者
  • 如果 operatorEqual,则它们的 value 应该相等。

存在两种特殊情况:

如果一个容忍度的 key 为空且 operatorExists, 表示这个容忍度与任意的 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:NoSchedulekubectl taint nodes node1 key1=value1:NoExecutekubectl 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 将 GuaranteedBurstable QoS 类中的 Pod(甚至没有设置内存请求的 Pod) 视为能够应对内存压力,而新创建的 BestEffort Pod 不会被调度到受影响的节点上。

总结

  1. 默认情况下,Pod不会调度到含有污点的节点上;
  2. 节点可以配置多个污点,各个污点直接是逻辑与的关系,因此设置容忍度的时候需要容忍所有污点;
  3. Pod容忍了节点上的污点,并不代表Pod一定会被调度到该节点上;
  4. 必须理解设置污点时effect对应的三个参数的含义(PreferNoSchedule,NoSchedule,NoExecute);
    建的 BestEffort Pod 不会被调度到受影响的节点上。