昨天我們學了 Pod Affinity 與 Anti-Affinity,用來控制 Pod 之間的排程關係。
其中 Pod Anti-Affinity 可以讓副本分散到不同 Node,但如果我們想進一步控制「分散得多均勻」,就需要更細緻的機制。
例如:
required 太嚴格,可能導致 Pod Pending
preferred 只是偏好,無法保證分散程度這時候就可以使用 Topology Spread Constraints。
topologySpreadConstraints 在 Kubernetes v1.19 正式 GA,可以控制 Pod 在不同 Node、Zone 等拓樸範圍之間的分布差距。
今天我們會學:
maxSkew、topologyKey、whenUnsatisfiable
minDomains、nodeAffinityPolicy、nodeTaintsPolicy
以下操作皆在 master 節點 執行。
topologySpreadConstraints 的核心概念是:限制 Pod 在不同拓樸域之間可以相差多少,讓 Scheduler 在排程時盡量維持較平均的分布。
| 欄位 | 說明 | 範例 |
|---|---|---|
maxSkew |
允許的最大分布差距 | 1 = 各拓樸域之間盡量不要差超過 1 個 Pod |
topologyKey |
定義拓樸域的範圍 | kubernetes.io/hostname |
whenUnsatisfiable |
無法滿足分散條件時要怎麼處理 | DoNotSchedule(硬性)/ ScheduleAnyway(軟性) |
labelSelector |
指定哪些 Pod 要一起計算分布 | app: web |
想像你在發撲克牌:
skew 可以先簡單理解成:
表示 Pod 在不同 Node(或 Zone)之間分布得有多不平均。
例如有 3 台 Node,目前 Pod 分布為:
Node-1:3 個
Node-2:2 個
Node-3:1 個
以最少的 Node-3 為基準,可以理解成:
如果設定:
maxSkew: 1
代表 Scheduler 會限制 Pod 分布不要過度失衡。
因此下一個 Pod 不會繼續排到已經很多 Pod 的 Node-1,而會優先考慮能讓整體分布維持在 maxSkew 限制內的 Node。
vim web-tsc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-tsc
spec:
replicas: 4
selector:
matchLabels:
app: web-tsc
template:
metadata:
labels:
app: web-tsc
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: web-tsc
containers:
- name: nginx
image: nginx
kubectl apply -f web-tsc.yaml
💡 解讀這段 YAML
「把所有
app=web-tsc的 Pod 分散到不同 Node 上,並盡量維持平均分布。」因為設定了
maxSkew: 1,代表各 Node 上符合條件的 Pod 數量差距最多允許相差 1 個。如果新的 Pod 會讓分布超過這個限制,
whenUnsatisfiable: DoNotSchedule會阻止它被排程。
kubectl get pods -l app=web-tsc -o wide
觀察 Pod 的分布結果:

因為設定了 maxSkew: 1,所以各 Node 之間符合條件的 Pod 數量差距最多只能相差 1 個。
如果不希望 Pod 因為無法完全符合分散條件而停留在 Pending,可以把:
vim web-tsc-soft.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-tsc-soft
spec:
replicas: 4
selector:
matchLabels:
app: web-tsc-soft
template:
metadata:
labels:
app: web-tsc-soft
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: web-tsc-soft
containers:
- name: nginx
image: nginx
kubectl apply -f web-tsc-soft.yaml
kubectl get pods -l app=web-tsc-soft -o wide
這次即使 Pod 的分布暫時不夠平均,也不會因此停留在 Pending。

