Kubernetes資源排程之汙點與Pod容忍度
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 <key,value,effect> using the matching operator <operator>.
FIELDS:
effect <string>
Effect indicates the taint effect to match. Empty means match all taint
effects. When specified, allowed values are NoSchedule, PreferNoSchedule
and NoExecute.
key <string>
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 <string>
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 <integer>
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 <string>
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等。