從NodeSelector到NodeAffinity:探索Kubernetes節點親和性的進化之路
在Kubernetes中,有時候我們需要更精確地控制Pod的調度,將其分配到集群中特定的節點上。kubernetes對Pod的調度規則,kubernetes提供了四大類調度方式:
- 自動調度:運行在哪個節點上完全由Scheduler經過一系列的算法計算得出
- 定向調度:NodeName、NodeSelector
- 親和性調度:NodeAffinity、PodAffinity、PodAntiAffinity
- 污點(容忍)調度:Taints、Toleration
本教程將向您介紹兩種方法:使用定向調度和親和性調度,以確保Pod只在我們指定的節點上運行。
一、定向調度
1.什么是NodeSelector
NodeSelector 是 Kubernetes 中一種用于調度 Pod 到特定節點的機制。通過在 Pod 的配置中定義 nodeSelector 字段,您可以為 Pod 指定一組鍵值對標簽。這些標簽將與集群中的節點標簽進行匹配,以確定 Pod 應該被調度到哪個節點上運行。
具體而言,nodeSelector 允許您按照節點的標簽選擇性地將 Pod 調度到集群中。這種機制非常適用于具有特定硬件要求或運行特定環境的 Pod,以確保它們在正確的節點上運行。
2.NodeSelector基本用法
此 Pod 配置文件描述了一個擁有節點選擇器 disktype: ssd 的 Pod。這表明該 Pod 將被調度到有 disktype=ssd 標簽的節點。
apiVersion:v1
kind:Pod
metadata:
name:nginx
labels:
env:test
spec:
containers:
-name:nginx
image:nginx
imagePullPolicy:IfNotPresent
nodeSelector:
disktype:ssd
以下通過案例演示的方式來闡述NodeSelector的基本用法:
(1) 列出你的集群中的節點, 包括這些節點上的標簽,輸出類似如下:
controlplane $ kubectl get node --show-labels
NAME STATUS ROLES AGE VERSION LABELS
controlplane Ready control-plane 12h v1.29.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=controlplane,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
node01 Ready <none> 12h v1.29.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node01,kubernetes.io/os=linux
(2) 從你的節點中選擇一個,為它添加標簽
kubectl label nodes node01 disktype=ssd
(3) 驗證你選擇的節點確實帶有 disktype=ssd 標簽:
(4) 創建一個將被調度到你選擇的節點的Pod:
kubectl create -f pod-nginx.yaml
- pod-nginx.yaml文件的內容是上述yaml所示。
- 創建成功后這個pod會調度到包含有disktype=ssd的標簽中
執行成功后,驗證Pod 確實運行在你選擇的節點上:
controlplane $ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 11s 192.168.1.4 node01 <none> <none>
我們還可以通過設置spec.nodeName參數將某個Pod 調度到特定的節點。演示yaml如下:
apiVersion:v1
kind:Pod
metadata:
name:nginx
spec:
nodeName:foo-node# 調度 Pod 到特定的節點
containers:
-name:nginx
image:nginx
imagePullPolicy:IfNotPresent
二、親和性調度
kubernetes還提供了一種親和性調度(Affinity)。它在NodeSelector的基礎之上的進行了擴展,可以通過配置的形式,實現優先選擇滿足條件的Node進行調度,如果沒有,也可以調度到不滿足條件的節點上,使調度更加靈活。Affinity主要分為三類:
- nodeAffinity(node親和性): 以node為目標,解決pod可以調度到哪些node的問題
- podAffinity(pod親和性) : 以pod為目標,解決pod可以和哪些已存在的pod部署在同一個拓撲域中的問題
- podAntiAffinity(pod反親和性) : 以pod為目標,解決pod不能和哪些已存在pod部署在同一個拓撲域中的問題
11.NodeAffinity
NodeAffinity意為Node親和性調度策略。是用于替換NodeSelector的全新調度策略。目前有兩種節點節點親和性表達:
- RequiredDuringSchedulingIgnoredDuringExecution:必須滿足制定的規則才可以調度pode到Node上。相當于硬限制。
- PreferredDuringSchedulingIgnoreDuringExecution:強調優先滿足制定規則,調度器會嘗試調度pod到Node上,但并不強求,相當于軟限制。多個優先級規則還可以設置權重值,以定義執行的先后順序。
首先來看一下NodeAffinity的可配置項:
pod.spec.affinity.nodeAffinity
requiredDuringSchedulingIgnoredDuringExecution #Node節點必須滿足指定的所有規則才可以,相當于硬限制
nodeSelectorTerms #節點選擇列表
matchFields #按節點字段列出的節點選擇器要求列表
matchExpressions #按節點標簽列出的節點選擇器要求列表(推薦)
key #鍵
values #值
operat or #關系符 支持Exists, DoesNotExist, In, NotIn, Gt, Lt
preferredDuringSchedulingIgnoredDuringExecution #優先調度到滿足指定的規則的Node,相當于軟限制 (傾向)
preference #一個節點選擇器項,與相應的權重相關聯
matchFields #按節點字段列出的節點選擇器要求列表
matchExpressions # 按節點標簽列出的節點選擇器要求列表(推薦)
key #鍵
values #值
operator #關系符 支持In, NotIn, Exists, DoesNotExist, Gt, Lt
weight #傾向權重,在范圍1-100。
例如,下面這個Pod需要部署到不是disktype=ssd標簽上的node上。
apiVersion:v1
kind:Pod
metadata:
name:nginx
labels:
env:test
spec:
containers:
-name:nginx
image:nginx
imagePullPolicy:IfNotPresent
affinity:
nodeAffinity:#設置node親和性
requiredDuringSchedulingIgnoredDuringExecution:# 硬限制
nodeSelectorTerms:
-matchExpressions:
-key:disktype
operator:NotIn
values:["ssd"]
執行創建命令后,該pod會被調度標簽disktype值中不包含ssd這個值的node上。
controlplane $ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 20s 192.168.0.4 controlplane <none> <none>
controlplane $ kubectl get node --show-labels
NAME STATUS ROLES AGE VERSION LABELS
controlplane Ready control-plane 15h v1.29.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=controlplane,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
node01 Ready <none> 14h v1.29.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=node01,kubernetes.io/os=linux
2.podAffinity
podAffinity 是 Kubernetes 中的一種調度機制,它允許您指定一組條件,以影響 Pod 之間的調度關系。具體而言,podAffinity 允許您在同一節點上調度具有相似屬性或關系的 Pod,或者在不同節點上調度具有相關屬性的 Pod。podAffinity 同樣通過 requiredDuringSchedulingIgnoredDuringExecution 和 preferredDuringSchedulingIgnoredDuringExecution兩種方式來實現。下面通過實例來說明 Pod 間的親和性和互斥性策略設置。
(1) 參照目標Pod
首先,創建一個名為 pod-flag 的 Pod ,帶有標簽 security=S1 和 app=nginx ,后面的例子將使用 pod-flag 作為 Pod 親和與互斥的目標 Pod 。
apiVersion:v1
kind:Pod
metadata:
name:pod-flag
labels:
security:"S1"
app:nginx
spec:
containers:
-name:nginx
image:nginx
(2) Pod的親和性調度
下面創建第 2 個 Pod 來說明 Pod 的親和性調度,這里定義的親和標簽是security=S1 ,對應上面的 Pod pod-flag, topologyKey 的值被設置為 kubemetes.io/hostname
apiVersion:v1
kind:Pod
metadata:
name:pod-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
-labelSelector:
matchExpressions:
-key:security
operator:In
values:
-S1
topologyKey:kubernetes.io/hostname
containers:
-name:with-pod-affinity
image:nginx
兩個Pod創建成功后,使用kubectl get pods -o wide命令可以看到,這兩個 Pod 處于同一個 Node之上運行 。
controlplane $ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-affinity 1/1 Running 0 8s 192.168.1.5 node01 <none> <none>
pod-flag 1/1 Running 0 94s 192.168.1.4 node01 <none> <none>
在創建pod-affinity這個Pod 之前,刪掉這個節點的kubemetes.io/hostname標簽,重復上面的創建步驟,將會發現 Pod 會一直處于 Pending 狀態,這是因為找不到滿足條件的 Node 了。
controlplane $ kubectl label node node01 kubernetes.io/hostname-
node/node01 unlabeled
controlplane $ kubectl get pod
NAME READY STATUS RESTARTS AGE
pod-affinity 1/1 Running 0 4m49s
pod-flag 1/1 Running 0 6m15s
controlplane $ kubectl delete pod pod-affinity
pod "pod-affinity" deleted
controlplane $ kubectl apply -f pod-affinity.yaml
pod/pod-affinity created
controlplane $ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-affinity 0/1 Pending 0 16s <none> <none> <none> <none>
pod-flag 1/1 Running 0 6m59s 192.168.1.4 node01 <none> <none>
(3) Pod的互斥性調度
創建第3個Pod , 我們希望它不能與參照目標 Pod 運行在同一個Node 上 。
apiVersion:v1
kind:Pod
metadata:
name:anti-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
-labelSelector:
matchExpressions:
-key:security
operator:In
values:
-S1
topologyKey:beta.kubernetes.io/arch
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
-labelSelector:
matchExpressions:
-key:app
operator:In
values:
-nginx
topologyKey:kubernetes.io/hostname
containers:
-name:anti-affinity
image:registry.aliyuncs.com/google_containers/pause:3.1
這里要求這個新 Pod 與 security=S1 的 Pod 為同一個arch平臺 ,但是不與 app=nginx 的 Pod 為同一個 Node 。創建 Pod 之后,同樣用kubectl get pods -o wide 來查看,會看到新的 Pod 被調度到了其他arch平臺 內的不同的 Node 上去。
controlplane $ kubectl apply -f anti-affinity.yaml
pod/anti-affinity created
controlplane $ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
anti-affinity 1/1 Running 0 6s 192.168.0.6 controlplane <none> <none>
pod-affinity 1/1 Running 0 24m 192.168.1.6 node01 <none> <none>
pod-flag 1/1 Running 0 31m 192.168.1.4 node01 <none> <none>
三、CKA真題
1.真題截圖
2.中文解析
切換 k8s 集群環境:kubectl config use-context k8sTask:創建一個 Pod,名字為 nginx-kusc00401,鏡像地址是 nginx,調度到具有 disk=spinning 標簽的節點上。
3.官方參考文檔
指定Pod調度到某個Node
4.解題作答
切換切換k8s集群環境:
kubectl config use-context k8s
創建Pod的資源對象:
apiVersion:v1
kind:Pod
metadata:
name:nginx-kusc00401
spec:
containers:
-name:nginx
image:nginx
imagePullPolicy:IfNotPresent
nodeSelector:
disk:spinning
執行命令創建pod:
kubectl apply -f nginx-kusc00401.yaml