iT邦幫忙

2026 iThome 鐵人賽

DAY 14
0
Kubernetes

從零到 CKA:30 天掌握 Kubernetes 核心觀念與實作系列 第 14

Day 14|Pod Affinity 與 Anti-Affinity — 控制 Pod 之間的排程關係

  • 分享至 

  • xImage
  •  

前言

昨天我們學了 Node AffinityTaints & Tolerations —— 一個是 Pod 選 Node,一個是 Node 限制 Pod,但它們處理的都是「Pod 跟 Node 的關係」。

在真實環境中,我們常常還需要控制「Pod 跟 Pod 的關係」。

例如:

  • Web Server 跟 Redis Cache 希望排在同一台 Node —— 減少彼此通訊的網路延遲
  • 同一個服務的多個副本希望分散到不同 Node —— 避免單一 Node 故障時,所有副本一起受到影響

這類需求就不是 Node Affinity 或 Taints & Tolerations 主要解決的問題,而是要靠 Pod AffinityPod Anti-Affinity

今天我們會學:

  1. Pod Affinity — 「我要跟你在一起」
  2. Pod Anti-Affinity — 「我們不要在一起」
  3. 實戰應用 — Web + Cache 靠近部署,並讓副本分散
  4. 排程機制對照 — Node Affinity / Taints & Tolerations / Pod Affinity 完整比較

以下操作皆在 master 節點 執行。


一、Pod Affinity — 「我要跟你在一起」

用比喻理解

想像大學選宿舍:

  • Node Affinity:「我要住有冷氣的宿舍」→ 看的是 Node 本身的條件
  • Pod Affinity:「我要跟我的好朋友住同一棟」→ 看的是 其他 Pod 已經在哪裡

Pod Affinity 讓你表達:

「如果符合條件的 Pod 已經在某個位置,那我也希望被排到相同的範圍內。」

這個「相同範圍」可以是同一台 Node,也可以是同一個 Zone,實際範圍會由後面要介紹的 topologyKey 決定。

核心概念:topologyKey

Pod Affinity 有一個 Node Affinity 沒有的關鍵欄位 —— topologyKey

它用來定義「在一起」或「分開」的範圍。

Kubernetes 會查看 Node 上對應的 Label,並根據 Label 的值判斷哪些 Node 屬於同一個拓樸範圍。

topologyKey 意思 常見用途
kubernetes.io/hostname 同一台 Node 控制 Pod 是否要在同一台主機
topology.kubernetes.io/zone 同一個 Zone 控制 Pod 是否要在同一個可用區
topology.kubernetes.io/region 同一個 Region 控制 Pod 是否要在同一個較大區域

兩種模式

跟 Node Affinity 一樣,Pod Affinity 也有 requiredpreferred 兩種模式:

模式 行為 類比
requiredDuringSchedulingIgnoredDuringExecution 硬性條件:排程時一定要符合,找不到符合條件的位置就會 Pending 「一定要跟好朋友住同一棟,否則我不住」
preferredDuringSchedulingIgnoredDuringExecution 偏好條件:排程時會盡量滿足,但不是強制要求 「優先跟好朋友住同一棟,沒辦法也可以接受」

實作:Web Pod 跟著 Cache Pod 走

Step 1:先部署一個 Cache Pod(被跟隨的目標)

vim cache-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: cache
  labels:
    app: cache        # 這個標籤是 Pod Affinity 的匹配依據
spec:
  containers:
  - name: redis
    image: redis:7
kubectl apply -f cache-pod.yaml

確認 Cache Pod 跑在哪個 Node:

kubectl get pod cache -o wide

https://ithelp.ithome.com.tw/upload/images/20260816/20181928Jtzi7RHy2M.png

Step 2:建立 Web Pod,用 Pod Affinity 跟 Cache 排在一起

vim web-with-affinity.yaml
apiVersion: v1
kind: Pod
metadata:
  name: web
  labels:
    app: web
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - cache
        topologyKey: kubernetes.io/hostname
  containers:
  - name: nginx
    image: nginx

💡 解讀這段 YAML

「找到標籤符合 app=cache 的 Pod,並把Web Pod排到與它相同的Node。」

因為這裡設定:

topologyKey: kubernetes.io/hostname
kubectl apply -f web-with-affinity.yaml
kubectl get pods cache web -o wide

Web Pod 應該會跟 Cache Pod 排在同一台 Node 上!

