Appearance
Kubernetes Pod Anti-Affinity 與 Deployment 策略
利用 Pod 反親和性確保服務副本分散到不同節點,搭配 Recreate 策略解決 ReadWriteOnce PVC 的滾動更新衝突。
概述
Kubernetes 的預設排程器著重資源均衡,但不保證將同一 Deployment 的多個副本分散到不同節點。若多個副本集中在同一節點,節點故障時服務會整體中斷,不符合高可用性要求。
Pod Anti-Affinity(Pod 反親和性)讓你能明確指示排程器「這些 Pod 必須分散到不同拓撲域(通常是不同節點)」,是 Kubernetes 高可用部署的核心排程技術之一。
此外,對於使用 ReadWriteOnce PVC 的 Deployment,預設的 RollingUpdate 策略會因為新舊 Pod 同時嘗試掛載同一 Volume 而卡住——需要改用 Recreate 策略來規避此衝突。
核心內容
Pod Anti-Affinity 設定結構
Anti-Affinity 設定加在 Pod template spec 的 affinity.podAntiAffinity 欄位,有兩個關鍵子欄位:
labelSelector: 指定「哪些 Pod 不能與我同節點」,通常設為與自己相同的 label。例如 app: squid 表示「不要把我排程到已有 app=squid Pod 的節點上」。
topologyKey: 指定節點的分組方式。最常用 kubernetes.io/hostname(以主機名稱為界,每個節點各自獨立)。若需要跨可用區分散,可改用 topology.kubernetes.io/zone。
硬性限制 vs. 軟性限制
| 類型 | 欄位名稱 | 行為 |
|---|---|---|
| 硬性限制 | requiredDuringSchedulingIgnoredDuringExecution | 嚴格執行。若可用節點數少於副本數,多餘的 Pod 會卡在 Pending 狀態,直到有新節點加入為止 |
| 軟性限制 | preferredDuringSchedulingIgnoredDuringExecution | 盡力分散,但節點不足時允許多個 Pod 共用同一節點,不阻擋排程 |
選擇依據:
- 對高可用性要求嚴格的基礎設施服務(Proxy、Ingress Controller)→ 硬性限制,但需確保叢集節點數 ≥ 副本數
- 有彈性擴縮需求、副本數可能超過節點數的應用 → 軟性限制
Deployment Strategy:ReadWriteOnce PVC 衝突
Kubernetes 的 RollingUpdate 策略(預設)會先啟動新 Pod,再終止舊 Pod。若 Pod 使用 ReadWriteOnce PVC,同一時間只允許一個 Pod 掛載,新 Pod 嘗試掛載時因舊 Pod 仍在使用中而失敗,整個更新就會卡住。
解決方案是改用 Recreate 策略:先終止所有舊 Pod(PVC 釋放),再啟動新 Pod:
yaml
spec:
strategy:
type: Recreate代價是更新期間服務有短暫中斷(downtime)。對需要零中斷的服務,應考慮改用 ReadWriteMany StorageClass,或架構層面改為無狀態設計。
關鍵要點
topologyKey: "kubernetes.io/hostname"是跨節點分散的標準設定- 硬性限制需確保叢集節點數 ≥ 副本數,否則 Pod 會 Pending
ReadWriteOncePVC +RollingUpdate策略 = 滾動更新卡住,必須改RecreateRecreate策略有短暫停機,零中斷需求應選ReadWriteMany或無狀態架構
實際應用
在部署 Squid Proxy 等需要高可用性的代理服務時,設定 3 個副本搭配硬性 Anti-Affinity,確保每個節點各執行一個 Squid Pod。即使某節點故障,其餘節點上的副本仍正常服務,系統可用性從 0/1(單點故障)提升至 2/3(可容一個節點故障)。
ReadWriteOnce PVC 的問題常出現在帶有持久化儲存的單一副本服務(如日誌收集器、小型資料庫 Sidecar),部署時務必留意更新策略。
部署設定參考
以下為完整的 YAML 設定,供日後查詢與複製使用。
Deployment 完整 YAML(含硬性 Pod Anti-Affinity)
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: squid-deployment
namespace: ingress-basic
spec:
replicas: 3
selector:
matchLabels:
app: squid
template:
metadata:
labels:
app: squid
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- squid
topologyKey: "kubernetes.io/hostname"
containers:
- name: squid
image: ubuntu/squid:edge
ports:
- containerPort: 3128
name: squid
protocol: TCPDeployment Strategy(ReadWriteOnce PVC)
yaml
spec:
strategy:
type: Recreate相關概念
- Squid Proxy(Kubernetes 部署) — Pod Anti-Affinity 的實際應用案例:三副本跨節點分散
- Kubernetes HPA 水平自動擴縮 — HPA 調整副本數時,Anti-Affinity 確保新副本分散到不同節點
- KEDA(Kubernetes Event-Driven Autoscaling) — 事件驅動自動擴縮,同樣可搭配 Anti-Affinity 提升可用性
- Kubernetes VolumeSnapshot 磁碟快照 — 同樣涉及 PVC 管理,ReadWriteOnce 限制在兩篇文章均有討論
- Kubernetes 維運技巧速查 — 日常維運速查手冊,含 PVC 相關操作