ScheduleAnyway 代表 Scheduler 會盡量讓 Pod 分布得更均勻,但不會把它當成硬性限制。
除了基本的 maxSkew、topologyKey、whenUnsatisfiable 之外,topologySpreadConstraints 還提供一些更進階的控制欄位:
| 欄位 | 說明 |
|---|---|
minDomains |
指定至少要有多少個「分散範圍」參與計算,例如幾台 Node 或幾個 Zone |
nodeAffinityPolicy |
決定計算分布時,是否只考慮符合 Pod nodeAffinity / nodeSelector 的 Node |
nodeTaintsPolicy |
決定計算分布時,是否考慮 Node 的 Taint 與 Pod 的 Toleration |
matchLabelKeys |
從 Pod 自己的 Label 取得值,進一步決定哪些 Pod 要一起計算分布 |
這些欄位主要用在更複雜的排程情境,現階段先知道它們的用途即可。
minDomains的實用場景假設我們使用:
topologyKey: kubernetes.io/hostname maxSkew: 1 minDomains: 3因為
topologyKey是kubernetes.io/hostname,所以這裡可以直接把minDomains: 3理解成:希望至少有 3 台符合條件的 Node 參與 Pod 的分散。
如果目前實際只有 1 台符合條件的 Node,Scheduler 在計算分布時會把最低基準視為
0。當這台 Node 上的 Pod 數量繼續增加,就可能超過
maxSkew: 1,使新的 Pod 無法再被排程。這可以避免 Pod 在可用 Node 太少時,持續全部集中到同一台 Node。
在雲端環境中,叢集可能同時跨越多個 Zone,而且每個 Zone 裡又有多台 Node。
這時候可能同時有兩個需求:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-multi-tsc
spec:
replicas: 6
selector:
matchLabels:
app: web-multi-tsc
template:
metadata:
labels:
app: web-multi-tsc
spec:
topologySpreadConstraints:
# 條件 1:跨 Zone 均勻分散
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: web-multi-tsc
# 條件 2:跨 Node 均勻分散
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: web-multi-tsc
containers:
- name: nginx
image: nginx
💡 解讀這段 YAML
- 跨 Zone:使用
DoNotSchedule,把 Zone 之間的分散當成硬性限制- 跨 Node:使用
ScheduleAnyway,讓 Scheduler 盡量把 Pod 分散到不同 Node,但不強制這樣可以優先確保 Pod 不會過度集中在同一個 Zone,同時也盡量讓同一個 Zone 內的 Pod 分散到不同 Node。
練習環境注意
在一般的 kubeadm 練習環境中,通常不會特別設定多個 Zone,Node 也可能沒有
topology.kubernetes.io/zoneLabel。因此這類跨 Zone 的分散策略,在具有多個 Zone 的叢集環境中會比較容易觀察到效果。
| 比較項目 | Pod Anti-Affinity | topologySpreadConstraints |
|---|---|---|
| 主要目標 | 讓 Pod 避開符合條件的其他 Pod | 讓 Pod 在不同 Node、Zone 等範圍中均勻分布 |
| 控制方式 | 控制「要不要跟其他 Pod 在同一個範圍」 | 透過 maxSkew 控制允許的分布差距 |
| 硬性 / 軟性 | required / preferred |
DoNotSchedule / ScheduleAnyway |
| 大型叢集 | Pod Anti-Affinity 的排程計算成本較高 | 更適合表達大量副本的均勻分散需求 |
| 多條件組合 | 可以設定多條規則 | 可以設定多個 topologySpreadConstraints |
| 適用場景 | Pod 之間需要明確避開彼此 | 需要控制副本在 Node / Zone 之間的分布均勻度 |
實務上怎麼選?
- 如果需求是「這兩個 Pod 不要在一起」→ 使用 Pod Anti-Affinity
- 如果需求是「這些副本要盡量平均分散」→ 使用 topologySpreadConstraints
- 兩者也可以搭配其他排程機制一起使用,例如用 Pod Affinity 讓 Web 靠近 Cache,再用 topologySpreadConstraints 讓 Web 副本跨 Zone 分散
今天我們學了 Kubernetes 用來控制 Pod 均勻分散的機制 —— topologySpreadConstraints:
| 重點 | 說明 |
|---|---|
| maxSkew | 控制不同 Node 或 Zone 之間,Pod 數量允許相差多少 |
| topologyKey | 定義 Pod 的分散範圍,例如 hostname / zone / region |
| whenUnsatisfiable | DoNotSchedule(硬性)vs ScheduleAnyway(軟性) |
| 多條件組合 | 可以同時控制跨 Zone 與跨 Node 的分布 |
| vs Anti-Affinity | Anti-Affinity 著重 Pod 彼此避開;topologySpreadConstraints 著重副本均勻分散 |
到這裡,我們已經掌握了 Kubernetes 排程的主要控制機制。
但如果叢集資源不足,哪些 Pod 應該優先被排程?哪些 Pod 可以讓出資源?
明天我們來看看 PriorityClass 與 Preemption,了解 Kubernetes 如何透過 Pod 優先級與搶佔機制,在資源不足時決定誰先執行、誰需要讓出位置!