Kubernetes资源调度之污点与Pod容忍度
概述
污点是定义在节点之上的键值型属性数据,用于让节点有能力主动拒绝调度器将Pod调度运行到节点上,除非该Pod对象具有接纳节点污点的容忍度。容忍度(tolerations)则是定义在Pod对象上的键值型属性数据,用于配置该Pod可容忍的节点污点,否则该 Taints 节点不会被调度 Pod。
我们知道,节点选择器(nodeSelector)和节点亲和性(nodeAffinity)两种调度方式都是通过在Pod对象上添加标签选择器来完成对特定类型节点标签的匹配,从而完成节点选择和绑定,节点亲和调度使得Pod对象被吸引到一类特定的节点,而污点的作用则相反,它为节点提供了排斥特定Pod对象的能力。
比如用户希望把 Master 节点保留给 Kubernetes 系统组件使用,或者把一组具有特殊资源预留给某些 Pod,则污点就很有用了,Pod 不会再被调度到 taint 标记过的节点。我们使用 kubeadm 搭建的集群默认就给 master 节点添加了一个污点标记,所以我们看到我们平时的 Pod 都没有被调度到 master 上去:
- [root@k8s-01 ~]# kubectl describe node k8s-01
- Name: k8s-01
- Roles: master
- Labels: beta.kubernetes.io/arch=amd64
- beta.kubernetes.io/os=linux
- kubernetes.io/arch=amd64
- kubernetes.io/hostname=master1
- kubernetes.io/os=linux
- node-role.kubernetes.io/master=
- ......
- Taints: node-role.kubernetes.io/master:NoSchedule
- Unschedulable: false
- ......
其中有一条关于 Taints 的信息:node-role.kubernetes.io/master:NoSchedule
,就表示master 节点打了一个污点的标记,其中影响的参数是 NoSchedule
,表示 Pod 不会被调度到标记为 taints 的节点,效用标识主要有以下3种类型。
-
NoSchedule:不能容忍此污点的Pod对象不可调度至当前节点,属于强制型约束关系,但添加污点对节点上现存的Pod对象不产生影响。
-
PreferNoSchedule:NoSchedule 的软策略版本,表示尽量不调度到污点节点上去;添加该类效用的污点同样对节点上现存的Pod对象不产生影响。
-
NoExecute:该选项意味着一旦 Taint 生效,如该节点内正在运行的 Pod 没有对应容忍(Tolerate)设置,则会直接被逐出
定义删除污点
任何符合键值规范要求的字符串均可用于定义污点信息:可使用字母、数字、连接符、点号和下划线,且仅能以字母或数字开头,其中键名的长度上限为253个字符,值最长为63个字符。实践中,污点通常用于描述具体的部署规划,它们的键名形如node-type、node-role、node-project或node-geo等,而且一般还会在必要时带上域名以描述一些额外信息,例如node-type.ilinux.io等。kubectl taint命令可用于管理Node对象的污点信息,污点 taint 标记节点的命令如下:
- [root@k8s-01 ~]# kubectl taint nodes k8s-02 test=node2:NoSchedule
- node/k8s-02 tainted
- [root@k8s-01 ~]#
删除污点,指定key和value,则具体删除这一个污点:
- [root@k8s-01 ~]# kubectl taint nodes k8s-02 test=node2:NoSchedule-
- node/k8s-02 untainted
- [root@k8s-01 ~]#
如果只指定具体的key,则删除该key下的所有污点:
- [root@k8s-01 ~]# kubectl taint nodes k8s-02 test=node2:NoSchedule
- node/k8s-02 tainted
- [root@k8s-01 ~]# kubectl taint nodes k8s-02 test=node3:NoExecute
- node/k8s-02 tainted
- [root@k8s-01 ~]# kubectl taint nodes k8s-02 test-
- node/k8s-02 untainted
- [root@k8s-01 ~]#
定义容忍度
Pod对象的容忍度通过其spec.tolerations字段添加,根据使用的操作符不同,主要有两种可用形式:一种是与污点信息完全匹配的等值关系;另一种是判断污点信息存在性的匹配方式,它们分别使用Equal和Exists操作符表示。下面容忍度的定义示例使用了Equal操作符,其中tolerationSeconds用于定义延迟驱逐当前Pod对象的时长。
查看官方说明:
- [root@k8s-01 ~]# kubectl explain deploy.spec.template.spec.tolerations
- KIND: Deployment
- VERSION: apps/v1
-
- RESOURCE: tolerations <[]Object>
-
- DESCRIPTION:
- If specified, the pod's tolerations.
-
- The pod this Toleration is attached to tolerates any taint that matches the
- triple
using the matching operator . -
- FIELDS:
- effect
- Effect indicates the taint effect to match. Empty means match all taint
- effects. When specified, allowed values are NoSchedule, PreferNoSchedule
- and NoExecute.
-
- key
- Key is the taint key that the toleration applies to. Empty means match all
- taint keys. If the key is empty, operator must be Exists; this combination
- means to match all values and all keys.
-
- operator
- Operator represents a key's relationship to the value. Valid operators are
- Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for
- value, so that a pod can tolerate all taints of a particular category.
-
- tolerationSeconds
- TolerationSeconds represents the period of time the toleration (which must
- be of effect NoExecute, otherwise this field is ignored) tolerates the
- taint. By default, it is not set, which means tolerate the taint forever
- (do not evict). Zero and negative values will be treated as 0 (evict
- immediately) by the system.
-
- value
- Value is the taint value the toleration matches to. If the operator is
- Exists, the value should be empty, otherwise just a regular string.
-
- [root@k8s-01 ~]#
operator
的默认值是 Equal
。
一个容忍度和一个污点相“匹配”是指它们有一样的键名和效果,并且:
- 如果
operator
是Exists
(此时容忍度不能指定value
),如果一个容忍度的key
为空且 operator 为Exists
, 表示这个容忍度与任意的 key 、value 和 effect 都匹配,即这个容忍度能容忍任意 taint。 - 如果
operator
是Equal
,则它们的value
应该相等 - 空的 effect 匹配所有的 effect
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: taint
- labels:
- app: taint
- spec:
- replicas: 20
- selector:
- matchLabels:
- app: taint
- template:
- metadata:
- labels:
- app: taint
- spec:
- containers:
- - name: nginx
- image: nginx
- ports:
- - name: http
- containerPort: 80
- tolerations:
- - key: "test"
- operator: "Exists"
- effect: "NoSchedule"
由于node2节点被标记为了污点,所以我们这里要想 Pod 能够调度到改节点去,就需要增加容忍的声明:
- tolerations:
- - key: "test"
- operator: "Exists"
- effect: "NoSchedule"
然后创建上面的资源,查看结果:
如果将key改成test2,则没有pod运行在02节点
k8s内置污点
当某种条件为真时,节点控制器会自动给节点添加一个污点。当前内置的污点包括:
node.kubernetes.io/not-ready
:节点未准备好。这相当于节点状态Ready
的值为 "False
"。node.kubernetes.io/unreachable
:节点控制器访问不到节点. 这相当于节点状态Ready
的值为 "Unknown
"。node.kubernetes.io/memory-pressure
:节点存在内存压力。node.kubernetes.io/disk-pressure
:节点存在磁盘压力。node.kubernetes.io/pid-pressure
: 节点的 PID 压力。node.kubernetes.io/network-unavailable
:节点网络不可用。node.kubernetes.io/unschedulable
: 节点不可调度。node.cloudprovider.kubernetes.io/uninitialized
:如果 kubelet 启动时指定了一个 "外部" 云平台驱动, 它将给当前节点添加一个污点将其标志为不可用。在 cloud-controller-manager 的一个控制器初始化这个节点后,kubelet 将删除这个污点。
不过,Kubernetes的核心组件通常都要容忍此类的污点,以确保相应的DaemonSet控制器能够无视此类污点在节点上部署相应的关键Pod对象,例如kube-proxy或kube-flannel等。