污點taints
是定義在節點之上的鍵值型屬性數據,用於讓節點拒絕將Pod
調度運行於其上, 除非該Pod
對象具有接納節點污點的容忍度。而容忍度tolerations
是定義在 Pod
對象上的鍵值型屬性數據,用於配置其可容忍的節點污點,而且調度器僅能將Pod
對象調度至其能夠容忍該節點污點的節點之上,如圖所示
節點選擇器nodeSelector
和節點親和性nodeAffinity
兩種調度方式都是通過在 Pod
對象上添加標簽選擇器來完成對特定類型節點標簽的匹配,它們實現的是由Pod
選擇節點的機制。而污點和容忍度則是通過向節點添加污點信息來控制Pod
對象的調度結果,從而賦予了節點控制何種Pod
對象能夠調度於其上的主控權。簡單來說,節點親和性使得Pod
對象被吸引到一類特定的節點,而污點則相反,它提供了讓節點排斥特定Pod
對象的能力。
Kubernetes
使用PodToleratesNodeTaints
預選策略和 TaintTolerationPriority
優選函數來完成此種類型的高級調度機制。
2、定義污點和容忍度
污點定義在節點的node Spec
中,而容忍度則定義在Pod
的podSpec
中,它們都是鍵值型數據,但又都額外支持一個效果effect
標記,語法格式為key=value:effect
,其中key
和value
的用法及格式與資源注俯-信息相似, 而effect
則用於定義對Pod
對象的排斥等級,它主要包含以下三種類型
- NoSchedule
不能容忍此污點的新Pod
對象不可調度至當前節點,屬於強制型約束關系,節點上現存的Pod
對象不受影響。 - PreferNoSchedule
NoSchedule
的柔性約束版本,即不能容忍此污點的新Pod
對象盡量不要調度至當前節點,不過無其他節點可供調度時也允許接受相應的Pod
對象。節點上現存的Pod
對象不受影響。 - NoExecute
不能容忍此污點的新Pod
對象不可調度至當前節點,屬於強制型約束關系,而且節點上現存的Pod
對象因節點污點變動或Pod
容忍度變動而不再滿足匹配規則時,Pod
對象將被驅逐。
在Pod
對象上定義容忍度時,它支持兩種操作符:一種是等值比較Equal
,表示容忍度與污點必須在key
、value
和effect
三者之上完全匹配;另一種是存在性判斷Exists
,表示二者的key
和effect
必須完全匹配,而容忍度中的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-tppe
、node-role
、node-project
或node-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>]-
例如,刪除nodeO1
上node-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
對象的時長
注:
如果operator
是Exists
(此時容忍度不能指定 value)
如果operator
是Equal
,則它們的value
應該相等
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
tolerationSeconds: 3600
使用存在性判斷機制的容忍度示例如下
tolerations:
- key: "key1"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 3600
實踐中,若集群中的一組機器專用於為運行非生產型的容器應用而備置,而且它們可能隨時按需上下線,那么就應該為其添加污點信息,以確保僅那些能容忍此污點的非生產型Pod
對象可以調度其上。另外,某些有着特殊硬件的節點需要專用於運行一類有着此類硬件資源需求的Pod
對象時,例如,那些有着SSD
或GPU
的設備,也應該為其添加污點信息以排除其他的Pod
對象。
5、問題節點標識
Kubernetes
自1.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-proxy
或kube- flannel
等。