引用
概念文档:污点和容忍度 | Kubernetes
命令文档:Kubectl Reference Docs (kubernetes.io)
污点/容忍概念
Node上的污点规则,即Node告知调度器只有可以容忍污点规则的Pod才可以调度过来。
Node的污点规则由两部分组成:污点:污点效果。
-
污点就是键值对,用来描述一种场景。例如网络不通、硬件标识(低性能HDD磁盘)、环境(测试环境)
-
污点效果是判定规则,用来判断是否可以调度到节点上。
Pod上的容忍规则,即Pod告知调度器可以容忍Node上设定的污点规则。
🍖容忍规则和污点规则都可以添加多个。
污点/容忍命令
Node的污点规则:
# 添加污点
## 标签对:污染关键词
kubectl taint nodes <node.name> KEY_1=VAL_1:TAINT_EFFECT_1 KEY_N=VAL_N:TAINT_EFFECT_N
# 移除污点
kubectl taint nodes <node.name> KEY_1-
# 查看节点污染信息,若无污染则为 none
kubectl describe nodes <node.name> | grep Taints
Taints: node-role.kubernetes.io/master:NoSchedule
Pod容忍规则:
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
operator 可以是Equal等于或者Exists存在。
调度逻辑
首先,Pod的容忍规则需要完全等同于污点规则,即污点和污点效果都一致才算是匹配成功。但存在特殊情况:
- 仅定义了
operator:Exists
,则表示匹配任意污点规则。 - 仅定义了污点,没有定义污点效果,则表示匹配这个污点的所有效果。
其次,当Node的污点规则有多个的时候,调度器会将Pod的容忍规则与之一一匹配。就如同小学题里那种连线题一样。
最后,若都可以匹配,则Pod可以调度进去。但只要存在一个不匹配的污点规则,那么调度器就需要依据这个污点规则的污点效果来判断Pod的进/退:
- 进:针对还未创建的Pod,是否将Pod调度进去。
- 退:针对已经创建的Pod,是否将Pod驱逐滚蛋。
污点效果
一般情况,若Node存在下列污点效果,调度器的逻辑是:
NoSchedule
表示调度器不可调度【还未创建的】Pod到此节点。
PreferNoSchedule
表示尽量不要调度【还未创建的】Pod到此节点。
NoExecute
表示绝不允许调度Pod到此节点,哪怕Pod【已经创建】都会被驱逐。
针对【NoExecute】,若可以【匹配NoExecute】的Pod里包含了额外的宽恕期规则tolerationSeconds
,则Pod【仅可以】在tolerationSeconds
宽恕期之内运行。
🤦♂️经测试,即使是污点规则添加之后的Pod,也只可以在tolerationSeconds
内运行。因此这个宽恕期不如称之为【可运行时间】。
例如:
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
tolerations:
- key: "example-key"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 3600
上述配置表示,当 pod 所在节点被添加了一个example-key:NoExecute
污点的时候,pod 将不会被驱逐,而是可以继续存活3600秒,如果还未到3600秒,污点就被移除,则 pod 驱逐也会停止。
自动污点规则
当某种条件为真时,节点控制器会自动给节点添加一个污点。当前内置的污点包括:
node.kubernetes.io/not-ready:NoExecute
:节点未准备好。这相当于节点状态Ready
的值为 “False
”。node.kubernetes.io/unreachable:NoExecute
:节点控制器访问不到节点. 这相当于节点状态Ready
的值为 “Unknown
”。node.kubernetes.io/memory-pressure:NoSchedule
:节点存在内存压力。node.kubernetes.io/disk-pressure:NoSchedule
:节点存在磁盘压力。node.kubernetes.io/pid-pressure:NoSchedule
: 节点的 PID 压力。node.kubernetes.io/network-unavailable:NoSchedule
:节点网络不可用。node.kubernetes.io/unschedulable:NoSchedule
: 节点不可调度。node.cloudprovider.kubernetes.io/uninitialized
:如果 kubelet 启动时指定了一个 “外部” 云平台驱动, 它将给当前节点添加一个污点将其标志为不可用。在 cloud-controller-manager 的一个控制器初始化这个节点后,kubelet 将删除这个污点。
在节点被驱逐的时候,节点控制器或者 kubelet 会添加带有 NoExecute
污点效果的相关内置污点。异常恢复的时候,会自动移除污点。
🤷♂️关于用
kubectl drain
执行驱逐的时候,node显示的污点只有一个node.kubernetes.io/unschedulable:NoSchedule。但实际效果是node.kubernetes.io/unschedulable:NoExecute
。即驱逐命令会驱逐掉已存在的Pod。可能kubectl drain
会添加内置的特殊污点效果。➜ kubectl drain k8s03 --ignore-daemonsets --delete-emptydir-data ➜ kubectl describe node k8s03 | grep Taints Taints: node.kubernetes.io/unschedulable:NoSchedule
如果你想让某个pod在节点出现问题(例如节点网络故障)后,依然被调度在当前节点保持1小时,那么你可以添加下列容忍规则:
tolerations:
- key: "node.kubernetes.io/network-unavailable"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 3600
自动容忍规则
Kubernetes 会自动给 Pod 添加内置污点 node.kubernetes.io/not-ready:NoExecute
的容忍度并配置 tolerationSeconds=300
,除非用户提供的 Pod 配置中已经已存在了 key 为 node.kubernetes.io/not-ready
的容忍度。
Kubernetes 会自动给 Pod 添加内置污点 node.kubernetes.io/unreachable:NoExecute
的容忍度并配置 tolerationSeconds=300
,除非用户提供的 Pod 配置中已经已存在了 key 为 node.kubernetes.io/unreachable
的容忍度。
这意味着在其中一种问题被检测到时 Pod 默认能够继续停留在当前节点运行 5 分钟。
但是,对于DaemonSet的Pod,则不会配置tolerationSeconds
。这意味着,Node出现上述问题后,这类Pod将永久运行不被驱逐。
DaemonSet的自动附加容忍度:
node.kubernetes.io/disk-pressure:NoSchedule op=Exists
node.kubernetes.io/memory-pressure:NoSchedule op=Exists
node.kubernetes.io/network-unavailable:NoSchedule op=Exists
node.kubernetes.io/pid-pressure:NoSchedule op=Exists
node.kubernetes.io/unschedulable:NoSchedule op=Exists
node.kubernetes.io/not-ready:NoExecute op=Exists
node.kubernetes.io/unreachable:NoExecute op=Exists
🍖DaemonSet中除了上述自动容忍度,还经常见到万能容忍度:NoSchedule op=Exists 或者 op=Exists
。