寫這篇想要分享的重點:
在 Kubernetes 叢集中,如何控制 Pod 的調度行為?本篇將深入剖析 Taints/Tolerations(污點與容忍)與 Node Affinity(節點親和性)的運作邏輯,並分享如何結合兩者,將特定的Pod綁定至指定硬體規格的節點。這篇想要講什麼:
- Taints 與 Tolerations 的三個效果 (NoSchedule, PreferNoSchedule, NoExecute) 與運作方式。
- Node Affinity 的匹配運算子 (In, NotIn, Exists) 與兩個階段類型 (requiredDuringScheduling..., preferredDuringScheduling...)。
- 實戰:為什麼單靠 Taints 或 Node Affinity 無法達到完全的「專屬節點隔離」?如何兩者配合做到雙向排他與綁定?
為何要寫這篇:
在設定調度規則時,常搞混「驅逐」與「吸引」的概念,導致 Pod 被派發到不適合的機器,或是無法成功綁定 GPU/高算力節點。掌握這套排他與吸引機制,是建構高可用與高效能叢集的基礎技能。
Taints(污點)是作用在 Node 上的標記,用來「拒絕」不符合條件的 Pod 排入;而 Tolerations(容忍度)則是設定在 Pod 上的屬性,代表該 Pod 可以「容忍」Node 上的特定污點。
簡單比喻:Taint 就像是驅蟲劑,預設會把所有 Pod 驅離;只有身上帶有對應 Toleration 護身符的 Pod,才能順利停靠。
NoSchedule:如果 Pod 沒有對應的 Toleration,調度器絕對不會將 Pod 調度到該 Node 上。但已存在於該 Node 上的 Pod 不受影響。PreferNoSchedule:軟限制。調度器會儘量避免將 Pod 調度到該 Node,但若全叢集無其他可用資源,仍可能勉強調度過去。NoExecute:強烈限制。不僅新 Pod 無法調度上去,若 Node 上已運行的 Pod 沒有對應 Toleration,會立即被踢出 (Evicted)!在 Node 上設定 Taint:
kubectl taint nodes node-gpu hardware=nvidia-a100:NoSchedule
在 Pod 的 spec 中設定 Toleration:
apiVersion: v1
kind: Pod
metadata:
name: gpu-training-job
spec:
containers:
- name: cuda-test
image: nvidia/cuda:11.0-base
tolerations:
- key: "hardware"
operator: "Equal"
value: "nvidia-a100"
effect: "NoSchedule"
與 Taints 這種「排他」邏輯不同,Node Affinity(節點親和性)是以「吸引」的方式,根據 Node 上的 Labels(標籤)來選擇 Pod 要投遞的目标 Node。
requiredDuringSchedulingIgnoredDuringExecution (硬要求):
Pending 狀態。preferredDuringSchedulingIgnoredDuringExecution (軟要求):
💡 區別法,重點在第一個單字:
required... $\rightarrow$ 「必須/硬要求」口訣:非他不可。沒找到合適的 Node,就不調度(Pending)。preferred... $\rightarrow$ 「偏好/軟要求」口訣:有他更好。有 match 的 Node 最好,沒有也隨便啦,能跑就行。apiVersion: v1
kind: Pod
metadata:
name: backend-service
spec:
affinity:
nodeAffinity: # <-- 1. 啟用 Node 條件篩選 (開關)
requiredDuringSchedulingIgnoredDuringExecution: # <-- 2. 硬要求:不符就 Pending
nodeSelectorTerms: # <-- 3. 條件組清單 [組間為 OR 邏輯:滿足任一組即可]
- matchExpressions: # <-- 4. 表達式清單 [組內為 AND 邏輯:必須同時滿足]
- key: instance-type
operator: In # <-- 5. 運算子:In / NotIn / Exists / DoesNotExist / Gt / Lt
values:
- high-memory
- compute-optimized
containers:
- name: app
image: nginx
matchExpressions 運算子(Operators)範例Kubernetes 的 matchExpressions 支援以下 6 種運算子:
In(包含於清單中)values 清單中的任意一個。key: instance-type
operator: In
values:
- high-memory
- compute-optimized
instance-type=high-memory 或者 instance-type=compute-optimized。NotIn(不包含於清單中)values 清單中的任何一個。常用於避開特定節點(例如老舊機器或測試機)。key: environment
operator: NotIn
values:
- testing
- staging
environment=testing 或 environment=staging 的 Node 上。Exists(鍵存在即可)key 標籤即可,不在乎 Value 是什麼。Exists 或 DoesNotExist 時,不能寫 values 欄位(否則 YAML 會報錯)。key: gpu-attached
operator: Exists
gpu-attached 這個 Key(例如 gpu-attached=true 或 gpu-attached=nvidia-t4),都符合條件。DoesNotExist(鍵不存在)key 標籤。key: maintenance-mode
operator: DoesNotExist
maintenance-mode 標籤)的 Node。Gt (Greater Than) 與 Lt (Less Than)values 欄位只能包含一個字串格式的數字。key: cpu-cores
operator: Gt
values:
- "8"
| 運算子 | values 欄位 |
邏輯意義 | 常見場景 |
|---|---|---|---|
In |
必須提供(可多個) | $\text{Key} \in {\text{Val}_1, \text{Val}_2}$ | 限定特定機型(high-memory)、地區(us-east-1a)。 |
NotIn |
必須提供(可多個) | $\text{Key} \notin {\text{Val}_1, \text{Val}_2}$ | 排除故障節點、避開搶佔式實例(Spot Instance)。 |
Exists |
不可提供 | 標籤 Key 存在即可 | 尋找有特殊硬體(如 GPU/SSD)的機器。 |
DoesNotExist |
不可提供 | 標籤 Key 不可存在 | 避開被打上特定標籤(如維護中、隔離中)的機器。 |
Gt / Lt |
必須提供(限 1 個數字) | 數值比大小 | 依據節點自訂的性能分數或規格進行門檻篩選。 |
常見問題:「如果我有一批帶有 GPU 的超強節點,只希望 AI 訓練 Pod 部署上去,且一般服務絕對不能佔用他,要怎麼設定?」
對專用節點上記號 (Taint + Label):
# 上 Taint 阻擋一般 Pod
kubectl taint nodes node-gpu dedicated=ai-workload:NoSchedule
# 上 Label 提供 Affinity 識別
kubectl label nodes node-gpu dedicated=ai-workload
在專用 Pod 上設定雙向配置 (Toleration + NodeAffinity):
apiVersion: v1
kind: Pod
metadata:
name: deep-learning-pod
spec:
# 1. 允許進入帶有污點的專用 Node
tolerations:
- key: "dedicated"
operator: "Equal"
value: "ai-workload"
effect: "NoSchedule"
# 2. 強制指定一定要進入帶有此 Label 的 Node
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: dedicated
operator: In
values:
- ai-workload
containers:
- name: trainer
image: tensorflow/tensorflow:latest-gpu
透過雙向設定:
NoSchedule 阻擋新 Pod 進駐;PreferNoSchedule 盡量避免但不強制;NoExecute 則會強制驅逐(Evict)現有未設定容忍度的 Pod。requiredDuringScheduling... 是硬要求,配對失敗會導致 Pending;preferredDuringScheduling... 是軟要求,找不到目標會退而求其次調度。