声明:本文为《Kubernetes权威指南:从Docker到Kubernetes实践全接触(第5版)》的读书笔记
在前面的博客《k8s教程(15)-pod之亲和性与互斥性调度》讲解的NodeAffinity节点亲和性
,是在Pod
上定义的一种属性,使得Pod
能够被调度到某些Node
上运行(优先选择或强制要求)。
Taint(污点) 则正好相反,它让Node
拒绝Pod
的运行。简单地说,被标记为Taint
的节点就是存在问题的节点,比 如磁盘要满、资源不足、存在安全隐患要进行升级维护,希望新的Pod
不会被调度过来。
但被标记为Taint
的节点并非故障节点,仍是有效的工作节点,所以仍需将某些Pod
调度到这些节点上时,可以通过使用Toleration
属性来实现。
在默认情况下,在Node
上设置一个或多个Taint
之后,除非Pod
明确声明能够容忍这些污点,否则无法在这些Node
上运行。
可以用kubectl taint
命令为Node
设置Taint
信息:
kubectl taint nodes node1 key=value:NoSchedule
描述:这个设置为node1
加上了一个Taint
,该Taint
的键为key
,值为value
,Taint
的效果是NoSchedule
,这意味着除非Pod
明确声明可以容忍这个Taint
,否则不会被调度到node1
上。
在Pod
上声明容忍的例子如下,下面的两个Toleration
都被设置为可以容忍(Tolerate
)具有该Taint
的Node
,使得Pod
能够被调度到node1
上:
tolerations:
- key: "key"operator: "Equal"value: "value"effect: "NoSchedule"
或者
tolerations:
- key: "key"operator: "Exists"effect: "NoSchedule"
Pod的Toleration声明中的key
和effect
需要与Taint
的设置保持一致,并且满足以下条件之一:
值 | 条件 |
---|---|
key | 空的key 配合Exists 操作符能够匹配所有键和值 |
operator | 值是Exists (无须指定value ), operator 的值是Equal 并且value 相等, 如果不指定operator ,则默认值为Equal |
effect | 空的effect 匹配所有effect ,在上面的例子中,effect 的取值为NoSchedule ,还可以取值为PreferNoSchedule ,这个值的意思是优先,也可以算作NoSchedule 的软限制版本 - 一个Pod 如果没有声明容忍这个Taint ,则系统会尽量避免把这个Pod 调度到这一 节点上,但不是强制的 |
系统允许在同一个Node上设置多个Taint,也可以在Pod上设置多个Toleration。
Kubernetes调度器处理多个Taint和Toleration的逻辑顺序为:首先列出节点中所有的Taint,然后忽略Pod的Toleration能够匹配的部分,剩下的没被忽略的Taint就是对Pod的效果了。
下面是几种特殊情况:
Taint
中存在effect=NoSchedule
,则调度器不会把该Pod
调度到这一节点上;Taint
中没有NoSchedule
效果,但是有PreferNoSchedule
效果,则调度器会尝试不把这个Pod
指派给这个节点;Taint
中有NoExecute
效果,并且这个Pod
已经在该节点上运行,则会被驱逐;例如,我们这样对一个节点进行Taint设置:
kubectl taint nodes node1 keyl=valuel:NoSchedule
kubectl taint nodes node1 keyl=valuel:NoExecute
kubectl taint nodes node1 key2=value2:NoSchedule
然后在Pod
上设置两个Toleration
:
tolerations:
- key: "key1"operator: "Equal"value: "valuel"effect: "NoSchedule"
- key: "key1"operator: "Equal"value: "valuel"effect: "NoExecute"
结果:
Pod
无法被调度到node1
上,这是因为第3个Taint
没有匹配的Toleration
。Pod
已经在node1
上运行了,那么在运行时设置第3个Taint
,它还能继续在node1
上运行,这是因为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: "valuel"effect: "NoExecute"tolerationSeconds: 3600
上述定义的意思是,如果Pod
正在运行,所在节点都被加入一个匹配的Taint
,则这个Pod
会持续在这个节点上存活3600s
后被逐出。如果在这个宽限期内Taint
被移除,则不会触发驱逐事件。
Taint和Toleration是一种处理节点并且让Pod进行规避或者驱逐Pod的弹性处理方式,下面列举一些常见的用例。
如果想要拿出一部分节点专门给一些特定应用使用,则可以为节点添加这样Taint
:
kubectl taint nodes nodename dedicated=groupName:NoSchedule
然后给这些应用的Pod
加入对应的Toleration
,这样,带有合适Toleration
的Pod
就会被允许同使用其他节点一样使用有Taint
的节点。
通过自定义Admission Controller
也可以实现这一目标。如果希望让这些应用独占一批节点,并且确保它们只能使用这些节点,则还可以给这些Taint
节点加入类似的标签dedicated=groupName
,然后Admission Controller
需要加入节点亲和 性设置,要求Pod
只会被调度到具有这一标签的节点上。
在集群里可能有一小部分节点安装了特殊的硬件设备(如GPU
芯片),用户自然会希望把不需要占用这类硬件的Pod
排除在外,以确保对这类硬件有需求的Pod
能够被顺利调度到这些节点上。
可以用下面的命令为节点设置Taint
:
kubectl taint nodes nodename special=true:NoSchedule
kubectl taint nodes nodename special=true:PreferNoSchedule
然后在Pod
中利用对应的Toleration
来保障特定的Pod
能够使用特定的硬件。
和上面独占节点的示例类似,使用Admission Controller
来完成这一任务会更方便,例如:
前面提到的NoExecute
这个Taint
效果对节点上正在运行的Pod
有以下影响:
注意,Kubernetes会自动给Pod添加下面几种Toleration:
以上添加的这种自动机制保证了在某些节点发生一些临时性问题时,Pod默认能够继续停留在当前节点运行5min等待节点恢复,而不是立即被驱逐,从而避免系统的异常波动。
另外,Kubernetes从1.6版本开始引入两个与Taint相关的新特性,TaintNodesByCondition及TaintBasedEvictions,用来改善异常情况下的Pod调度与驱逐问题,比如在节点内存吃紧、节点磁盘空间已满、节点失联等情况下,是 否自动驱逐某些Pod或者暂时保留这些Pod等待节点恢复正常。这个过程的完整逻 辑基本如下。
其中,检查Node
的状态并设置Node
的Taint
就是TaintNodesByCondition
特性,即在Node满足某些特定的条件时,自动为Node节点添加Taint,目前主要有以下几种条件:
条件 | 描述 |
---|---|
node.kubernetes.io/not-ready:节点未就绪 | 对应NodeCondition Ready为False的情况 |
node.kubernetes.io/unreachable:节点不可触达 | 对应NodeCondition Ready.为Unknown的情况 |
node.kubernetes.io/out-of-disk | 节点磁盘空间已满 |
node.kubernetes.io/network-unavailable | 节点网络不可用 |
node.kubernetes.io/unschedulable | 节点不可调度 |
node.cloudprovider,kubernetes.io/uninitialized | 如果kubelet是由"外部"云服务商启动的,则该污点用来标识某个节点当前为不可用状态。在云控制器 (cloud-controller-manager)初始化这个节点以后,kubelet会将此污点移除 |
自Kubernetes 1.13开始,上述两个特性被默认启用,TaintNodesByCondition 这个特性只会为节点添加NoSchedule效果的污点,TaintBasedEviction则为节点添加NoExecute效果的污点。
在TaintBasedEvictions特性被开启之后,kubelet会在有资源压力时对相应的Node节点自动加上对应的NoExecute效果的Taint,例如 node.kubernetes.io/memory-pressure、node.kubernetes.io/disk-pressure。
如果Pod没有设置对应的Toleration,则这部分Pod将被驱逐,以确保节点不会崩溃。
本文主要讲解了pod的污点与容忍的概念、案例及应用的场景,希望能帮助到大家,谢谢大家的阅读,本文完!