Kubernetes Pod调度进阶:Taints(污点)和Tolerations(容忍)

【注意】最后更新于 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:effect

每个污点有一个key和value作为污点的标签,其中value可以为空,effect描述污点的作用。当前taint effect支持如下三个选项:

  • NoSchedule:表示k8s将不会将Pod调度到具有该污点的Node上
  • PreferNoSchedule:表示k8s将尽量避免将Pod调度到具有该污点的Node上
  • NoExecute:表示k8s将不会将Pod调度到具有该污点的Node上,同时会将Node上已经存在的Pod驱逐出去

污点的设置和去除

使用kubectl设置和去除污点的命令示例如下:

 
# 设置污点
kubectl taint nodes node1 key1=value1:NoSchedule

# 去除污点
kubectl taint nodes node1 key1:NoSchedule-

接下来看一个具体的例子,使用kubeadm部署和初始化的Kubernetes集群,master节点被设置了一个node-role.kubernetes.io/master:NoSchedule的污点,可以使用kubectl describe node <node-name>命令查看。这个污点表示默认情况下master节点将不会调度运行Pod,即不运行工作负载。对于使用二进制手动部署的集群设置和移除这个污点的命令如下:

 
kubectl taint nodes <node-name> node-role.kubernetes.io/master=:NoSchedule

kubectl taint nodes <node-name> node-role.kubernetes.io/master:NoSchedule-

注意:kubeadm初始化的Kubernetes集群,master节点也被打上了一个node-role.kubernetes.io/master=的label,标识这个节点的角色为master。给Node设置Label和设置污点是两个不同的操作。设置Label和移除Label的操作命令如下

 
# 设置Label
kubectl label node node1 node-role.kubernetes.io/master=
# 移除Label
kubectl label node node1 node-role.kubernetes.io/master-

kubectl get node
NAME      STATUS    ROLES     AGE       VERSION
node1    Ready     master    10d       v1.9.8
node2    Ready     master    10d       v1.9.8
node3    Ready     master    10d       v1.9.8
node4    Ready     <none>    10d       v1.9.8
node5    Ready     <none>    10d       v1.9.8

容忍(Tolerations)

设置了污点的Node将根据taint的effect:NoSchedule、PreferNoSchedule、NoExecute和Pod之间产生互斥的关系,Pod将在一定程度上不会被调度到Node上。 但我们可以在Pod上设置容忍(Toleration),意思是设置了容忍的Pod将可以容忍污点的存在,可以被调度到存在污点的Node上。

通过在Pod的spec中设置tolerations字段,给Pod设置上容忍点Toleration:

 
tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule"
  tolerationSeconds: 3600
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoExecute"
- key: "key2"
  operator: "Exists"
  effect: "NoSchedule"
  • 其中key, vaule, effect要与Node上设置的taint保持一致
  • operator的值为Exists将会忽略value值
  • tolerationSeconds用于描述当Pod需要被驱逐时可以在Pod上继续保留运行的时间

下面看一下在Pod上设置容忍的两个特例:

示例1: 当不指定key值时,表示容忍所有的污点key:

 
tolerations:
- operator: "Exists"

示例2:当不指定effect值时,表示容忍所有的污点作用:

 
tolerations:
- key: "key"
  operator: "Exists"

实践:Kubernetes master节点不运行工作负载

Kubernetes集群的Master节点是十分重要的,一个高可用的Kubernetes集群一般会存在3个以上的master节点,为了保证master节点的稳定性,一般不推荐将业务的Pod调度到master节点上。 下面将介绍一下我们使用Kubernetes调度的Taints和和Tolerations特性确保Kubernetes的Master节点不执行工作负载的实践。

我们的Kubernetes集群中总共有3个master节点,节点的名称分别为k8s-01k8s-02k8s-03。 为了保证集群的稳定性,同时提高master节点的利用率,我们将其中一个节点设置为node-role.kubernetes.io/master:NoSchedule,另外两个节点设置为node-role.kubernetes.io/master:PreferNoSchedule,这样保证3个节点中的1个无论在任何情况下都将不运行业务Pod,而另外2个载集群资源充足的情况下尽量不运行业务Pod。

 
kubectl taint nodes k8s-01 node-role.kubernetes.io/master=:NoSchedule


kubectl taint nodes k8s-02 node-role.kubernetes.io/master=:PreferNoSchedule


kubectl taint nodes k8s-03 node-role.kubernetes.io/master=:PreferNoSchedule

另外对于我们部署在集群中的一些非业务组件,例如Kubernetes Dashboardjaeger-collectorjaeger-queryPrometheuskube-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"自动加入。

参考

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值