90% 的 K8s 故障都和調度有關:五種 Pod 調度策略你必須會
今天分享一下五種Pod調度策略,企業中很多問題可能都跟Pod的調度策略有關,需要你了解Pod每種調度策略的原理和使用方式。篇幅較長,可以先收藏!
Pod 的調度策略主要有:
- nodeSelector
- 親和性與反親和性
- nodeName
- Pod 拓撲分布約束
- 污點與容忍性

一、Pod調度概述
調度器通過 Kubernetes 的監測(Watch)機制來發現集群中新創建且尚未被調度到節點上的 Pod。調度的主要任務是將Pod分配到集群中的合適的節點上。調度器根據Pod的需求(如CPU、內存、存儲等)和節點的資源狀況(如可用CPU、內存、節點標簽等)來決定Pod部署在哪個節點上。
二、五種調度策略詳解
1. nodeSelector
nodeSelector 是 Kubernetes 中最簡單、最直觀的調度機制,它基于節點標簽進行 Pod 調度。節點標簽是 Kubernetes 用于標識節點屬性的鍵值對,調度器會根據這些標簽來決定將 Pod 調度到哪個節點。
(1) 工作原理:
- 每個 Kubernetes 節點可以具有多個標簽(labels)。標簽是 key: value 的形式,通常表示節點的特征,如硬件類型、地區、環境等。
- Pod 的 nodeSelector 字段指定一組標簽,調度器會篩選出具有這些標簽的節點,然后將 Pod 調度到這些節點。
(2) 使用場景:
- 環境隔離:比如,你有一些節點專門用于生產環境,其他節點用于測試環境,使用 nodeSelector 來確保 Pod 只在生產節點上運行。
- 硬件要求:例如,某些應用需要 SSD 磁盤或特定的 CPU 類型,你可以使用 nodeSelector 來確保 Pod 調度到符合這些硬件要求的節點。
(3) 實戰操作:
① 給節點打上標簽
# 給k8s-node2節點打上ssd標簽
kubectl label node k8s-node2 disktype=ssd
# 查看
kubectl get node k8s-node1 --show-labels② 編寫pod的yaml文件
【溫馨提示】生產環境不要直接運行pod,這里只是為了演示效果
vim nodeSelector_pod.yamlapiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
nodeSelector:
disktype: ssd
containers:
- name: nginx
image: docker.m.daocloud.io/nginx:1.25運行pod:
kubectl apply -f nodeSelector_pod.yaml③ 查看pod調度情況
[root@k8s-master data]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 60s 10.224.169.149 k8s-node2 <none> <none>已經根據節點標簽將pod調度到node2節點。
(4) nodeSelector的優缺點:
- 優點:簡單高效。
- 缺點:靈活性差,無法處理復雜的調度需求。
2. 親和性與反親和性
親和性(Affinity)和反親和性(Anti-Affinity)是比 nodeSelector 更強大、更靈活的調度策略。它們允許用戶根據更多的條件進行節點選擇,比如節點的標簽、Pod 的存在與否等。
親和性(Affinity)用于指定 Pod 需要盡量調度到某些節點上,基于節點標簽、Pod 與節點的關系等。 反親和性(Anti-Affinity)用于指定 Pod 不應該調度到某些節點,或者應該盡量避免和其他 Pod 調度到同一個節點上。
Kubernetes 中有兩種親和性:
- 節點親和性(Node Affinity)
- Pod 親和性與反親和性(Pod Affinity & Anti-Affinity)。
(1) 節點親和性(Node Affinity)
實戰操作:
① 編寫yaml文件
vim nodeAffinity.yamlapiVersion: v1
kind: Pod
metadata:
name: nginx2
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx2
image: docker.m.daocloud.io/nginx:1.25確保 Pod 只會調度到具有 disktype=ssd標簽的節點。
② 運行pod
kubectl apply -f nodeAffinity.yaml③ 查看pod調度情況
[root@k8s-master data]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 27m 10.224.169.149 k8s-node2 <none> <none>
nginx2 1/1 Running 0 3m16s 10.224.169.154 k8s-node2 <none> <none>已經將pod調度到預期的node上。
字段解釋:
- nodeAffinity 是定義節點選擇規則的字段。通過 requiredDuringSchedulingIgnoredDuringExecution(必須滿足調度時條件)和 preferredDuringSchedulingIgnoredDuringExecution(調度時首選,但不強制)來定義硬性和軟性約束。
- matchExpressions 支持使用 In、NotIn、Exists 等操作符,這些操作符使得你可以做更復雜的條件匹配。
operator 字段操作符說明:
操作符 | 說明 |
In | 指定值必須在給定的列表中 |
NotIn | 指定值不在給定的列表中 |
Exists | 指定鍵存在,不關心值 |
DoesNotExist | 指定鍵不存在 |
(2) Pod 親和性
Pod 親和性允許你指定 Pod 希望與其他 Pod 一起調度的偏好,而反親和性則表示 Pod 希望避免與某些 Pod 一起調度。
① 給前面創建的pod打上app=nginx1的標簽
# 給使用nodeSelector創建的nginx打上標簽
kubectl label pod nginx app=nginx1② 編寫yaml文件
vim podAffinity.yamlapiVersion: v1
kind: Pod
metadata:
name: nginx3
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 滿足條件才調度
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx1
topologyKey: "kubernetes.io/hostname"
containers:
- name: nginx3
image: docker.m.daocloud.io/nginx:1.25③ 運行pod
kubectl apply -f podAffinity.yaml④ 查看調度情況
[root@k8s-master data]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 4h32m 10.224.169.149 k8s-node2 <none> <none>
nginx2 1/1 Running 0 4h8m 10.224.169.154 k8s-node2 <none> <none>
nginx3 1/1 Running 0 14s 10.224.169.153 k8s-node2 <none> <none>可見pod已經調度到node2上,現在3個都運行在node2上,接下來測試一下反親和性
(3) Pod 反親和性
要求 Pod 不與特定的 Pod 調度到同一節點上,通常用于防止某些類型的 Pod 集中到同一節點上,避免單點故障。
① 編寫yaml文件
vim podAntiAffinity.yamlapiVersion: v1
kind: Pod
metadata:
name: nginx4
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx1
topologyKey: "kubernetes.io/hostname"
containers:
- name: app
image: docker.m.daocloud.io/nginx:1.25② 運行pod
kubectl apply -f podAntiAffinity.yaml③ 查看調度情況
[root@k8s-master data]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 4h37m 10.224.169.149 k8s-node2 <none> <none>
nginx2 1/1 Running 0 4h13m 10.224.169.154 k8s-node2 <none> <none>
nginx3 1/1 Running 0 5m26s 10.224.169.153 k8s-node2 <none> <none>
nginx4 1/1 Running 0 10s 10.224.36.69 k8s-node1 <none> <none>可以看到新建的nginx4避免與標簽為 app=nginx1的 Pod 調度到同一節點上,所以被調度到node1上,驗證了pod的反親和性。
親和性和反親和性優缺點:
優點:
- 靈活性強:支持多條件、復雜的調度規則,可以基于節點標簽、Pod 標簽、拓撲結構等進行細粒度控制。
- 支持跨節點調度:可以控制 Pod 在集群中的分布,增強應用的可用性和容錯性。
缺點:
- 配置復雜:調度規則更加復雜,理解和配置起來需要更多的時間。
- 可能影響調度效率:當使用大量的親和性和反親和性規則時,調度器需要更多時間來評估每個節點的匹配情況。
3. nodeName:直接指定節點
nodeName 是 Kubernetes 中一種最簡單且強制性的調度方式,它允許你直接指定一個節點來運行 Pod,而無需依賴調度器的調度決策。nodeName 適用于一些特殊場景,比如需要將 Pod 調度到特定的節點(例如硬件節點,或特定的節點上有特定設備,如 GPU)。
(1) 實戰操作:
① 編寫yaml
vim nodeName.yamlapiVersion: v1
kind: Pod
metadata:
name: nginx5
spec:
nodeName: k8s-node1
containers:
- name: nginx5
image: docker.m.daocloud.io/nginx:1.25② 運行pod
kubectl apply -f nodeName.yaml③ 查看調度情況
[root@k8s-master data]# kubectl get pod nginx5 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx5 1/1 Running 0 47s 10.224.36.70 k8s-node1 <none> <none>可以看到Pod nginx5 會被直接調度到 node1節點上。
(2) nodeName優缺點:
- 優點:簡單、直觀,適用于需要特定硬件或設備的場景。
- 缺點:失去調度器的靈活性,不適用于動態環境。
4. Pod 拓撲分布約束
Pod 拓撲分布約束用于保證 Pod 在多個節點、區域或故障域中的均衡分布。通過設置 topologySpreadConstraints,可以確保 Pod 在集群中分布更加均衡,避免 Pod 集中到某個節點或某個區域,從而增強集群的高可用性和容災能力。
apiVersion: v1
kind: Pod
metadata:
name: nginx6
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: nginx
containers:
- name: nginx6
image: docker.m.daocloud.io/nginx:1.25[root@k8s-master data]# kubectl get pod nginx6 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx6 1/1 Running 0 37s 10.224.36.71 k8s-node1 <none> <none>使用deployment來演示可能效果更明顯。
topologySpreadConstraints 保證 nginx Pod 在不同的主機上均勻分布。maxSkew 控制 Pod 在各個節點之間的最大不平衡度,而 topologyKey 是表示分布維度的關鍵字段,kubernetes.io/hostname 表示按主機名進行分布。
優缺點:
- 優點:保證 Pod 在多個節點、區域的均衡分布,提高高可用性。
- 缺點:配置較復雜,可能對調度性能產生影響。
5. 污點與容忍性
污點(Taints)和容忍性(Tolerations)是 Kubernetes 的一對調度機制,用于控制 Pod 是否能調度到帶有某些特定條件的節點。節點可以加上污點,只有設置了相應容忍性的 Pod 才能調度到這些節點。
污點(Taints) 是對節點的標記,表示該節點不希望接受不符合條件的 Pod。容忍(Tolerations) 是 Pod 上的標記,表示 Pod 能夠“容忍”某些污點。
(1) 實戰操作:
① 給節點加污點:
# 在節點1上添加污點
kubectl taint nodes k8s-node1 key=value:NoSchedule【溫馨提示】設置污點后,新建的pod如果沒有設置容忍,都無法調度到該節點,已存在的pod不受影響。
② Pod 上設置容忍性:
vim tolerations.yamlapiVersion: v1
kind: Pod
metadata:
name: nginx7
spec:
tolerations:
- key: "key"
operator: "Equal"
value: "value"
effect: "NoSchedule"
containers:
- name: nginx7
image: docker.m.daocloud.io/nginx:1.25③ 查看調度情況
[root@k8s-master data]# kubectl get pod nginx7 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx7 1/1 Running 0 32s 10.224.36.72 k8s-node1 <none> <none>nginx7被調度到設置了污點的節點,說明tolerations生效了,容忍了污點。
④ 去除污點
kubectl taint node k8s-node1 key-(2) 優缺點:
- 優點:提供了靈活的節點隔離和調度控制,適用于隔離特定類型的工作負載或維護節點。
- 缺點:配置復雜,濫用污點可能導致資源浪費或 Pod 調度錯誤。
三、總結
Kubernetes 提供了多種調度策略,可以根據不同的需求靈活選擇:
- nodeSelector:簡單的節點標簽匹配調度。
- 親和性與反親和性:更靈活的調度控制,基于節點和 Pod 之間的關系進行調度。
- nodeName:直接指定節點進行調度。
- Pod 拓撲分布約束:確保 Pod 在集群中的均衡分布,增強高可用性。
- 污點與容忍性:通過污點和容忍性控制哪些 Pod 可以調度到哪些節點。
通過合理組合這些調度策略,你可以優化 Pod 的資源分配、提升集群的可靠性和性能。




