https://ithelp.ithome.com.tw/upload/images/20260816/20181928bQ3OkCpBYF.png

Step 3:驗證 — 如果 Cache Pod 不存在會怎樣?

kubectl delete pod cache web

先不建立 Cache Pod,直接部署 Web Pod:

kubectl apply -f web-with-affinity.yaml
kubectl get pod web

Web Pod 會一直 Pending!因為找不到任何 Node 上有 app=cache 的 Pod。

https://ithelp.ithome.com.tw/upload/images/20260816/20181928q6y0PzMXXZ.png

describe 確認原因:

kubectl describe pod web | grep -A 5 Events

https://ithelp.ithome.com.tw/upload/images/20260816/201819284ruStYD26N.png

會看到類似 didn't match pod affinity rules 的訊息 — 這就是 required 的硬性約束。


二、Pod Anti-Affinity — 「我們不要在一起」

用比喻理解

如果 Pod Affinity 是「我要跟好朋友住同一棟」,那 Pod Anti-Affinity 就像「考試座位要分開」—— 同一科考試的學生盡量不要坐在一起,降低彼此互相影響的風險。

在 Kubernetes 中,Pod Anti-Affinity 很常用來讓同一個應用程式的多個副本分散到不同 Node

例如一個 Deployment 有 3 個副本,如果它們全部被排到同一台 Node,一旦這台 Node 發生故障,3 個副本可能會同時受到影響。

透過 Pod Anti-Affinity,可以讓這些 Pod 分散到不同 Node,降低單一 Node 故障造成的影響。

實作:讓副本分散到不同 Node

Step 1:建立帶有 Anti-Affinity 的 Deployment

vim web-spread.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-spread
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-spread
  template:
    metadata:
      labels:
        app: web-spread
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - web-spread
            topologyKey: kubernetes.io/hostname
      containers:
      - name: nginx
        image: nginx
kubectl apply -f web-spread.yaml

💡 解讀這段 YAML

「我是 app=web-spread 的 Pod,不要把我排到已經有其他 app=web-spread Pod 的 Node 上。」

因為這裡使用:

topologyKey: kubernetes.io/hostname

所以 Anti-Affinity 會以「同一台 Node」作為判斷範圍。

又因為使用的是 requiredDuringSchedulingIgnoredDuringExecution,因此只要某台 Node 上已經有符合 app=web-spread 的 Pod,其他符合相同條件的 Pod 就不能再被排到同一台 Node。

Step 2:觀察行為

kubectl get pods -l app=web-spread

如果你的叢集只有 2 個 worker Node,但 Deployment 設定 replicas: 3

  • 前 2 個 Pod 會分別排到 2 台不同的 Node → Running
  • 第 3 個 Pod 找不到符合 Anti-Affinity 條件的 Node → Pending

原因是每台 Node 上都已經有一個 app=web-spread Pod,而 requiredDuringSchedulingIgnoredDuringExecution 不允許另一個符合相同條件的 Pod 再排到同一台 Node。

https://ithelp.ithome.com.tw/upload/images/20260816/20181928tNAfDHMYr9.png

這正是 required Anti-Affinity 的硬性約束 —— 寧可讓 Pod 停留在 Pending,也不會違反既定的排程規則。

Step 3:改用 preferred 讓排程更有彈性

如果你希望「盡量分散,但真的沒有其他選擇時,排在一起也可以」,就可以改用 preferred

vim web-spread-preferred.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-spread-soft
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-spread-soft
  template:
    metadata:
      labels:
        app: web-spread-soft
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - web-spread-soft
              topologyKey: kubernetes.io/hostname
      containers:
      - name: nginx
        image: nginx
kubectl delete deployment web-spread
kubectl apply -f web-spread-preferred.yaml
kubectl get pods -o wide -l app=web-spread-soft

這次 3 個 Pod 都可以進入 Running

即使叢集只有 2 台 Node,第 3 個 Pod 仍然可以被排程,只是 Scheduler 會盡量避免把它和其他 app=web-spread Pod 放在同一台 Node。

這就是 preferred Anti-Affinity 的特性:優先分散,但不會因為無法完全滿足條件而讓 Pod 停留在 Pending

https://ithelp.ithome.com.tw/upload/images/20260816/20181928qEssFKZMph.png


三、實戰組合應用:Web + Cache 同節點 & 副本分散

需求

