Kubernetes集群調(diào)度詳解(節(jié)點(diǎn)親和性、Pod親和性、Taint與Toleration)
引導(dǎo):現(xiàn)在發(fā)覺每次pod調(diào)度都是隨機(jī)事件,不知道pod會被調(diào)度到哪一個節(jié)點(diǎn)
一、簡介
Scheduler 是 kubernetes 的調(diào)度器,主要的任務(wù)是把定義的 pod 分配到集群的節(jié)點(diǎn)上。聽起來非常簡單,但有很多要考慮的問題:
- 公平:如何保證每個節(jié)點(diǎn)都能被分配資源
- 資源高效利用:集群所有資源最大化被使用
- 效率:調(diào)度的性能要好,能夠盡快地對大批量的 pod 完成調(diào)度工作
- 靈活:允許用戶根據(jù)自己的需求控制調(diào)度的邏輯
Scheduler 是作為單獨(dú)的程序運(yùn)行的,啟動之后會一直堅挺 API Server,獲取PodSpec.NodeName為空的 pod,對每個 pod 都會創(chuàng)建一個 binding(必須遵守的),表明該 pod 應(yīng)該放到哪個節(jié)點(diǎn)上
二、調(diào)度過程
調(diào)度分為幾個部分:
- 首先是過濾掉不滿足條件的節(jié)點(diǎn),這個過程稱為predicate(預(yù)選);
- 然后對通過的節(jié)點(diǎn)按照優(yōu)先級排序,這個是priority(優(yōu)選);
- 最后從中選擇優(yōu)先級最高的節(jié)點(diǎn)。如果中間任何一步驟有錯誤,就直接返回錯誤(先預(yù)選,后優(yōu)選)
Predicate(預(yù)選)有一系列的算法可以使用:
- PodFitsResources:節(jié)點(diǎn)上剩余的資源是否大于 pod 請求的資源
- PodFitsHost:如果 pod 指定了 NodeName,檢查節(jié)點(diǎn)名稱是否和 NodeName 匹配
- PodFitsHostPorts:節(jié)點(diǎn)上已經(jīng)使用的 port 是否和 pod 申請的 port 沖突
- PodSelectorMatches:過濾掉和 pod 指定的 label 不匹配的節(jié)點(diǎn)
- NoDiskConflict:已經(jīng) mount 的 volume 和 pod 指定的 volume 不沖突,除非它們都是只讀
如果在 predicate 過程中沒有合適的節(jié)點(diǎn),pod 會一直在pending狀態(tài)(pending:等待),不斷重試調(diào)度,直到有節(jié)點(diǎn)滿足條件。經(jīng)過這個步驟,如果有多個節(jié)點(diǎn)滿足條件,就繼續(xù) priorities 過程:按照優(yōu)先級大小對節(jié)點(diǎn)排序
優(yōu)先級由一系列鍵值對組成,鍵是該優(yōu)先級項的名稱,值是它的權(quán)重(該項的重要性)。這些優(yōu)先級選項包括:
- LeastRequestedPriority:通過計算 CPU 和 Memory 的使用率來決定權(quán)重,使用率越低權(quán)重越高。換句話說,這個優(yōu)先級指標(biāo)傾向于資源使用比例更低的節(jié)點(diǎn)
- BalancedResourceAllocation:節(jié)點(diǎn)上 CPU 和 Memory 使用率越接近,權(quán)重越高。這個應(yīng)該和上面的一起使用,不應(yīng)該單獨(dú)使用
- ImageLocalityPriority:傾向于已經(jīng)有要使用鏡像的節(jié)點(diǎn),鏡像總大小值越大,權(quán)重越高
通過算法對所有的優(yōu)先級項目和權(quán)重進(jìn)行計算,得出最終的結(jié)果
三、自定義調(diào)度器
除了 kubernetes 自帶的調(diào)度器,你也可以編寫自己的調(diào)度器。通過spec:schedulername參數(shù)指定調(diào)度器的名字,可以為 pod 選擇某個調(diào)度器進(jìn)行調(diào)度。
比如下面的 pod 選擇my-scheduler進(jìn)行調(diào)度,而不是默認(rèn)的default-scheduler:
四、節(jié)點(diǎn)親和性(pod與node的親和性)
pod.spec.nodeAffinity
- preferredDuringSchedulingIgnoredDuringExecution(優(yōu)先執(zhí)行計劃):軟策略
- requiredDuringSchedulingIgnoredDuringExecution(要求執(zhí)行計劃):硬策略
- preferred:首選,較喜歡
- required:需要,必修
鍵值運(yùn)算關(guān)系
- In:label 的值在某個列表中
- NotIn:label 的值不在某個列表中
- Gt:label 的值大于某個值
- Lt:label 的值小于某個值
- Exists:某個 label 存在
- DoesNotExist:某個 label 不存在
1、硬策略:requiredDuringSchedulingIgnoredDuringExecution
#節(jié)點(diǎn)硬策略。排除node02,只能在node01上運(yùn)行
apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: hub.atguigu.com/library/myapp:v1
affinity: #親和性
nodeAffinity: #node親和性
# 硬親和性限制
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname # 標(biāo)簽鍵名
operator: NotIn #鍵值運(yùn)算關(guān)系 ,NotIn:label的值不在某個列表中。 表示不是node02節(jié)點(diǎn)就可運(yùn)行
values:
- k8s-node02 # 標(biāo)簽鍵值
kubectl get node --show-labels mkdir affi cd affi vim pod1.yaml kubectl create -f pod1.yaml kubectl get pod -o wide

