k8s 污点和容忍度

污点taints是定义在节点之上的键值型属性数据,用于让节点拒绝将Pod调度运行于其上, 除非该Pod对象具有接纳节点污点的容忍度。而容忍度tolerations是定义在 Pod对象上的键值型属性数据,用于配置其可容忍的节点污点,而且调度器仅能将Pod对象调度至其能够容忍该节点污点的节点之上,如图所示

img

节点选择器nodeSelector和节点亲和性nodeAffinity两种调度方式都是通过在 Pod对象上添加标签选择器来完成对特定类型节点标签的匹配,它们实现的是由Pod选择节点的机制。而污点和容忍度则是通过向节点添加污点信息来控制Pod对象的调度结果,从而赋予了节点控制何种Pod对象能够调度于其上的主控权。简单来说,节点亲和性使得Pod对象被吸引到一类特定的节点,而污点则相反,它提供了让节点排斥特定Pod对象的能力。

Kubernetes使用PodToleratesNodeTaints预选策略和 TaintTolerationPriority优选函数来完成此种类型的高级调度机制。

2、定义污点和容忍度

污点定义在节点的node Spec中,而容忍度则定义在PodpodSpec中,它们都是键值型数据,但又都额外支持一个效果effect标记,语法格式为key=value:effect,其中keyvalue的用法及格式与资源注俯-信息相似, 而effect则用于定义对Pod对象的排斥等级,它主要包含以下三种类型

  • NoSchedule
    不能容忍此污点的新Pod对象不可调度至当前节点,属于强制型约束关系,节点上现存的Pod对象不受影响。
  • PreferNoSchedule
    NoSchedule的柔性约束版本,即不能容忍此污点的新Pod对象尽量不要调度至当前节点,不过无其他节点可供调度时也允许接受相应的Pod对象。节点上现存的Pod对象不受影响。
  • NoExecute
    不能容忍此污点的新Pod对象不可调度至当前节点,属于强制型约束关系,而且节点上现存的Pod对象因节点污点变动或Pod容忍度变动而不再满足匹配规则时,Pod对象将被驱逐。

Pod对象上定义容忍度时,它支持两种操作符:一种是等值比较Equal,表示容忍度与污点必须在keyvalueeffect三者之上完全匹配;另一种是存在性判断Exists,表示二者的keyeffect必须完全匹配,而容忍度中的value字段要使用空值。

一个节点可以配置使用多个污点,一个Pod对象也可以有多个容忍度,不过二者在进行匹配检查时应遵循如下逻辑。

  • 首先处理每个有着与之匹配的容忍度的污点
  • 不能匹配到的污点上,如果存在一个污点使用了NoSchedule效用标识,则拒绝调度Pod对象至此节点
  • 不能匹配到的污点上,若没有任何一个使用了NoSchedule效用标识,但至少有一个使用了PreferNoScheduler,则应尽量避免将Pod对象调度至此节点
  • 如果至少有一个不匹配的污点使用了NoExecute效用标识,则节点将立即驱逐Pod对象,或者不予调度至给定节点;另外,即便容忍度可以匹配到使用了 NoExecute效用标识的污点,若在定义容忍度时还同时使用tolerationSeconds属性定义了容忍时限,则超出时限后其也将被节点驱逐。

使用kubeadm部署的Kubernetes集群,其Master节点将自动添加污点信息以阻止不能容忍此污点的Pod对象调度至此节点,因此,用户手动创建的未特意添加容忍此污点容忍度的Pod对象将不会被调度至此节点

kubectl describe nodes k8s-master-01
Name:               k8s-master-01
Roles:              master
Labels:             beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/os=linux
                    kubernetes.io/arch=amd64
                    kubernetes.io/hostname=k8s-master-01
                    kubernetes.io/os=linux
                    node-role.kubernetes.io/master=
......
Taints:             node-role.kubernetes.io/master:NoSchedule
Unschedulable:      false

有些系统级应用,如kube-proxy或者kube-flannel等,都在资源创建时就添加上了相应的容忍度以确保它们被DaemonSet控制器创建时能够调度至Master节点运行一个实例:

# kubectl -n kube-system describe pods calico-node-pw5n9
......
Node-Selectors:  beta.kubernetes.io/os=linux
Tolerations:     :NoSchedule
                 :NoExecute
                 CriticalAddonsOnly
                 node.kubernetes.io/disk-pressure:NoSchedule
                 node.kubernetes.io/memory-pressure:NoSchedule
                 node.kubernetes.io/network-unavailable:NoSchedule
                 node.kubernetes.io/not-ready:NoExecute
                 node.kubernetes.io/pid-pressure:NoSchedule
                 node.kubernetes.io/unreachable:NoExecute
                 node.kubernetes.io/unschedulable:NoSchedule

这类Pod是构成Kubernetes系统的基础且关键性的组件,它们甚至还定义了更大的容忍度。从上面某calico-node实例的容忍度定义来看,它还能容忍那些报告了磁盘压力或内存压力的节点,以及未就绪的节点和不可达的节点,以确保它们能在任何状态下正常调度至集群节点上运行。