假設有一個 Web 應用程式和 Cache 服務,希望達成兩個排程目標:

  • Web Pod 和 Cache Pod 盡量排在同一台 Node,減少彼此通訊的網路延遲
  • 多個 Web Pod 盡量分散到不同 Node,避免單一 Node 故障時影響所有副本

解法:同時使用 Pod Affinity + Pod Anti-Affinity

這兩個需求可以透過不同的規則搭配完成:

  • Pod Affinity:讓 Web Pod 靠近 app=cache 的 Pod
  • Pod Anti-Affinity:讓多個 app=web Pod 盡量分散到不同 Node

也就是:

Web 靠近 Cache,但 Web 彼此盡量分開。

接下來我們一步一步完成這個配置。

Step 1:部署 Cache Pod

kubectl apply -f cache-pod.yaml
kubectl get pod cache -o wide

https://ithelp.ithome.com.tw/upload/images/20260816/20181928eV50NHvbl4.png

Step 2:部署 Web Deployment,同時設定 Affinity 和 Anti-Affinity

vim web-combo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-combo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web-combo
  template:
    metadata:
      labels:
        app: web-combo
    spec:
      affinity:
        # Pod Affinity:跟 Cache 排在一起
        podAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 80
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - cache
              topologyKey: kubernetes.io/hostname
        # Pod Anti-Affinity:副本盡量分散
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 50
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - web-combo
              topologyKey: kubernetes.io/hostname
      containers:
      - name: nginx
        image: nginx
kubectl apply -f web-combo.yaml
kubectl get pods -l 'app in (web-combo, cache)' -o wide

https://ithelp.ithome.com.tw/upload/images/20260816/20181928No9cCDduuu.png

為什麼這裡用 preferred?

因為兩個規則可能互相衝突:

  • Affinity:希望 Web 靠近 Cache
  • Anti-Affinity:希望 Web 副本彼此分散

如果都用 required,可能找不到同時符合條件的 Node,導致 Pod Pending

改用 preferred 後,Scheduler 會依照 weight 綜合評分,選擇較適合的 Node。


五、排程機制對照

經過 Day 12 到 Day 14,我們已經學了 Kubernetes 核心的排程控制機制,最後來做一個完整對照:

比較項目 nodeSelector Node Affinity Taints & Tolerations Pod Affinity / Anti-Affinity
控制什麼? Pod → Node Pod → Node Node → Pod Pod → Pod
方向 選擇 選擇 / 偏好 限制 靠近(Affinity)/ 分散(Anti-Affinity)
條件類型 硬性 required / preferred NoSchedule / PreferNoSchedule / NoExecute required / preferred
匹配依據 Node Label Node Label Node Taint + Pod Toleration Pod Label + topologyKey
有 topologyKey? ,用來定義拓樸範圍
典型場景 簡單指定 Node GPU、SSD 等 Node 條件 專用 Node、隔離工作負載 Pod 共置 / 分散部署

💡 總結

  • nodeSelector / Node Affinity:Pod 的「志願表」—— 我想去哪個 Node
  • Taints & Tolerations:Node 的「門禁系統」—— 哪些 Pod 可以進來
  • Pod Affinity:Pod 的「組隊偏好」—— 我想跟誰靠近
  • Pod Anti-Affinity:Pod 的「迴避清單」—— 我想跟誰分開

小結

今天我們學會了控制 Pod 之間排程關係的機制:

重點 說明
Pod Affinity 讓 Pod 靠近符合條件的其他 Pod
Pod Anti-Affinity 讓 Pod 與符合條件的其他 Pod 分散部署
topologyKey 定義「靠近」或「分散」的範圍,例如 hostname / zone / region
required vs preferred required 是硬性條件;preferred 是偏好條件
組合應用 Affinity + Anti-Affinity 搭配 weight,讓 Scheduler 綜合不同排程偏好

到這裡,我們已經掌握了 Pod 之間的排程控制。

Pod Anti-Affinity 可以讓副本彼此分散,但如果我們希望 Pod 能夠在不同 Node 或 Zone 之間更均勻地分布,就需要另一個更適合的機制。

明天我們來學 Topology Spread Constraints(topologySpreadConstraints,看看 Kubernetes 如何更精確地控制 Pod 的分散程度!


參考資源


上一篇
Day 13|Node Affinity 與 Taints & Tolerations — 精準控制 Pod 的排程位置
下一篇
Day 15|topologySpreadConstraints — 更優雅的 Pod 分散機制
系列文
從零到 CKA:30 天掌握 Kubernetes 核心觀念與實作17
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言