【注意】最后更新于 2 years ago,文中内容可能已过时,请谨慎使用。
污点(Taint)和容忍(Toleration)是从Kubernetes 1.6开始提供的高级调度功能。 在Kubernetes的文档中Taints and Tolerations的介绍已经十分详细。 本文将从简单理解的角度看一下Taint和Toleration。
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]-
#比如设置污点:
kubectl taint node test test=16:NoSchedule
kubectl taint node test test=16:NoExecute
#去除指定key及其effect:
kubectl taint nodes node\_name key:\[effect\]- #(这里的key不用指定value) #去除指定key所有的effect:
kubectl taint nodes node\_name key- #示例:
kubectl taint node test test:NoSchedule-
kubectl taint node test test:NoExecute-
kubectl taint node test test-
下面是一个简单的示例:在 node1 上加一个 Taint,该 Taint 的键为 key,值为 value,Taint 的效果是 NoSchedule。这意味着除非 pod 明确声明可以容忍这个 Taint,否则就不会被调度到 node1 上:
kubectl taint nodes node1 key=value:NoSchedule
然后需要在 pod 上声明 Toleration。下面的 Toleration 设置为可以容忍具有该 Taint 的 Node,使得 pod 能够被调度到 node1 上:
apiVersion: v1
kind: Pod
metadata:
name: pod-taints
spec:
tolerations:
\- key: "key"
operator: "Equal"
value:"value" effect: "NoSchedule"
containers:
- name: pod-taints
image: busybox:latest
也可以写成如下:
tolerations:
\- key: "key"
operator: "Exists"
effect: "NoSchedule"
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 已经在该节点运行,则会被驱逐;如果没有在该节点运行,也不会再被调度到该节点上。
示例如下:
kubectltaint nodes node1 key1=value1:NoSchedule
kubectl taint nodes node1 key1=value1:NoExecute
kubectl taint nodes node1 key2=value2:NoSchedule
复制代码
在 pod 上设置两个 toleration:
tolerations:
\- key: "key1"
operator: "Equal" value:"value1" effect: "NoSchedule"
- key: "key1" operator: "Equal" value: "value1" effect: "NoExecute"
这样的结果是该 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):
tolerations:
\- key: "key1"
operator: "Equal" value:"value1" effect: "NoSchedule"
tolerationSeconds: 3600
上面的例子的意思是,如果 pod 正在运行,所在节点被加入一个匹配的 Taint,则这个 Pod 会持续在这个节点上存活 3600s 后被驱逐。如果在这个宽限期内 taint 被移除,则不会触发驱逐事件。
污点(Taint)
污点(Taint)的组成
使用kubectl taint
命令可以给某个Node节点设置污点,Node被设置上污点之后就和Pod之间存在了一种相斥的关系,可以让Node拒绝Pod的调度执行,甚至将Node已经存在的Pod驱逐出去。
每个污点的组成如下:
|
每个污点有一个key和value作为污点的标签,其中value可以为空,effect描述污点的作用。当前taint effect支持如下三个选项:
NoSchedule
:表示k8s将不会将Pod调度到具有该污点的Node上PreferNoSchedule
:表示k8s将尽量避免将Pod调度到具有该污点的Node上NoExecute
:表示k8s将不会将Pod调度到具有该污点的Node上,同时会将Node上已经存在的Pod驱逐出去
污点的设置和去除
使用kubectl设置和去除污点的命令示例如下:
|
接下来看一个具体的例子,使用kubeadm部署和初始化的Kubernetes集群,master节点被设置了一个node-role.kubernetes.io/master:NoSchedule
的污点,可以使用kubectl describe node <node-name>
命令查看。这个污点表示默认情况下master节点将不会调度运行Pod,即不运行工作负载。对于使用二进制手动部署的集群设置和移除这个污点的命令如下:
|
注意:kubeadm初始化的Kubernetes集群,master节点也被打上了一个
node-role.kubernetes.io/master=
的label,标识这个节点的角色为master。给Node设置Label和设置污点是两个不同的操作。设置Label和移除Label的操作命令如下
|
容忍(Tolerations)
设置了污点的Node将根据taint的effect:NoSchedule、PreferNoSchedule、NoExecute和Pod之间产生互斥的关系,Pod将在一定程度上不会被调度到Node上。 但我们可以在Pod上设置容忍(Toleration),意思是设置了容忍的Pod将可以容忍污点的存在,可以被调度到存在污点的Node上。
通过在Pod的spec中设置tolerations字段,给Pod设置上容忍点Toleration:
|
- 其中key, vaule, effect要与Node上设置的taint保持一致
- operator的值为Exists将会忽略value值
- tolerationSeconds用于描述当Pod需要被驱逐时可以在Pod上继续保留运行的时间
下面看一下在Pod上设置容忍的两个特例:
示例1: 当不指定key值时,表示容忍所有的污点key:
|
示例2:当不指定effect值时,表示容忍所有的污点作用:
|
实践:Kubernetes master节点不运行工作负载
Kubernetes集群的Master节点是十分重要的,一个高可用的Kubernetes集群一般会存在3个以上的master节点,为了保证master节点的稳定性,一般不推荐将业务的Pod调度到master节点上。 下面将介绍一下我们使用Kubernetes调度的Taints和和Tolerations特性确保Kubernetes的Master节点不执行工作负载的实践。
我们的Kubernetes集群中总共有3个master节点,节点的名称分别为k8s-01
、k8s-02
、k8s-03
。 为了保证集群的稳定性,同时提高master节点的利用率,我们将其中一个节点设置为node-role.kubernetes.io/master:NoSchedule
,另外两个节点设置为node-role.kubernetes.io/master:PreferNoSchedule
,这样保证3个节点中的1个无论在任何情况下都将不运行业务Pod,而另外2个载集群资源充足的情况下尽量不运行业务Pod。
|
另外对于我们部署在集群中的一些非业务组件,例如Kubernetes Dashboard
、jaeger-collector
、jaeger-query
、Prometheus
、kube-state-metrics
等组件,通过设置Tolerations和Pod Affinity(亲和性)将这些组件运行在master节点上,而其他的业务Pod运行在普通的Node节点上。
常见应用场景节点独占
如果想要拿出一部分节点,专门给特定的应用使用,则可以为节点添加这样的 Taint:
kubectl taint nodes test dedicated=groupName:NoSchedule
复制代码
然后给这些应用的 pod 加入相应的 toleration,则带有合适 toleration 的 pod 就会被允许同使用其他节点一样使用有 taint 的节点。然后再将这些 node 打上指定的标签,再通过 nodeSelector 或者亲和性调度的方式,要求这些 pod 必须运行在指定标签的节点上。
(1) 具有特殊硬件设备的节点
在集群里,可能有一小部分节点安装了特殊的硬件设备,比如 GPU 芯片。用户自然会希望把不需要占用这类硬件的 pod 排除在外。以确保对这类硬件有需求的 pod 能够顺利调度到这些节点上。可以使用下面的命令为节点设置 taint:
kubectl taint nodes test special=true:NoSchedule
kubectl taint nodes test special=true:PreferNoSchedule
复制代码
然后在 pod 中利用对应的 toleration 来保障特定的 pod 能够使用特定的硬件。然后同样的,我们也可以使用标签或者其他的一些特征来判断这些 pod,将其调度到这些特定硬件的服务器上。
(2) 应对节点故障
之前说到,在节点故障时,可以通过 TaintBasedEvictions 功能自动将节点设置 Taint,然后将 pod 驱逐。但是在一些场景下,比如说网络故障造成的 master 与 node 失联,而这个 node 上运行了很多本地状态的应用即使网络故障,也仍然希望能够持续在该节点上运行,期望网络能够快速恢复,从而避免从这个 node 上被驱逐。Pod 的 Toleration 可以这样定义:
tolerations:
\- key: "node.alpha.kubernetes.io/unreachable"
operator:"Exists" effect: "NoExecute"
tolerationSeconds: 6000
对于 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"自动加入。