3、管理节点的污点

任何符合其键值规范要求的字符串均可用于定义污点信息:仅可使用字母、数字、连接符、点号和下划线,且仅能以字母或数字开头,其中键名的长度上限为253个字符,值最长为63个字符。实践中,污点通常用于描述具体的部署规划,它们的键名形如node-tppenode-rolenode-projectnode-geo等,因此还可在必要时带上域名以描述其额外的信息,如node-type.linux.io等。使用kubectl taint命令即可向节点添加污点,命令的语法格式如下:

kubectl taint nodes <node-name> <key>=<value>:<effect> 

例如,使用node-type=production:NoSchedule定义节点node01.linux.io:

# kubectl taint nodes node01.linux.io node-type=production:NoSchedule
node "node01.linux.io" tainted

此时,nodeO1上已有的Pod对象不受影响,但新建的Pod若不能容忍此污点将不能再被调度至此节点。可以查看节点上的污点信息:

# kubectl get nodes node01.linux.io -o go-template={{.spec.taints}}
[map[value:production effect:NoSchedule key:node-type]]

需要注意的是,即便是同一个键值数据,若其效用标识不同,则其也分属于不同的污点信息,例如,将上面命令中的效用标识定义为PreferNoSchedule再添加一次

# kubectl taint nodes node01.linux.io node-type=production:PreferNoSchedule
node "node01.linux.io" tainted

删除某污点,仍然通过kubectl taint命令进行,但要使用如下的命令格式,省略效用标识则表示删除使用指定键名的所有污点,否则就只删除指定键名上对应效用标识的污点:

kubectl taint nodes <node-name> <key>:[<effect>]- 

例如,删除nodeO1node-type键的效用标识为NoSchedule的污点信息:

# kubectl taint nodes node01.linux.io node-type:NoSchedule- 
node "node01.linux.io" untainted

若要删除使用指定键名的所有污点,则在删除命令中省略效用标识即能实现,例如:

# kubectl taint nodes node01.linux.io node-type- 
node "node01.linux.io" untainted

删除节点上的全部污点信息,通过kubectl patch命令将节点属性spec.taints的值直接置空即可,例如:

# kubectl patch nodes node01.linux.io -p '{"spec":{"taints":[]}}' 
node "node01.linux.io" patched

节点污点的变动会影响到新建Pod对象的调度结果,而且使用NoExecute进行标识时,还会影响到节点上现有的Pod对象。

4、Pod对象的容忍度

Pod对象的容忍度可通过其spec.tolerations字段进行添加,根据使用的操作符不同,主要有两种可用的形式:一种是与污点信息完全匹配的等值关系;另一种是判断污点信息存在性的匹配方式。使用Equal操作符的示例如下所示,其中 tolerationSeconds用于定义延迟驱逐当前Pod对象的时长

注:
如果operatorExists(此时容忍度不能指定 value)
如果operatorEqual,则它们的value应该相等

tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoExecute"
  tolerationSeconds: 3600

使用存在性判断机制的容忍度示例如下

tolerations:
- key: "key1"
  operator: "Exists"
  effect: "NoExecute"
  tolerationSeconds: 3600

实践中,若集群中的一组机器专用于为运行非生产型的容器应用而备置,而且它们可能随时按需上下线,那么就应该为其添加污点信息,以确保仅那些能容忍此污点的非生产型Pod对象可以调度其上。另外,某些有着特殊硬件的节点需要专用于运行一类有着此类硬件资源需求的Pod对象时,例如,那些有着SSDGPU的设备,也应该为其添加污点信息以排除其他的Pod对象。

5、问题节点标识

Kubernetes1.6版本起支持使用污点自动标识问题节点,它通过节点控制器在特定条件下自动为节点添加污点信息实现。它们都使用NoExecute效用标识,因此不能容忍此类污点的现有Pod对象也会遭到驱逐。目前,内建使用的此类污点包含如下几个。

  • node.kubernetes.io/not-ready

节点进入NotReady状态时被自动添加的污点

  • node.alpha.kubernetes.io/unreachable

节点进入NotReachable状态时被自动添加的污点

  • node.kubernetes.io/out-of-disk

节点进入OutOfDisk状态时被自动添加的污点

  • node.kubernetes.io/memory-pressure
    节点内存资源面临压力
  • node.kubernetes.io/disk-pressure

节点磁盘资源面临压力

  • node.kubernetes.io/network-unavailable

节点网络不可用

  • node.cloudprovider.kubernetes.io/uninitialized

kubelet由外部的云环境程序启动时,
它将自动为节点添加此污点,待到云控制器管理器中的控制器初始化此节点时再将其删除

Kubernetes的核心组件通常都要容忍此类的污点,以确保其相应的DaemonSet控制器能够无视此类污点,于节点上部署相应的关键性Pod对象,例如kube-proxykube- flannel等。

posted @ 2020-09-21 15:07  包泽旭  阅读(1176)  评论(0编辑  收藏