kubectl delete pod --all && kubectl create -f pod1.yaml && kubectl get pod -o wide

把pod1.yaml改為In node3

然而實際并沒有node3節(jié)點(diǎn),因此一直處于Pending狀態(tài),這就是硬策略

2、軟策略:preferredDuringSchedulingIgnoredDuringExecution
如果有的話就在上面運(yùn)行,沒有的話就算了
vim pod2.yaml
#軟策略
apiVersion: v1
kind: Pod
metadata:
name: affinity2
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: hub.atguigu.com/library/myapp:v1
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1 #權(quán)重,權(quán)重越大越親和(多個軟策略的情況)
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- k8s-node03 # 期望是node03
查看:kubectl get node --show-labels

3、軟硬策略(先滿足硬策略再滿足軟策略)
#軟硬合體
apiVersion: v1
kind: Pod
metadata:
name: affinity2
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: hub.atguigu.com/library/myapp:v1
affinity:
nodeAffinity: #node親和性
# 硬親和性限制
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname # 標(biāo)簽鍵名
operator: NotIn #鍵值運(yùn)算關(guān)系 ,NotIn:label的值不在某個列表中。 表示不是node02節(jié)點(diǎn)就可運(yùn)行
values:
- k8s-node02 # 標(biāo)簽鍵值
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1 #權(quán)重,權(quán)重越大越親和(多個軟策略的情況)
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- k8s-node03 # 期望是node03
五、Pod親和性(pod與pod之間的親和性)
pod.spec.affinity.podAffinity/podAntiAffinity
- preferredDuringSchedulingIgnoredDuringExecution:軟策略
- requiredDuringSchedulingIgnoredDuringExecution:硬策略
親和性/反親和性調(diào)度策略比較如下:

kubectl get pod --show-labels

vim pod3.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-3
labels:
app: pod-3
spec:
containers:
- name: pod-3
image: hub.atguigu.com/library/myapp:v1
affinity:
#想讓兩個pod運(yùn)行在同一個node上
podAffinity:
#硬策略
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector: #標(biāo)簽選擇
matchExpressions:
- key: app #當(dāng)app存在node-affinity-pod時就選擇
operator: In
values:
- node-affinity-pod
topologyKey: kubernetes.io/hostname
#hostname判斷是否在同一個pod,唯一
發(fā)覺處于同一個拓?fù)溆騮opologyKey

vim pod4.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-4
labels:
app: pod-4
spec:
containers:
- name: pod-4
image: hub.atguigu.com/library/myapp:v1
affinity:
#不想讓兩個pod運(yùn)行在同一個node上
#匹配標(biāo)簽如果app=pod-2,那么則不運(yùn)行在這個節(jié)點(diǎn)
podAntiAffinity:
#軟策略
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app #匹配app=node-affinity-pod
operator: In
values:
- node-affinity-pod
topologyKey: kubernetes.io/hostname

