從NodeSelector到NodeAffinity:探索Kubernetes節(jié)點(diǎn)親和性的進(jìn)化之路
在Kubernetes中,有時(shí)候我們需要更精確地控制Pod的調(diào)度,將其分配到集群中特定的節(jié)點(diǎn)上。kubernetes對(duì)Pod的調(diào)度規(guī)則,kubernetes提供了四大類調(diào)度方式:
- 自動(dòng)調(diào)度:運(yùn)行在哪個(gè)節(jié)點(diǎn)上完全由Scheduler經(jīng)過一系列的算法計(jì)算得出
- 定向調(diào)度:NodeName、NodeSelector
- 親和性調(diào)度:NodeAffinity、PodAffinity、PodAntiAffinity
- 污點(diǎn)(容忍)調(diào)度:Taints、Toleration
本教程將向您介紹兩種方法:使用定向調(diào)度和親和性調(diào)度,以確保Pod只在我們指定的節(jié)點(diǎn)上運(yùn)行。
一、定向調(diào)度
1.什么是NodeSelector
NodeSelector 是 Kubernetes 中一種用于調(diào)度 Pod 到特定節(jié)點(diǎn)的機(jī)制。通過在 Pod 的配置中定義 nodeSelector 字段,您可以為 Pod 指定一組鍵值對(duì)標(biāo)簽。這些標(biāo)簽將與集群中的節(jié)點(diǎn)標(biāo)簽進(jìn)行匹配,以確定 Pod 應(yīng)該被調(diào)度到哪個(gè)節(jié)點(diǎn)上運(yùn)行。
具體而言,nodeSelector 允許您按照節(jié)點(diǎn)的標(biāo)簽選擇性地將 Pod 調(diào)度到集群中。這種機(jī)制非常適用于具有特定硬件要求或運(yùn)行特定環(huán)境的 Pod,以確保它們?cè)谡_的節(jié)點(diǎn)上運(yùn)行。
2.NodeSelector基本用法
此 Pod 配置文件描述了一個(gè)擁有節(jié)點(diǎn)選擇器 disktype: ssd 的 Pod。這表明該 Pod 將被調(diào)度到有 disktype=ssd 標(biāo)簽的節(jié)點(diǎn)。
apiVersion:v1
kind:Pod
metadata:
name:nginx
labels:
env:test
spec:
containers:
-name:nginx
image:nginx
imagePullPolicy:IfNotPresent
nodeSelector:
disktype:ssd
以下通過案例演示的方式來(lái)闡述NodeSelector的基本用法:
(1) 列出你的集群中的節(jié)點(diǎn), 包括這些節(jié)點(diǎn)上的標(biāo)簽,輸出類似如下:
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) 從你的節(jié)點(diǎn)中選擇一個(gè),為它添加標(biāo)簽
kubectl label nodes node01 disktype=ssd
(3) 驗(yàn)證你選擇的節(jié)點(diǎn)確實(shí)帶有 disktype=ssd 標(biāo)簽:
(4) 創(chuàng)建一個(gè)將被調(diào)度到你選擇的節(jié)點(diǎn)的Pod:
kubectl create -f pod-nginx.yaml
- pod-nginx.yaml文件的內(nèi)容是上述yaml所示。
- 創(chuàng)建成功后這個(gè)pod會(huì)調(diào)度到包含有disktype=ssd的標(biāo)簽中
執(zhí)行成功后,驗(yàn)證Pod 確實(shí)運(yùn)行在你選擇的節(jié)點(diǎn)上:
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>
我們還可以通過設(shè)置spec.nodeName參數(shù)將某個(gè)Pod 調(diào)度到特定的節(jié)點(diǎn)。演示yaml如下:
apiVersion:v1
kind:Pod
metadata:
name:nginx
spec:
nodeName:foo-node# 調(diào)度 Pod 到特定的節(jié)點(diǎn)
containers:
-name:nginx
image:nginx
imagePullPolicy:IfNotPresent
二、親和性調(diào)度
kubernetes還提供了一種親和性調(diào)度(Affinity)。它在NodeSelector的基礎(chǔ)之上的進(jìn)行了擴(kuò)展,可以通過配置的形式,實(shí)現(xiàn)優(yōu)先選擇滿足條件的Node進(jìn)行調(diào)度,如果沒有,也可以調(diào)度到不滿足條件的節(jié)點(diǎn)上,使調(diào)度更加靈活。Affinity主要分為三類:
- nodeAffinity(node親和性): 以node為目標(biāo),解決pod可以調(diào)度到哪些node的問題
- podAffinity(pod親和性) : 以pod為目標(biāo),解決pod可以和哪些已存在的pod部署在同一個(gè)拓?fù)溆蛑械膯栴}
- podAntiAffinity(pod反親和性) : 以pod為目標(biāo),解決pod不能和哪些已存在pod部署在同一個(gè)拓?fù)溆蛑械膯栴}
11.NodeAffinity
NodeAffinity意為Node親和性調(diào)度策略。是用于替換NodeSelector的全新調(diào)度策略。目前有兩種節(jié)點(diǎn)節(jié)點(diǎn)親和性表達(dá):
- RequiredDuringSchedulingIgnoredDuringExecution:必須滿足制定的規(guī)則才可以調(diào)度pode到Node上。相當(dāng)于硬限制。
- PreferredDuringSchedulingIgnoreDuringExecution:強(qiáng)調(diào)優(yōu)先滿足制定規(guī)則,調(diào)度器會(huì)嘗試調(diào)度pod到Node上,但并不強(qiáng)求,相當(dāng)于軟限制。多個(gè)優(yōu)先級(jí)規(guī)則還可以設(shè)置權(quán)重值,以定義執(zhí)行的先后順序。
首先來(lái)看一下NodeAffinity的可配置項(xiàng):
pod.spec.affinity.nodeAffinity
requiredDuringSchedulingIgnoredDuringExecution #Node節(jié)點(diǎn)必須滿足指定的所有規(guī)則才可以,相當(dāng)于硬限制
nodeSelectorTerms #節(jié)點(diǎn)選擇列表
matchFields #按節(jié)點(diǎn)字段列出的節(jié)點(diǎn)選擇器要求列表
matchExpressions #按節(jié)點(diǎn)標(biāo)簽列出的節(jié)點(diǎn)選擇器要求列表(推薦)
key #鍵
values #值
operat or #關(guān)系符 支持Exists, DoesNotExist, In, NotIn, Gt, Lt
preferredDuringSchedulingIgnoredDuringExecution #優(yōu)先調(diào)度到滿足指定的規(guī)則的Node,相當(dāng)于軟限制 (傾向)
preference #一個(gè)節(jié)點(diǎn)選擇器項(xiàng),與相應(yīng)的權(quán)重相關(guān)聯(lián)
matchFields #按節(jié)點(diǎn)字段列出的節(jié)點(diǎn)選擇器要求列表
matchExpressions # 按節(jié)點(diǎn)標(biāo)簽列出的節(jié)點(diǎn)選擇器要求列表(推薦)
key #鍵
values #值
operator #關(guān)系符 支持In, NotIn, Exists, DoesNotExist, Gt, Lt
weight #傾向權(quán)重,在范圍1-100。
例如,下面這個(gè)Pod需要部署到不是disktype=ssd標(biāo)簽上的node上。
apiVersion:v1
kind:Pod
metadata:
name:nginx
labels:
env:test
spec:
containers:
-name:nginx
image:nginx
imagePullPolicy:IfNotPresent
affinity:
nodeAffinity:#設(shè)置node親和性
requiredDuringSchedulingIgnoredDuringExecution:# 硬限制
nodeSelectorTerms:
-matchExpressions:
-key:disktype
operator:NotIn
values:["ssd"]
執(zhí)行創(chuàng)建命令后,該pod會(huì)被調(diào)度標(biāo)簽disktype值中不包含ssd這個(gè)值的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 中的一種調(diào)度機(jī)制,它允許您指定一組條件,以影響 Pod 之間的調(diào)度關(guān)系。具體而言,podAffinity 允許您在同一節(jié)點(diǎn)上調(diào)度具有相似屬性或關(guān)系的 Pod,或者在不同節(jié)點(diǎn)上調(diào)度具有相關(guān)屬性的 Pod。podAffinity 同樣通過 requiredDuringSchedulingIgnoredDuringExecution 和 preferredDuringSchedulingIgnoredDuringExecution兩種方式來(lái)實(shí)現(xiàn)。下面通過實(shí)例來(lái)說明 Pod 間的親和性和互斥性策略設(shè)置。
(1) 參照目標(biāo)Pod
首先,創(chuàng)建一個(gè)名為 pod-flag 的 Pod ,帶有標(biāo)簽 security=S1 和 app=nginx ,后面的例子將使用 pod-flag 作為 Pod 親和與互斥的目標(biāo) Pod 。
apiVersion:v1
kind:Pod
metadata:
name:pod-flag
labels:
security:"S1"
app:nginx
spec:
containers:
-name:nginx
image:nginx
(2) Pod的親和性調(diào)度
下面創(chuàng)建第 2 個(gè) Pod 來(lái)說明 Pod 的親和性調(diào)度,這里定義的親和標(biāo)簽是security=S1 ,對(duì)應(yīng)上面的 Pod pod-flag, topologyKey 的值被設(shè)置為 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
兩個(gè)Pod創(chuàng)建成功后,使用kubectl get pods -o wide命令可以看到,這兩個(gè) Pod 處于同一個(gè) Node之上運(yùn)行 。
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>
在創(chuàng)建pod-affinity這個(gè)Pod 之前,刪掉這個(gè)節(jié)點(diǎn)的kubemetes.io/hostname標(biāo)簽,重復(fù)上面的創(chuàng)建步驟,將會(huì)發(fā)現(xiàn) Pod 會(huì)一直處于 Pending 狀態(tài),這是因?yàn)檎也坏綕M足條件的 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的互斥性調(diào)度
創(chuàng)建第3個(gè)Pod , 我們希望它不能與參照目標(biāo) Pod 運(yùn)行在同一個(gè)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
這里要求這個(gè)新 Pod 與 security=S1 的 Pod 為同一個(gè)arch平臺(tái) ,但是不與 app=nginx 的 Pod 為同一個(gè) Node 。創(chuàng)建 Pod 之后,同樣用kubectl get pods -o wide 來(lái)查看,會(huì)看到新的 Pod 被調(diào)度到了其他arch平臺(tái) 內(nèi)的不同的 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 集群環(huán)境:kubectl config use-context k8sTask:創(chuàng)建一個(gè) Pod,名字為 nginx-kusc00401,鏡像地址是 nginx,調(diào)度到具有 disk=spinning 標(biāo)簽的節(jié)點(diǎn)上。
3.官方參考文檔
指定Pod調(diào)度到某個(gè)Node
4.解題作答
切換切換k8s集群環(huán)境:
kubectl config use-context k8s
創(chuàng)建Pod的資源對(duì)象:
apiVersion:v1
kind:Pod
metadata:
name:nginx-kusc00401
spec:
containers:
-name:nginx
image:nginx
imagePullPolicy:IfNotPresent
nodeSelector:
disk:spinning
執(zhí)行命令創(chuàng)建pod:
kubectl apply -f nginx-kusc00401.yaml