這篇文章主要講解了“k8s默認(rèn)調(diào)度器調(diào)度策略是什么意思”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“k8s默認(rèn)調(diào)度器調(diào)度策略是什么意思”吧!
平利ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:13518219792(備注:SSL證書合作)期待與您的合作!
首先,我們一起看看 Predicates。
Predicates 在調(diào)度過程中的作用,可以理解為 Filter,即:它按照調(diào)度策略,從當(dāng)前集群的所有節(jié)點(diǎn)中,“過濾”出一系列符合條件的節(jié)點(diǎn)。這些節(jié)點(diǎn),都是可以運(yùn)行待調(diào)度 Pod 的宿主機(jī)。
而在 Kubernetes 中,默認(rèn)的調(diào)度策略有如下三種。
顧名思義,這一組過濾規(guī)則,負(fù)責(zé)的是最基礎(chǔ)的調(diào)度策略。
PodFitsResources 計算的就是宿主機(jī)的 CPU 和內(nèi)存資源等是否夠用。
當(dāng)然,我在前面已經(jīng)提到過,PodFitsResources 檢查的只是 Pod 的 requests 字段。需要注意的是,Kubernetes 的調(diào)度器并沒有為 GPU 等硬件資源定義具體的資源類型,而是統(tǒng)一用一種名叫 Extended Resource 的、Key-Value 格式的擴(kuò)展字段來描述的。比如下面這個例子:
apiVersion: v1 kind: Pod metadata: name: extended-resource-demo spec: containers: - name: extended-resource-demo-ctr image: nginx resources: requests: alpha.kubernetes.io/nvidia-gpu: 2 limits: alpha.kubernetes.io/nvidia-gpu: 2
可以看到,我們這個 Pod 通過alpha.kubernetes.io/nvidia-gpu=2
這樣的定義方式,聲明使用了兩個 NVIDIA 類型的 GPU。
而在 PodFitsResources 里面,調(diào)度器其實(shí)并不知道這個字段 Key 的含義是 GPU,而是直接使用后面的 Value 進(jìn)行計算。當(dāng)然,在 Node 的 Capacity 字段里,你也得相應(yīng)地加上這臺宿主機(jī)上 GPU 的總數(shù),比如:alpha.kubernetes.io/nvidia-gpu=4
。這些流程,我在后面講解 Device Plugin 的時候會詳細(xì)介紹到。
而 PodFitsHost 檢查的是,宿主機(jī)的名字是否跟 Pod 的 spec.nodeName 一致。
PodFitsHostPorts 檢查的是,Pod 申請的宿主機(jī)端口(spec.nodePort)是不是跟已經(jīng)被使用的端口有沖突。
PodMatchNodeSelector 檢查的是,Pod 的 nodeSelector 或者 nodeAffinity 指定的節(jié)點(diǎn),是否與待考察節(jié)點(diǎn)匹配,等等。
可以看到,像上面這樣一組 GeneralPredicates,正是 Kubernetes 考察一個 Pod 能不能運(yùn)行在一個 Node 上最基本的過濾條件。所以,GeneralPredicates 也會被其他組件(比如 kubelet)直接調(diào)用。
我在上一篇文章中已經(jīng)提到過,kubelet 在啟動 Pod 前,會執(zhí)行一個 Admit 操作來進(jìn)行二次確認(rèn)。這里二次確認(rèn)的規(guī)則,就是執(zhí)行一遍 GeneralPredicates。
這一組過濾規(guī)則,負(fù)責(zé)的是跟容器持久化 Volume 相關(guān)的調(diào)度策略。
其中,NoDiskConflict 檢查的條件,是多個 Pod 聲明掛載的持久化 Volume 是否有沖突。比如,AWS EBS 類型的 Volume,是不允許被兩個 Pod 同時使用的。所以,當(dāng)一個名叫 A 的 EBS Volume 已經(jīng)被掛載在了某個節(jié)點(diǎn)上時,另一個同樣聲明使用這個 A Volume 的 Pod,就不能被調(diào)度到這個節(jié)點(diǎn)上了。
而 MaxPDVolumeCountPredicate 檢查的條件,則是一個節(jié)點(diǎn)上某種類型的持久化 Volume 是不是已經(jīng)超過了一定數(shù)目,如果是的話,那么聲明使用該類型持久化 Volume 的 Pod 就不能再調(diào)度到這個節(jié)點(diǎn)了。
而 VolumeZonePredicate,則是檢查持久化 Volume 的 Zone(高可用域)標(biāo)簽,是否與待考察節(jié)點(diǎn)的 Zone 標(biāo)簽相匹配。
此外,這里還有一個叫作 VolumeBindingPredicate 的規(guī)則。它負(fù)責(zé)檢查的,是該 Pod 對應(yīng)的 PV 的 nodeAffinity 字段,是否跟某個節(jié)點(diǎn)的標(biāo)簽相匹配。
曾經(jīng)講解過,Local Persistent Volume(本地持久化卷),必須使用 nodeAffinity 來跟某個具體的節(jié)點(diǎn)綁定。這其實(shí)也就意味著,在 Predicates 階段,Kubernetes 就必須能夠根據(jù) Pod 的 Volume 屬性來進(jìn)行調(diào)度。
此外,如果該 Pod 的 PVC 還沒有跟具體的 PV 綁定的話,調(diào)度器還要負(fù)責(zé)檢查所有待綁定 PV,當(dāng)有可用的 PV 存在并且該 PV 的 nodeAffinity 與待考察節(jié)點(diǎn)一致時,這條規(guī)則才會返回“成功”。比如下面這個例子:
apiVersion: v1 kind: PersistentVolume metadata: name: example-local-pv spec: capacity: storage: 500Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: local-storage local: path: /mnt/disks/vol1 nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - my-node
可以看到,這個 PV 對應(yīng)的持久化目錄,只會出現(xiàn)在名叫 my-node 的宿主機(jī)上。所以,任何一個通過 PVC 使用這個 PV 的 Pod,都必須被調(diào)度到 my-node 上才可以正常工作。VolumeBindingPredicate,正是調(diào)度器里完成這個決策的位置。
這一組規(guī)則,主要考察待調(diào)度 Pod 是否滿足 Node 本身的某些條件。
比如,PodToleratesNodeTaints,負(fù)責(zé)檢查的就是我們前面經(jīng)常用到的 Node 的“污點(diǎn)”機(jī)制。只有當(dāng) Pod 的 Toleration 字段與 Node 的 Taint 字段能夠匹配的時候,這個 Pod 才能被調(diào)度到該節(jié)點(diǎn)上。
而 NodeMemoryPressurePredicate,檢查的是當(dāng)前節(jié)點(diǎn)的內(nèi)存是不是已經(jīng)不夠充足,如果是的話,那么待調(diào)度 Pod 就不能被調(diào)度到該節(jié)點(diǎn)上。<
這一組規(guī)則,跟 GeneralPredicates 大多數(shù)是重合的。而比較特殊的,是 PodAffinityPredicate。這個規(guī)則的作用,是檢查待調(diào)度 Pod 與 Node 上的已有 Pod 之間的親密(affinity)和反親密(anti-affinity)關(guān)系。比如下面這個例子:
apiVersion: v1 kind: Pod metadata: name: with-pod-antiaffinity spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: security operator: In values: - S2 topologyKey: kubernetes.io/hostname containers: - name: with-pod-affinity image: docker.io/ocpqe/hello-pod
這個例子里的 podAntiAffinity 規(guī)則,就指定了這個 Pod 不希望跟任何攜帶了 security=S2 標(biāo)簽的 Pod 存在于同一個 Node 上。需要注意的是,PodAffinityPredicate 是有作用域的,比如上面這條規(guī)則,就僅對攜帶了 Key 是kubernetes.io/hostname
標(biāo)簽的 Node 有效。這正是 topologyKey 這個關(guān)鍵詞的作用。
而與 podAntiAffinity 相反的,就是 podAffinity,比如下面這個例子:
apiVersion: v1 kind: Pod metadata: name: with-pod-affinity spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: - S1 topologyKey: failure-domain.beta.kubernetes.io/zone containers: - name: with-pod-affinity image: docker.io/ocpqe/hello-pod
這個例子里的 Pod,就只會被調(diào)度到已經(jīng)有攜帶了 security=S1 標(biāo)簽的 Pod 運(yùn)行的 Node 上。而這條規(guī)則的作用域,則是所有攜帶 Key 是failure-domain.beta.kubernetes.io/zone
標(biāo)簽的 Node。
此外,上面這兩個例子里的 requiredDuringSchedulingIgnoredDuringExecution 字段的含義是:這條規(guī)則必須在 Pod 調(diào)度時進(jìn)行檢查(requiredDuringScheduling);但是如果是已經(jīng)在運(yùn)行的 Pod 發(fā)生變化,比如 Label 被修改,造成了該 Pod 不再適合運(yùn)行在這個 Node 上的時候,Kubernetes 不會進(jìn)行主動修正(IgnoredDuringExecution)。
上面這四種類型的 Predicates,就構(gòu)成了調(diào)度器確定一個 Node 可以運(yùn)行待調(diào)度 Pod 的基本策略。
在具體執(zhí)行的時候, 當(dāng)開始調(diào)度一個 Pod 時,Kubernetes 調(diào)度器會同時啟動 16 個 Goroutine,來并發(fā)地為集群里的所有 Node 計算 Predicates,最后返回可以運(yùn)行這個 Pod 的宿主機(jī)列表。
需要注意的是,在為每個 Node 執(zhí)行 Predicates 時,調(diào)度器會按照固定的順序來進(jìn)行檢查。這個順序,是按照 Predicates 本身的含義來確定的。比如,宿主機(jī)相關(guān)的 Predicates 會被放在相對靠前的位置進(jìn)行檢查。要不然的話,在一臺資源已經(jīng)嚴(yán)重不足的宿主機(jī)上,上來就開始計算 PodAffinityPredicate,是沒有實(shí)際意義的。
接下來,我們再來看一下 Priorities。
在 Predicates 階段完成了節(jié)點(diǎn)的“過濾”之后,Priorities 階段的工作就是為這些節(jié)點(diǎn)打分。這里打分的范圍是 0-10 分,得分最高的節(jié)點(diǎn)就是最后被 Pod 綁定的最佳節(jié)點(diǎn)。
Priorities 里最常用到的一個打分規(guī)則,是 LeastRequestedPriority。它的計算方法,可以簡單地總結(jié)為如下所示的公式:
score = (cpu((capacity-sum(requested))10/capacity) + memory((capacity-sum(requested))10/capacity))/2
可以看到,這個算法實(shí)際上就是在選擇空閑資源(CPU 和 Memory)最多的宿主機(jī)。
而與 LeastRequestedPriority 一起發(fā)揮作用的,還有 BalancedResourceAllocation。它的計算公式如下所示:
score = 10 - variance(cpuFraction,memoryFraction,volumeFraction)*10
其中,每種資源的 Fraction 的定義是 :Pod 請求的資源 / 節(jié)點(diǎn)上的可用資源。而 variance 算法的作用,則是計算每兩種資源 Fraction 之間的“距離”。而最后選擇的,則是資源 Fraction 差距最小的節(jié)點(diǎn)。
所以說,BalancedResourceAllocation 選擇的,其實(shí)是調(diào)度完成后,所有節(jié)點(diǎn)里各種資源分配最均衡的那個節(jié)點(diǎn),從而避免一個節(jié)點(diǎn)上 CPU 被大量分配、而 Memory 大量剩余的情況。
此外,還有 NodeAffinityPriority、TaintTolerationPriority 和 InterPodAffinityPriority 這三種 Priority。顧名思義,它們與前面的 PodMatchNodeSelector、PodToleratesNodeTaints 和 PodAffinityPredicate 這三個 Predicate 的含義和計算方法是類似的。但是作為 Priority,一個 Node 滿足上述規(guī)則的字段數(shù)目越多,它的得分就會越高。
在默認(rèn) Priorities 里,還有一個叫作 ImageLocalityPriority 的策略。它是在 Kubernetes v1.12 里新開啟的調(diào)度規(guī)則,即:如果待調(diào)度 Pod 需要使用的鏡像很大,并且已經(jīng)存在于某些 Node 上,那么這些 Node 的得分就會比較高。
當(dāng)然,為了避免這個算法引發(fā)調(diào)度堆疊,調(diào)度器在計算得分的時候還會根據(jù)鏡像的分布進(jìn)行優(yōu)化,即:如果大鏡像分布的節(jié)點(diǎn)數(shù)目很少,那么這些節(jié)點(diǎn)的權(quán)重就會被調(diào)低,從而“對沖”掉引起調(diào)度堆疊的風(fēng)險。
以上,就是 Kubernetes 調(diào)度器的 Predicates 和 Priorities 里默認(rèn)調(diào)度規(guī)則的主要工作原理了。
在實(shí)際的執(zhí)行過程中,調(diào)度器里關(guān)于集群和 Pod 的信息都已經(jīng)緩存化,所以這些算法的執(zhí)行過程還是比較快的。
此外,對于比較復(fù)雜的調(diào)度算法來說,比如 PodAffinityPredicate,它們在計算的時候不只關(guān)注待調(diào)度 Pod 和待考察 Node,還需要關(guān)注整個集群的信息,比如,遍歷所有節(jié)點(diǎn),讀取它們的 Labels。這時候,Kubernetes 調(diào)度器會在為每個待調(diào)度 Pod 執(zhí)行該調(diào)度算法之前,先將算法需要的集群信息初步計算一遍,然后緩存起來。這樣,在真正執(zhí)行該算法的時候,調(diào)度器只需要讀取緩存信息進(jìn)行計算即可,從而避免了為每個 Node 計算 Predicates 的時候反復(fù)獲取和計算整個集群的信息。
需要注意的是,除了本篇講述的這些規(guī)則,Kubernetes 調(diào)度器里其實(shí)還有一些默認(rèn)不會開啟的策略。你可以通過為 kube-scheduler 指定一個配置文件或者創(chuàng)建一個 ConfigMap ,來配置哪些規(guī)則需要開啟、哪些規(guī)則需要關(guān)閉。并且,你可以通過為 Priorities 設(shè)置權(quán)重,來控制調(diào)度器的調(diào)度行為。
感謝各位的閱讀,以上就是“k8s默認(rèn)調(diào)度器調(diào)度策略是什么意思”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對k8s默認(rèn)調(diào)度器調(diào)度策略是什么意思這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!