污點與容忍度
節點親和性 是 Pod 的一個屬性,會吸引它們到一組節點(作為偏好或硬性要求)。污點則相反——它們允許節點排斥一組 Pod。
容忍度會套用到 Pod。容忍度允許排程器排程具有相符污點的 Pod。容忍度允許排程,但不保證排程:排程器也會評估其他參數作為其功能的一部分。
污點與容忍度協同運作,以確保 Pod 不會排程到不適當的節點上。一個或多個污點會套用到節點;這標記該節點不應接受任何不容忍污點的 Pod。
概念
您可以使用 kubectl taint 將污點新增到節點。例如,
kubectl taint nodes node1 key1=value1:NoSchedule
在節點 node1
上放置一個污點。污點具有鍵 key1
、值 value1
和污點效果 NoSchedule
。這表示除非 Pod 具有相符的容忍度,否則任何 Pod 都無法排程到 node1
上。
若要移除上述命令新增的污點,您可以執行
kubectl taint nodes node1 key1=value1:NoSchedule-
您可以在 PodSpec 中指定 Pod 的容忍度。以下兩個容忍度都「符合」上述 kubectl taint
行建立的污點,因此具有任一容忍度的 Pod 都能夠排程到 node1
上
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
tolerations:
- key: "key1"
operator: "Exists"
effect: "NoSchedule"
預設的 Kubernetes 排程器在選擇要執行特定 Pod 的節點時,會考量污點與容忍度。但是,如果您手動為 Pod 指定 .spec.nodeName
,則該動作會繞過排程器;Pod 隨後會繫結到您指派的節點上,即使您選取的節點上有 NoSchedule
污點。如果發生這種情況,且節點也設定了 NoExecute
污點,則 kubelet 將會驅逐 Pod,除非設定了適當的容忍度。
以下是一個定義了一些容忍度的 Pod 範例
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: "NoSchedule"
operator
的預設值為 Equal
。
如果鍵相同且效果相同,並且
operator
為Exists
(在這種情況下不應指定value
),或operator
為Equal
且值應相等,則容忍度「符合」污點。
注意
有兩個特殊情況
如果 key
為空,則 operator
必須為 Exists
,這會符合所有鍵與值。請注意,effect
仍然需要同時符合。
空的 effect
符合具有鍵 key1
的所有效果。
上述範例使用了 NoSchedule
的 effect
。或者,您可以使用 PreferNoSchedule
的 effect
。
effect
欄位的允許值為
NoExecute
- 這會以下列方式影響已在節點上執行的 Pod
- 不容忍污點的 Pod 會立即被驅逐
- 在容忍度規格中未指定
tolerationSeconds
的容忍污點的 Pod 將永遠保持繫結 - 容忍汙染的 Pod 在指定的
tolerationSeconds
期間內保持綁定。經過這段時間後,節點生命週期控制器會將 Pod 從節點驅逐。
NoSchedule
- 除非新的 Pod 具有相符的容忍度,否則不會將新的 Pod 排程到受汙染的節點上。目前在節點上執行的 Pod 不會被驅逐。
PreferNoSchedule
PreferNoSchedule
是NoSchedule
的「偏好」或「軟性」版本。控制平面會嘗試避免將不容忍汙染的 Pod 放置在節點上,但這並非保證。
您可以在同一個節點上放置多個汙染,並在同一個 Pod 上放置多個容忍度。Kubernetes 處理多個汙染和容忍度的方式就像一個篩選器:從節點的所有汙染開始,然後忽略 Pod 具有相符容忍度的那些汙染;剩餘未被忽略的汙染會對 Pod 產生指示的效果。特別是,
- 如果至少有一個未被忽略且效果為
NoSchedule
的汙染,則 Kubernetes 將不會將 Pod 排程到該節點上 - 如果沒有未被忽略且效果為
NoSchedule
的汙染,但至少有一個未被忽略且效果為PreferNoSchedule
的汙染,則 Kubernetes 將嘗試不將 Pod 排程到該節點上 - 如果至少有一個未被忽略且效果為
NoExecute
的汙染,則 Pod 將從節點驅逐(如果它已經在節點上執行),並且不會被排程到該節點上(如果它尚未在節點上執行)。
例如,假設您像這樣汙染一個節點
kubectl taint nodes node1 key1=value1:NoSchedule
kubectl taint nodes node1 key1=value1:NoExecute
kubectl taint nodes node1 key2=value2:NoSchedule
以及一個 Pod 具有兩個容忍度
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
在這種情況下,Pod 將無法排程到節點上,因為沒有與第三個汙染相符的容忍度。但是,如果 Pod 在添加汙染時已經在節點上執行,它將能夠繼續執行,因為第三個汙染是三個汙染中唯一一個 Pod 無法容忍的汙染。
通常,如果將效果為 NoExecute
的汙染添加到節點,則任何不容忍該汙染的 Pod 都會立即被驅逐,而容忍該汙染的 Pod 永遠不會被驅逐。但是,效果為 NoExecute
的容忍度可以指定一個可選的 tolerationSeconds
欄位,該欄位規定在添加汙染後,Pod 將在節點上保持綁定的時間長度。例如,
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
tolerationSeconds: 3600
表示如果此 Pod 正在執行,並且將相符的汙染添加到節點,則 Pod 將在節點上保持綁定 3600 秒,然後被驅逐。如果汙染在那段時間之前被移除,則 Pod 將不會被驅逐。
使用案例範例
汙染和容忍度是一種彈性的方式,可以引導 Pod 遠離節點,或驅逐不應執行的 Pod。以下是一些使用案例:
專用節點:如果您想將一組節點專用於特定使用者群組的獨佔使用,您可以將汙染添加到這些節點(例如,
kubectl taint nodes nodename dedicated=groupName:NoSchedule
),然後將對應的容忍度添加到他們的 Pod(這可以透過編寫自訂的准入控制器來最輕鬆地完成)。具有容忍度的 Pod 將被允許使用受汙染(專用)的節點以及叢集中的任何其他節點。如果您想將節點專用於他們並且確保他們僅使用專用節點,那麼您還應該在同一組節點上添加類似於汙染的標籤(例如dedicated=groupName
),並且准入控制器應額外添加節點親和性,以要求 Pod 只能排程到標記為dedicated=groupName
的節點上。具有特殊硬體的節點:在叢集中,一小部分節點具有特殊硬體(例如 GPU),理想情況是讓不需要特殊硬體的 Pod 遠離這些節點,從而為稍後到達且需要特殊硬體的 Pod 騰出空間。這可以透過汙染具有特殊硬體的節點(例如
kubectl taint nodes nodename special=true:NoSchedule
或kubectl taint nodes nodename special=true:PreferNoSchedule
),並將對應的容忍度添加到使用特殊硬體的 Pod 來完成。與專用節點使用案例一樣,最簡單的方式可能是使用自訂的准入控制器來應用容忍度。例如,建議使用延伸資源來表示特殊硬體,使用延伸資源名稱汙染您的特殊硬體節點,並執行 ExtendedResourceToleration 准入控制器。現在,由於節點已被汙染,因此沒有容忍度的 Pod 將不會排程到這些節點上。但是,當您提交請求延伸資源的 Pod 時,ExtendedResourceToleration
准入控制器將自動將正確的容忍度添加到 Pod,並且該 Pod 將排程到特殊硬體節點上。這將確保這些特殊硬體節點專用於請求此類硬體的 Pod,而且您不必手動將容忍度添加到您的 Pod。基於汙染的驅逐:當節點出現問題時,每個 Pod 可配置的驅逐行為,這將在下一節中描述。
基於汙染的驅逐
Kubernetes v1.18 [stable]
當某些條件為真時,節點控制器會自動汙染節點。以下是內建的汙染:
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 會移除此汙染。
如果節點要被排空,節點控制器或 kubelet 會添加具有 NoExecute
效果的相關汙染。預設情況下,node.kubernetes.io/not-ready
和 node.kubernetes.io/unreachable
汙染會添加此效果。如果故障狀況恢復正常,kubelet 或節點控制器可以移除相關的汙染。
在某些情況下,當節點無法連線時,API 伺服器無法與節點上的 kubelet 通訊。在與 API 伺服器的通訊重新建立之前,無法將刪除 Pod 的決定傳達給 kubelet。同時,排程要刪除的 Pod 可能會繼續在分割的節點上執行。
注意
控制平面限制向節點添加新汙染的速率。此速率限制管理在許多節點同時變得無法連線時(例如:如果發生網路中斷)觸發的驅逐數量。您可以為 Pod 指定 tolerationSeconds
,以定義該 Pod 在故障或無回應節點上保持綁定的時間長度。
例如,您可能希望在發生網路分割時,將具有大量本機狀態的應用程式長時間綁定到節點,希望分割能夠恢復,從而避免 Pod 驅逐。您為該 Pod 設定的容忍度可能如下所示
tolerations:
- key: "node.kubernetes.io/unreachable"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 6000
注意
Kubernetes 會自動為 node.kubernetes.io/not-ready
和 node.kubernetes.io/unreachable
添加 tolerationSeconds=300
的容忍度,除非您或控制器明確設定這些容忍度。
這些自動添加的容忍度表示 Pod 在偵測到這些問題之一後,會在節點上保持綁定 5 分鐘。
DaemonSet Pod 是使用針對以下汙染且沒有 tolerationSeconds
的 NoExecute
容忍度建立的
node.kubernetes.io/unreachable
node.kubernetes.io/not-ready
這確保了 DaemonSet Pod 永遠不會因這些問題而被驅逐。
依狀況汙染節點
控制平面使用節點控制器,自動為 節點狀況建立具有 NoSchedule
效果的汙染。
排程器在做出排程決策時會檢查汙染,而不是節點狀況。這確保了節點狀況不會直接影響排程。例如,如果 DiskPressure
節點狀況處於活動狀態,則控制平面會添加 node.kubernetes.io/disk-pressure
汙染,並且不會將新的 Pod 排程到受影響的節點上。如果 MemoryPressure
節點狀況處於活動狀態,則控制平面會添加 node.kubernetes.io/memory-pressure
汙染。
您可以透過添加對應的 Pod 容忍度來忽略新建立 Pod 的節點狀況。控制平面還會在具有非 BestEffort
的QoS 等級的 Pod 上添加 node.kubernetes.io/memory-pressure
容忍度。這是因為 Kubernetes 將 Guaranteed
或 Burstable
QoS 等級中的 Pod(即使是沒有設定記憶體請求的 Pod)視為能夠應對記憶體壓力,而新的 BestEffort
Pod 則不會排程到受影響的節點上。
DaemonSet 控制器會自動將以下 NoSchedule
容忍度添加到所有 daemons,以防止 DaemonSet 崩潰。
node.kubernetes.io/memory-pressure
node.kubernetes.io/disk-pressure
node.kubernetes.io/pid-pressure
(1.14 或更新版本)node.kubernetes.io/unschedulable
(1.10 或更新版本)node.kubernetes.io/network-unavailable
(僅限主機網路)
添加這些容忍度可確保向後相容性。您也可以將任意容忍度添加到 DaemonSet。