01 引言
声明:本文为《Kubernetes权威指南:从Docker到Kubernetes实践全接触(第5版)》的读书笔记
在前面的博客《k8s教程(15)-pod之亲和性与互斥性调度》讲解的NodeAffinity节点亲和性
,是在Pod
上定义的一种属性,使得Pod
能够被调度到某些Node
上运行(优先选择或强制要求)。
Taint(污点) 则正好相反,它让Node
拒绝Pod
的运行。简单地说,被标记为Taint
的节点就是存在问题的节点,比 如磁盘要满、资源不足、存在安全隐患要进行升级维护,希望新的Pod
不会被调度过来。
但被标记为Taint
的节点并非故障节点,仍是有效的工作节点,所以仍需将某些Pod
调度到这些节点上时,可以通过使用Toleration
属性来实现。
02 案例
2.1 污点与容忍设置
在默认情况下,在Node
上设置一个或多个Taint
之后,除非Pod
明确声明能够容忍这些污点,否则无法在这些Node
上运行。
2.1.1 Node设置污点
可以用kubectl taint
命令为Node
设置Taint
信息:
kubectl taint nodes node1 key=value:NoSchedule
描述:这个设置为node1
加上了一个Taint
,该Taint
的键为key
,值为value
,Taint
的效果是NoSchedule
,这意味着除非Pod
明确声明可以容忍这个Taint
,否则不会被调度到node1
上。
2.1.2 Pod声明容忍
在Pod
上声明容忍的例子如下,下面的两个Toleration
都被设置为可以容忍(Tolerate
)具有该Taint
的Node
,使得Pod
能够被调度到node1
上:
tolerations: - key: "key" operator: "Equal" value: "value" effect: "NoSchedule"
或者
tolerations: - key: "key" operator: "Exists" effect: "NoSchedule"
2.1.3 小结
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的效果了。
2.2 特殊情况
下面是几种特殊情况:
- 如果在剩余的
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
被移除,则不会触发驱逐事件。
03 应用场景
Taint和Toleration是一种处理节点并且让Pod进行规避或者驱逐Pod的弹性处理方式,下面列举一些常见的用例。
3.1 独占节点
如果想要拿出一部分节点专门给一些特定应用使用,则可以为节点添加这样Taint
:
kubectl taint nodes nodename dedicated=groupName:NoSchedule
然后给这些应用的Pod
加入对应的Toleration
,这样,带有合适Toleration
的Pod
就会被允许同使用其他节点一样使用有Taint
的节点。
通过自定义Admission Controller
也可以实现这一目标。如果希望让这些应用独占一批节点,并且确保它们只能使用这些节点,则还可以给这些Taint
节点加入类似的标签dedicated=groupName
,然后Admission Controller
需要加入节点亲和 性设置,要求Pod
只会被调度到具有这一标签的节点上。
3.2 具有特殊硬件设备的节点
在集群里可能有一小部分节点安装了特殊的硬件设备(如GPU
芯片),用户自然会希望把不需要占用这类硬件的Pod
排除在外,以确保对这类硬件有需求的Pod
能够被顺利调度到这些节点上。
可以用下面的命令为节点设置Taint
:
kubectl taint nodes nodename special=true:NoSchedule kubectl taint nodes nodename special=true:PreferNoSchedule
然后在Pod
中利用对应的Toleration
来保障特定的Pod
能够使用特定的硬件。
和上面独占节点的示例类似,使用Admission Controller
来完成这一任务会更方便,例如:
- Admission Controller使用Pod的一些特征来判断这些Pod,如果可以使用这些件,就添加Toleration来完成这一工作;
- 要保障需要使用特殊硬件的Pod只被调度到安装这些硬件的节点上,则还需要一些额外的工作,比如将这些特殊资源使用opaque-int-resource的方式对自定义资源进行量化,然后在PodSpec中进行请求;
- 也可以使用标签的方式来标注这些安装有特别硬件的节点,然后在Pod 中定义节点亲和性来实现这个目标。
3.3 定义Pod驱逐行为,以应对节点故障
前面提到的NoExecute
这个Taint
效果对节点上正在运行的Pod
有以下影响:
- 没有设置Toleration的Pod会被立刻驱逐;
- 配置了对应Toleration的Pod,如果没有为tolerationSeconds赋值,则会一直留在这一节点中;
- 配置了对应Toleration的Pod且指定了tolerationSeconds值,则会在指定的时间后驱逐(注意,在节点发生故障的情况下,系统将会以限速(rte- limiting)模式逐步给Node设置Taint,这样就能避免在一些特定情况下(比如
Master暂时失联)有大量的Pod被驱逐)。
注意,Kubernetes会自动给Pod添加下面几种Toleration:
- key为node.kubernetes.io/not-ready,并配置tolerationSeconds=300;
- key 为node.kubernetes.io/unreachable,并配置tolerationSeconds=300。
以上添加的这种自动机制保证了在某些节点发生一些临时性问题时,Pod默认能够继续停留在当前节点运行5min等待节点恢复,而不是立即被驱逐,从而避免系统的异常波动。
另外,Kubernetes从1.6版本开始引入两个与Taint相关的新特性,TaintNodesByCondition及TaintBasedEvictions,用来改善异常情况下的Pod调度与驱逐问题,比如在节点内存吃紧、节点磁盘空间已满、节点失联等情况下,是 否自动驱逐某些Pod或者暂时保留这些Pod等待节点恢复正常。这个过程的完整逻 辑基本如下。
- 不断地检查所有Node状态,设置对应的Condition;
- 不断地根据Node Condition设置对应的Taint;
- 不断地根据Taint驱逐Node上的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将被驱逐,以确保节点不会崩溃。
04 文末
本文主要讲解了pod的污点与容忍的概念、案例及应用的场景,希望能帮助到大家,谢谢大家的阅读,本文完!