k8s教程(16)-pod之污点与容忍

时间:2022-12-10 07:59:20


文章目录

  • ​​01 引言​​
  • ​​02 案例​​
  • ​​2.1 污点与容忍设置​​
  • ​​2.1.1 Node设置污点​​
  • ​​2.1.2 Pod声明容忍​​
  • ​​2.1.3 小结​​
  • ​​2.2 特殊情况​​
  • ​​03 应用场景​​
  • ​​3.1 独占节点​​
  • ​​3.2 具有特殊硬件设备的节点​​
  • ​​3.3 定义Pod驱逐行为,以应对节点故障​​
  • ​​04 文末​​

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 小结

PodToleration声明中的​​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 应用场景

TaintToleration一种处理节点并且让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等待节点恢复正常。这个过程的完整逻 辑基本如下。

  1. 不断地检查所有Node状态,设置对应的Condition;
  2. 不断地根据Node Condition设置对应的Taint;
  3. 不断地根据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的污点与容忍的概念、案例及应用的场景,希望能帮助到大家,谢谢大家的阅读,本文完!