Taint(污点)和 Toleration(容忍)可以作用于 node 和 pod 上,其目的是优化 pod 在集群间的调度,它们相互配合,可以用来避免 pod 被分配到不合适的节点上。本文作者通过代码实践讲述了他学习 K8s 容点和污点的经历。
K8s 每个节点上都可以应用一个或多个 taint ,这表示对于那些不能容忍这些 taint 的 pod,是不会被该节点接受的。如果将 toleration 应用于 pod 上,则表示这些 pod 可以(但不要求)被调度到具有相应 taint 的节点上。
Taint 基本用法
设置污点: kubectl taint node [node] key=value:[effect]
其中[effect] 可取值:[ NoSchedule | PreferNoSchedule | NoExecute ]:
NoSchedule :一定不能被调度。
PreferNoSchedule:尽量不要调度。
NoExecute:不仅不会调度,还会驱逐 Node 上已有的 Pod。
去除污点:kubectl taint node [node] key:[effect]-
下面是一个简单的示例:在 node1 上加一个 Taint,该 Taint 的键为 key,值为 value,Taint 的效果是 NoSchedule。这意味着除非 pod 明确声明可以容忍这个 Taint,否则就不会被调度到 node1 上:
然后需要在 pod 上声明 Toleration。下面的 Toleration 设置为可以容忍具有该 Taint 的 Node,使得 pod 能够被调度到 node1 上:
也可以写成如下:
Toleration 基本用法
pod 的 Toleration 声明中的 key 和 effect 需要与 Taint 的设置保持一致,并且满足以下条件之一:
operator 的值为 Exists,这时无需指定 value
operator 的值为 Equal 并且 value 相等
如果不指定 operator,则默认值为 Equal。
另外还有如下两个特例:
空的 key 配合 Exists 操作符能够匹配所有的键和值
空的 effect 匹配所有的 effect
上面的例子中 effect 的取值为 NoSchedule,下面对 effect 的值作下简单说明:
NoSchedule:如果一个 pod 没有声明容忍这个 Taint,则系统不会把该 Pod 调度到有这个 Taint 的 node 上
PreferNoSchedule:NoSchedule 的软限制版本,如果一个 Pod 没有声明容忍这个 Taint,则系统会尽量避免把这个 pod 调度到这一节点上去,但不是强制的。
NoExecute:定义 pod 的驱逐行为,以应对节点故障。
NoExecute 这个 Taint 效果对节点上正在运行的 pod 有以下影响:
没有设置 Toleration 的 Pod 会被立刻驱逐
配置了对应 Toleration 的 pod,如果没有为 tolerationSeconds 赋值,则会一直留在这一节点中
配置了对应 Toleration 的 pod 且指定了 tolerationSeconds 值,则会在指定时间后驱逐
从 kubernetes1.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 已经在该节点运行,则会被驱逐;如果没有在该节点运行,也不会再被调度到该节点上。
示例如下:
在 pod 上设置两个 toleration:
这样的结果是该 pod 无法被调度到 node1 上,因为第三个 taint 没有匹配的 toleration。但是如果这个 Pod 已经在 node1 上运行了,那么在运行时设置上第三个 Taint,它还能继续运行,因为 pod 可以容忍前两个 taint。
一般来说,如果给 node 加上 effect=NoExecute 的 Taint,那么该 node 上正在运行的所有无对应 toleration 的 pod 都会被立刻驱逐,而具有相应 toleration 的 pod 则永远不会被逐出。不过系统允许给具有 NoExecute 效果的 Toleration 加入一个可选的 tolerationSeconds 字段,这个设置表明 pod 可以在 Taint 添加到 node 之后还能在这个 node 上运行多久(单们为 s):
上面的例子的意思是,如果 pod 正在运行,所在节点被加入一个匹配的 Taint,则这个 Pod 会持续在这个节点上存活 3600s 后被驱逐。如果在这个宽限期内 taint 被移除,则不会触发驱逐事件。
常见应用场景节点独占
如果想要拿出一部分节点,专门给特定的应用使用,则可以为节点添加这样的 Taint:
然后给这些应用的 pod 加入相应的 toleration,则带有合适 toleration 的 pod 就会被允许同使用其他节点一样使用有 taint 的节点。然后再将这些 node 打上指定的标签,再通过 nodeSelector 或者亲和性调度的方式,要求这些 pod 必须运行在指定标签的节点上。
(1) 具有特殊硬件设备的节点
在集群里,可能有一小部分节点安装了特殊的硬件设备,比如 GPU 芯片。用户自然会希望把不需要占用这类硬件的 pod 排除在外。以确保对这类硬件有需求的 pod 能够顺利调度到这些节点上。可以使用下面的命令为节点设置 taint:
然后在 pod 中利用对应的 toleration 来保障特定的 pod 能够使用特定的硬件。然后同样的,我们也可以使用标签或者其他的一些特征来判断这些 pod,将其调度到这些特定硬件的服务器上。
(2) 应对节点故障
之前说到,在节点故障时,可以通过 TaintBasedEvictions 功能自动将节点设置 Taint,然后将 pod 驱逐。但是在一些场景下,比如说网络故障造成的 master 与 node 失联,而这个 node 上运行了很多本地状态的应用即使网络故障,也仍然希望能够持续在该节点上运行,期望网络能够快速恢复,从而避免从这个 node 上被驱逐。Pod 的 Toleration 可以这样定义:
对于 Node 未就绪状态,可以把 key 设置为 node.alpha.kubernetes.io/notReady
如果没有为 pod 指定 node.alpha.kubernetes.io/noReady 的 Toleration,那么 Kubernetes 会自动为 pod 加入 tolerationSeconds=300 的 node.alpha.kubernetes.io/notReady 类型的 toleration。
如果没有为 pod 指定 node.alpha.kubernetes.io/unreachable 的 Toleration,那么 Kubernetes 会自动为 pod 加入 tolerationSeconds=300 的 node.alpha.kubernetes.io/unreachable 类型的 toleration。
这些系统自动设置的 toleration 用于在 node 发现问题时,能够为 pod 确保驱逐前再运行 5min。这两个默认的 toleration 由 Admission Controller "DefaultTolerationSeconds"自动加入。
添加小助手微信,加入【容器魔方】技术社群。
评论