補(bǔ)充:如果標(biāo)簽不滿足的情況,改標(biāo)簽的話就能滿足
kubectl label pod podname app=label --overwrite=true
六、Taint 和 Toleration
節(jié)點(diǎn)親和性,是pod的一種屬性(偏好或硬性要求),它使pod被吸引到一類特定的節(jié)點(diǎn)。Taint 則相反,它使節(jié)點(diǎn)能夠排斥一類特定的 pod
Taint 和 toleration 相互配合,可以用來避免 pod 被分配到不合適的節(jié)點(diǎn)上。每個節(jié)點(diǎn)上都可以應(yīng)用一個或多個taint ,這表示對于那些不能容忍這些 taint 的 pod,是不會被該節(jié)點(diǎn)接受的。如果將 toleration 應(yīng)用于 pod上,則表示這些 pod 可以(但不要求)被調(diào)度到具有匹配 taint 的節(jié)點(diǎn)上
污點(diǎn) (Taint)
1、污點(diǎn) ( Taint ) 的組成
使用kubectl taint命令可以給某個 Node 節(jié)點(diǎn)設(shè)置污點(diǎn),Node 被設(shè)置上污點(diǎn)之后就和 Pod 之間存在了一種相斥的關(guān)系,可以讓 Node 拒絕 Pod 的調(diào)度執(zhí)行,甚至將 Node 已經(jīng)存在的 Pod 驅(qū)逐出去每個污點(diǎn)的組成如下:
key=value:effect
每個污點(diǎn)有一個 key 和 value 作為污點(diǎn)的標(biāo)簽,其中 value 可以為空,effect 描述污點(diǎn)的作用。
當(dāng)前 taint effect 支持如下三個選項:
- NoSchedule:表示k8s將不會將Pod調(diào)度到具有該污點(diǎn)的Node上(K8Snode添加這個effecf類型污點(diǎn),新的不能容忍的pod不能再調(diào)度過來,但是老的運(yùn)行在node上不受影響)
- PreferNoSchedule:表示k8s將不會將Pod調(diào)度到具有該污點(diǎn)的Node上,同時會將Node上已經(jīng)存在的Pod驅(qū)逐出去(pod會嘗試將pod分配到該節(jié)點(diǎn))
- NoExecute:表示k8s將盡量避免將Pod調(diào)度到具有該污點(diǎn)的Node上(K8Snode添加這個effecf類型污點(diǎn),新的不能容忍的pod不能調(diào)度過來,老的pod也會被驅(qū)逐)
這也是為什么生成的pod不會分配到master的原因(因為天生就打了這個污點(diǎn)NoSchedule)

2、污點(diǎn)的設(shè)置、查看和去除
#查看節(jié)點(diǎn)污點(diǎn) 模板:kubectl describe node node-name kubectl describe node k8s-node01 # 設(shè)置污點(diǎn) 模板:kubectl taint nodes node1 key1=value1:NoSchedule kubectl taint nodes k8s-node01 check=guozige:NoExecute 因為pod是自主式pod,沒有控制器控制的pod。去除后就不存在了 如果是Deployment和StatefullSet,它就會在node02上創(chuàng)建,維持副本數(shù) # 節(jié)點(diǎn)說明中,查找 Taints 字段 kubectl describe node k8s-node01 # 去除污點(diǎn) 模板:kubectl taint nodes node1 key1=value1:NoSchedule- kubectl taint nodes k8s-node01 check=guozige:NoExecute-
設(shè)置污點(diǎn)測試
容忍(Tolerations)
設(shè)置了污點(diǎn)的 Node 將根據(jù) taint 的 effect:NoSchedule、PreferNoSchedule、NoExecute 和 Pod 之間產(chǎn)生互斥的關(guān)系,Pod 將在一定程度上不會被調(diào)度到 Node 上。但我們可以在 Pod 上設(shè)置容忍 ( Toleration ) ,意思是設(shè)置了容忍的 Pod 將可以容忍污點(diǎn)的存在,可以被調(diào)度到存在污點(diǎn)的 Node 上
pod.spec.tolerations
tolerations: #containers同級 - key: "check" #能容忍的污點(diǎn)key operator: "Equal" #Equal等于表示key=value , Exists不等于,表示當(dāng)值不等于下面value正常 value: "guozige" #值 effect: "NoExecute" #effect策略 tolerationSeconds: 3600 #原始的pod多久驅(qū)逐,注意只有effect: "NoExecute"才能設(shè)置,不然報錯
- 其中 key, vaule, effect 要與 Node 上設(shè)置的 taint 保持一致
- operator 的值為 Exists 將會忽略 value 值
- tolerationSeconds 用于描述當(dāng) Pod 需要被驅(qū)逐時可以在 Pod 上繼續(xù)保留運(yùn)行的時間
vim pod3.yaml

