污點與容忍度

節點親和性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

如果鍵相同且效果相同,並且

  • operatorExists(在這種情況下不應指定 value),或
  • operatorEqual 且值應相等,則容忍度「符合」污點。

上述範例使用了 NoScheduleeffect。或者,您可以使用 PreferNoScheduleeffect

effect 欄位的允許值為

NoExecute
這會以下列方式影響已在節點上執行的 Pod
  • 不容忍污點的 Pod 會立即被驅逐
  • 在容忍度規格中未指定 tolerationSeconds 的容忍污點的 Pod 將永遠保持繫結
  • 容忍汙染的 Pod 在指定的 tolerationSeconds 期間內保持綁定。經過這段時間後,節點生命週期控制器會將 Pod 從節點驅逐。
NoSchedule
除非新的 Pod 具有相符的容忍度,否則不會將新的 Pod 排程到受汙染的節點上。目前在節點上執行的 Pod 不會被驅逐。
PreferNoSchedule
PreferNoScheduleNoSchedule 的「偏好」或「軟性」版本。控制平面會嘗試避免將不容忍汙染的 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:NoSchedulekubectl 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-readynode.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

DaemonSet Pod 是使用針對以下汙染且沒有 tolerationSecondsNoExecute 容忍度建立的

  • 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 的節點狀況。控制平面還會在具有非 BestEffortQoS 等級的 Pod 上添加 node.kubernetes.io/memory-pressure 容忍度。這是因為 Kubernetes 將 GuaranteedBurstable 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。

下一步

上次修改時間:2024 年 9 月 15 日 凌晨 12:23 PST:修正關於空容忍度金鑰的錯誤資訊 (#47929) (dd46be9118)