Kubernetes 提供多種排程策略,讓開發者可以精確控制 Pod 的佈署位置。本文將從最基本的 nodeName 和 nodeSelector 開始,逐步深入到更進階的 Node Affinity、Taints 和 Tolerations 等技術,並搭配例項說明如何根據不同的應用場景選擇合適的排程策略。瞭解這些策略,可以有效提升資源利用率,確保應用程式的高用性和效能。
Kubernetes Pod 排程高階技巧
Kubernetes 的 kube-scheduler 會根據特定的規則和組態值來選擇適合的節點(Node)執行 Pod。透過這些組態,你可以精確控制 kube-scheduler 如何選擇節點來執行 Pod。要控制 Pod 的執行位置,可以設定約束條件來限制其執行在特定的節點上,或指示優先選擇的節點。
為何需要影響 Pod 排程
通常情況下,Kubernetes 會有效地處理 Pod 的放置,確保 Pod 分散在不同的節點上以避免資源短缺。然而,在某些情況下,你可能需要影響 Pod 的排程,例如確保 Pod 執行在具備 SSD 的節點上,或將頻繁通訊的 Pod 放置在相同的可用區域內。
影響 Pod 排程的方法
你可以使用以下方法來影響 Kubernetes 中的 Pod 排程:
- 使用
nodeSelector欄位匹配節點標籤。 - 設定親和性(affinity)與反親和性(anti-affinity)規則。
- 指定
nodeName欄位。 - 定義 Pod 拓撲分佈約束(Pod topology spread constraints)。
- 使用汙點(Taints)和容忍(Tolerations)。
設定多節點 Kubernetes 叢集
在進行實作之前,請確保你擁有一個多節點的 Kubernetes 叢集。以下示範如何使用 minikube 建立一個多節點叢集:
$ minikube start \
--driver=virtualbox \
--nodes 3 \
--cni calico \
--cpus=2 \
--memory=2g \
--kubernetes-version=v1.30.0 \
--container-runtime=containerd
執行上述指令後,你將獲得一個包含三個節點的 Kubernetes 叢集。使用 kubectl get nodes 指令檢視節點狀態:
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
minikube Ready control-plane 3m34s v1.30.0
minikube-m02 Ready <none> 2m34s v1.30.0
minikube-m03 Ready <none> 87s v1.30.0
管理節點親和性
要了解 Kubernetes 中的節點親和性是如何工作的,首先需要檢視最基本的排程選項,即使用 nodeName 和 nodeSelector。
使用 nodeName 排程 Pod
每個 Pod 物件都有一個 nodeName 欄位,通常由 kube-scheduler 控制。然而,你可以在建立 Pod 或使用 Pod 範本建立控制器時,直接在 YAML 清單中設定此屬性。這是靜態排程 Pod 到特定節點的最簡單形式,但不具備彈性且無法擴充套件。
以下是一個 Deployment 物件的範例,展示瞭如何使用 nodeName 將五個 nginx Pod 排程到 minikube-m02 節點上:
# 01_nodename/nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-app
spec:
replicas: 5
selector:
matchLabels:
app: nginx
environment: test
template:
metadata:
labels:
app: nginx
environment: test
spec:
nodeName: minikube-m02 # 指定節點名稱
containers:
- name: nginx
image: nginx:1.17
ports:
- containerPort: 80
套用上述 Deployment YAML 後,使用 kubectl get pods 指令檢視 Pod 的狀態和節點名稱:
$ kubectl get pods --namespace default --output=custom-columns="NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName"
NAME STATUS NODE
nginx-app-7b547cfd87-4g9qx Running minikube
nginx-app-7b547cfd87-m76l2 Running minikube-m02
nginx-app-7b547cfd87-mjf78 Running minikube-m03
nginx-app-7b547cfd87-vvrgk Running minikube-m02
nginx-app-7b547cfd87-w7jcw Running minikube-m03
詳細解說
nodeName的作用:直接指定 Pod 要執行的節點名稱,繞過 kube-scheduler 的排程邏輯。- 優缺點:簡單直接,但缺乏彈性和自動化排程能力,不適合動態環境。
- 適用場景:除錯或特定測試場景,需要將 Pod 固定在特定節點上。
Kubernetes 中的 Pod 排程技術
在 Kubernetes 中,Pod 的排程是一個重要的議題。預設情況下,Kubernetes 的 kube-scheduler 會根據預設的排程策略來分配 Pod 到不同的 Node 上。在本章中,我們將探討如何使用 nodeName 和 nodeSelector 來控制 Pod 的排程。
使用 nodeName 強制排程 Pod
首先,我們來看看如何使用 nodeName 來強制排程 Pod 到特定的 Node 上。在 Deployment 的 Pod 範本中,我們可以指定 nodeName 欄位來強制將 Pod 排程到指定的 Node 上。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-app
spec:
...
template:
...
spec:
nodeName: minikube-m02
在這個例子中,我們將 nodeName 設定為 minikube-m02,這意味著所有的 Pod 都將被排程到 minikube-m02 這個 Node 上。
內容解密:
nodeName欄位用於指定 Pod 應該被排程到哪個 Node 上。- 當我們設定了
nodeName後,kube-scheduler 將會忽略其他的排程策略,直接將 Pod 排程到指定的 Node 上。 - 這種方式可以讓我們強制控制 Pod 的排程,但也需要謹慎使用,以避免資源分配不均的問題。
使用 nodeSelector 排程 Pod
除了 nodeName 之外,我們還可以使用 nodeSelector 來根據 Node 的標籤(label)來排程 Pod。nodeSelector 允許我們指定一個或多個標籤,只有具備這些標籤的 Node 才會被考慮用於排程 Pod。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-app
spec:
...
template:
...
spec:
nodeSelector:
node-type: superfast
在這個例子中,我們設定了 nodeSelector 為 {node-type: superfast},這意味著只有具備 node-type=superfast 標籤的 Node 才會被用於排程 Pod。
內容解密:
nodeSelector用於根據 Node 的標籤來篩選適合排程的 Node。- 只有當 Node 的標籤與
nodeSelector中指定的標籤相符時,該 Node 才會被考慮用於排程 Pod。 - 這種方式提供了一種更靈活的方式來控制 Pod 的排程,可以根據不同的需求來設定不同的標籤。
為 Node 新增自定義標籤
在 Kubernetes 中,每個 Node 都有一組預設的標籤,例如 kubernetes.io/arch 和 kubernetes.io/os。除了這些預設的標籤之外,我們還可以為 Node 新增自定義的標籤。
$ kubectl label nodes minikube-m02 node-type=superfast
$ kubectl label nodes minikube-m03 node-type=superfast
在這個例子中,我們為 minikube-m02 和 minikube-m03 這兩個 Node 增加了 node-type=superfast 的標籤。
內容解密:
- 使用
kubectl label命令可以為 Node 新增自定義的標籤。 - 自定義標籤可以用於
nodeSelector中,以控制 Pod 的排程。 - 為 Node 新增合適的標籤可以幫助我們更好地管理和排程資源。
進階 Pod 排程技術:Node Affinity 的應用
在 Kubernetes 中,Pod 的排程是一個重要的議題。除了基本的 nodeSelector 之外,Kubernetes 還提供了更進階的排程技術,例如 Node Affinity。本篇文章將探討 Node Affinity 的概念、組態方法及其在實際應用中的場景。
為什麼需要 Node Affinity?
在之前的章節中,我們已經瞭解瞭如何使用 nodeSelector 將 Pod 指派到特定的 Node 上。然而,nodeSelector 的功能相對有限,只能進行簡單的標籤匹配。Node Affinity 則提供了更豐富的語言來定義 Pod 與 Node 之間的關聯,使得排程規則更加靈活和強大。
Node Affinity 的優勢
與 nodeSelector 相比,Node Affinity 具有以下優勢:
- 更豐富的匹配規則:Node Affinity 支援多種運算元,如
In、NotIn、Exists、DoesNotExist、Gt和Lt,使得標籤匹配更加靈活。 - 軟性與硬性規則:可以定義軟性(soft)規則和硬性(hard)規則。軟性規則代表一種偏好,而非強制性要求。
- 權重組態:軟性規則可以設定權重,讓排程器在決策時綜合考量多個因素。
如何組態 Node Affinity?
以下是一個範例,展示如何使用 Node Affinity 來定義 Pod 的排程規則。假設我們有一個 Deployment,需要將 Pod 排程到具有 node-type 標籤且值為 fast 或 superfast 的 Node 上,但嚴格避免排程到具有 node-type=extremelyslow 的 Node 上。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-app
spec:
replicas: 5
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: node-type
operator: In
values:
- fast
- superfast
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-type
operator: NotIn
values:
- extremelyslow
containers:
- name: nginx
image: nginx:latest
內容解密:
preferredDuringSchedulingIgnoredDuringExecution:定義軟性規則,優先將 Pod 排程到具有node-type=fast或node-type=superfast的 Node 上。這裡設定了權重80,表示排程器會傾向於滿足這個條件。requiredDuringSchedulingIgnoredDuringExecution:定義硬性規則,確保 Pod 不會被排程到具有node-type=extremelyslow的 Node 上。這是透過NotIn運算元實作的。
實際操作與結果分析
將上述組態套用到 Kubernetes 叢集:
kubectl apply -f nginx-deployment.yaml檢視 Pod 的狀態和 Node 分配情況:
kubectl get pods -o custom-columns="NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName"結果顯示,Pod 主要被排程到符合
node-type=fast或node-type=superfast的 Node 上,並且避免了具有node-type=extremelyslow的 Node。
Plantuml 圖表說明
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title Kubernetes Pod 排程策略詳解
package "Kubernetes Cluster" {
package "Control Plane" {
component [API Server] as api
component [Controller Manager] as cm
component [Scheduler] as sched
database [etcd] as etcd
}
package "Worker Nodes" {
component [Kubelet] as kubelet
component [Kube-proxy] as proxy
package "Pods" {
component [Container 1] as c1
component [Container 2] as c2
}
}
}
api --> etcd : 儲存狀態
api --> cm : 控制迴圈
api --> sched : 調度決策
api --> kubelet : 指令下達
kubelet --> c1
kubelet --> c2
proxy --> c1 : 網路代理
proxy --> c2
note right of api
核心 API 入口
所有操作經由此處
end note
@enduml此圖示展示了 Pod 如何透過 Node Affinity 被排程到符合特定條件的 Node 上。優先選擇具有 node-type=fast 或 superfast 的 Node,同時避免具有 node-type=extremelyslow 的 Node。
高階Pod排程技術:Node親和性(Affinity)與反親和性(Anti-Affinity)實踐
在Kubernetes叢集中,合理地排程Pod至適當的Node上是確保應用效能和資源利用率的關鍵。本章節將探討如何使用Node親和性(Node Affinity)與反親和性(Node Anti-Affinity)來控制Pod的排程。
Node親和性與反親和性組態
為了展示Node親和性與反親和性的工作原理,我們首先為叢集中的Node設定特定的標籤。假設我們有三個Node:Node1、Node2和Node3,分別具有slow、fast和superfast的node-type標籤。我們的目標是讓Deployment的Pod優先排程到fast和superfast的Node上,同時嚴格避免排程到具有extremelyslow標籤的Node。
首先,我們使用kubectl label nodes命令為Node新增或更新node-type標籤:
$ kubectl label nodes --overwrite minikube node-type=slow
$ kubectl label nodes --overwrite minikube-m02 node-type=fast
$ kubectl label nodes --overwrite minikube-m03 node-type=superfast
接下來,我們需要在Deployment的YAML檔案中定義Node親和性規則。以下是一個範例組態:
# 03_affinity/nginx-deployment.yaml
spec:
template:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-type
operator: NotIn
values:
- extremelyslow
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: node-type
operator: In
values:
- fast
- superfast
內容解密:
nodeAffinity定義了Node親和性規則,用於控制Pod排程到哪些Node上。requiredDuringSchedulingIgnoredDuringExecution定義了一個硬性條件:Pod不能被排程到具有extremelyslow標籤的Node上。preferredDuringSchedulingIgnoredDuringExecution定義了一個軟性條件:Pod優先被排程到具有fast或superfast標籤的Node上。如果這些Node資源不足,Pod可以被排程到其他Node上。
實驗驗證
套用Deployment組態並觀察Pod的狀態和Node分配:
$ kubectl apply -f 03_affinity/nginx-deployment.yaml $ kubectl get pods --namespace default --output=custom-columns="NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName"結果顯示Pod被成功排程到
fast和superfast的Node上。修改Node標籤,將Node2和Node3標記為
extremelyslow,並重新佈署Deployment:$ kubectl label nodes --overwrite minikube-m02 node-type=extremelyslow $ kubectl label nodes --overwrite minikube-m03 node-type=extremelyslow $ kubectl rollout restart deployment nginx-app再次檢查Pod的狀態和Node分配:
$ kubectl get pods --namespace default --output=custom-columns="NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName"由於硬性條件的限制,Pod被排程到唯一的可用Node(Node1,具有
slow標籤)上。如果Node1資源不足,Pod將保持在Pending狀態。