1. 程式人生 > 實用技巧 >k8s 汙點和容忍度

k8s 汙點和容忍度

汙點taints是定義在節點之上的鍵值型屬性資料,用於讓節點拒絕將Pod排程運行於其上, 除非該Pod物件具有接納節點汙點的容忍度。而容忍度tolerations是定義在 Pod物件上的鍵值型屬性資料,用於配置其可容忍的節點汙點,而且排程器僅能將Pod物件排程至其能夠容忍該節點汙點的節點之上,如圖所示

節點選擇器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等。