kubectl apply -f pod3.yaml kubectl get pod -o wide
容忍污點(diǎn)

1、當(dāng)不指定 key 值時,表示容忍所有的污點(diǎn) key:
tolerations: - operator: "Exists"
2、當(dāng)不指定 effect 值時,表示容忍所有的污點(diǎn)作用
tolerations: - key: "key" operator: "Exists"
3、有多個 Master 存在時,防止資源浪費(fèi),可以如下設(shè)置
kubectl taint nodes Node-Name node-role.kubernetes.io/master=:PreferNoSchedule PreferNoSchedule 盡可能不在該節(jié)點(diǎn)上運(yùn)行,只有當(dāng)節(jié)點(diǎn)資源不夠用才運(yùn)行
配置節(jié)點(diǎn)故障后Pod重新調(diào)度的時間
例如下面的配置文件,對于notReady和unreachable狀態(tài)的節(jié)點(diǎn),其上的Pod等待300秒,如果仍未恢復(fù),則會停止執(zhí)行。
八、指定調(diào)度節(jié)點(diǎn)
親和性和污點(diǎn),容忍都比較含蓄。
指定調(diào)度節(jié)點(diǎn)是絕對指定目標(biāo),就要這個
1、Pod.spec.nodeName 將 Pod 直接調(diào)度到指定的 Node 節(jié)點(diǎn)上,會跳過 Scheduler 的調(diào)度策略,該匹配規(guī)則是強(qiáng)制匹配
vim pod5.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: myweb
spec:
replicas: 7
template:
metadata:
labels:
app: myweb
spec:
nodeName: k8s-node01 #指定全在node01
containers:
- name: myweb
image: hub.atguigu.com/library/myapp:v1
ports:
- containerPort: 80

2、Pod.spec.nodeSelector:通過 kubernetes 的 label-selector 機(jī)制選擇節(jié)點(diǎn),由調(diào)度器調(diào)度策略匹配 label,而后調(diào)度 Pod 到目標(biāo)節(jié)點(diǎn),該匹配規(guī)則屬于強(qiáng)制約束
vim pod6.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: myweb66
spec:
replicas: 2
template:
metadata:
labels:
app: myweb66
spec:
nodeSelector:
disk: ssd #硬盤必須是ssd類型才運(yùn)行
#type: backEndNode1 #標(biāo)簽名,標(biāo)簽值
containers:
- name: myweb66
image: hub.atguigu.com/library/myapp:v1
ports:
- containerPort: 80
測試驗證
kubectl label node k8s-node01 disk=ssd kubectl label node k8s-node02 disk=ssd kubectl edit deployment myweb66 增加副本數(shù)目 kubectl get pod 發(fā)現(xiàn)有些在node02上了
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Kubernetes?安裝flannel組件的過程(本地?kube-flannel.yml?文件)
文章介紹了如何在無法直接訪問raw.githubusercontent.com的情況下,通過科學(xué)上網(wǎng)或下載kube-flannel.yml文件源碼來部署Flannel網(wǎng)絡(luò)插件的方法,感興趣的朋友一起看看吧2025-03-03
keepalived?nopreempt的應(yīng)用場景及說明
文章詳細(xì)介紹了keepalived高可用模式下`nopreempt`非搶占模式的應(yīng)用場景,并探討了不同配置下的VIP故障轉(zhuǎn)移行為,同時,文章還解釋了`notify`腳本的作用,包括觸發(fā)時機(jī)和典型用途2026-01-01
Centos?8.2?升級內(nèi)核通過elrepo源的方法
這篇文章主要介紹了Centos?8.2?升級內(nèi)核通過elrepo源,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-10-10

