k8s學習筆記-調度介紹


一:概述

一個容器平台的主要功能就是為容器分配運行時所需要的計算,存儲和網絡資源。容器調度系統負責選擇在最合適的主機上啟動容器,並且將它們關聯起來。

它必須能夠自動的處理容器故障並且能夠在更多的主機上自動啟動更多的容器來應對更多的應用訪問。

目前三大主流的容器平台Swarm, Mesos和Kubernetes具有不同的容器調度系統。

1.Swarm的特點是直接調度Docker容器,並且提供和標准Docker API一致的API。

2.Mesos針對不同的運行框架采用相對獨立的調度系統,其中Marathon框架提供了Docker容器的原生支持。

3.Kubernetes則采用了Pod和Label這樣的概念把容器組合成一個個的互相存在依賴關系的邏輯單元。相關容器被組合成Pod后被共同部署和調度,形成服務(Service)。

這個是Kubernetes和Swarm,Mesos的主要區別。

相對來說,Kubernetes采用這樣的方式簡化了集群范圍內相關容器被共同調度管理的復雜性。換一種角度來看,Kubernetes采用這種方式能夠相對容易的支持更強大,更復雜的容器調度算法。

二:K8S 調度工作方式

Kubernetes調度器作為集群的大腦,在如何提高集群的資源利用率、保證集群中服務的穩定運行中也會變得越來越重要

Kubernetes的資源分為兩種屬性。

1.可壓縮資源(例如CPU循環,Disk I/O帶寬)都是可以被限制和被回收的,對於一個Pod來說可以降低這些資源的使用量而不去殺掉Pod。

2.不可壓縮資源(例如內存、硬盤空間)一般來說不殺掉Pod就沒法回收。未來Kubernetes會加入更多資源,如網絡帶寬,存儲IOPS的支持。

Kubernets調度器

Scheduler調度器做為Kubernetes三大核心組件之一, 承載着整個集群資源的調度功能,其根據特定調度算法和策略,將Pod調度到最優工作節點上,從而更合理與充分的利用集群計算資源。

其作用是根據特定的調度算法和策略將Pod調度到指定的計算節點(Node)上,其做為單獨的程序運行,啟動之后會一直監聽API Server,獲取PodSpec.NodeName為空的Pod,對每個Pod都會創建一個綁定。

默認情況下,k8s的調度器采用擴散策略,將同一集群內部的pod對象調度到不同的Node節點,以保證資源的均衡利用。

 

首先用戶通過 Kubernetes 客戶端 Kubectl 提交創建 Pod 的 Yaml 的文件,向Kubernetes 系統發起資源請求,該資源請求被提交到
Kubernetes 系統中,用戶通過命令行工具 Kubectl 向 Kubernetes 集群即 APIServer 用 的方式發送“POST”請求,即創建 Pod 的請求。
APIServer 接收到請求后把創建 Pod 的信息存儲到 Etcd 中,從集群運行那一刻起,資源調度系統 Scheduler 就會定時去監控 APIServer
通過 APIServer 得到創建 Pod 的信息,Scheduler 采用 watch 機制,一旦 Etcd 存儲 Pod 信息成功便會立即通知APIServer,
APIServer會立即把Pod創建的消息通知Scheduler,Scheduler發現 Pod 的屬性中 Dest Node 為空時(Dest Node=””)便會立即觸發調度流程進行調度。
而這一個創建Pod對象,在調度的過程當中有3個階段:節點預選、節點優選、節點選定,從而篩選出最佳的節點

  • 節點預選:基於一系列的預選規則對每個節點進行檢查,將那些不符合條件的節點過濾,從而完成節點的預選
  • 節點優選:對預選出的節點進行優先級排序,以便選出最合適運行Pod對象的節點
  • 節點選定:從優先級排序結果中挑選出優先級最高的節點運行Pod,當這類節點多於1個時,則進行隨機選擇

Kubernetes調度器使用Predicates和Priorites來決定一個Pod應該運行在哪一個節點上。

Predicates是強制性規則,用來形容主機匹配Pod所需要的資源,如果沒有任何主機滿足該Predicates, 則該Pod會被掛起,直到有主機能夠滿足。

 

 

1.預選環節:

源碼參考:https://github.com/erlonglong/kubernetes/blob/master/pkg/scheduler/algorithm/predicates/predicates.go

通過組合多個函數可以完成一條可擴展的過濾器鏈。目前k8s中已注冊的過濾器函數如下:

  • CheckNodeCondition:檢查是否可以在節點報告磁盤、網絡不可用或未准備好的情況下將Pod對象調度其上。
  • HostName:如果Pod對象擁有spec.hostname屬性,則檢查節點名稱字符串是否和該屬性值匹配。
  • PodFitsHostPorts:如果Pod對象定義了ports.hostPort屬性,則檢查Pod指定的端口是否已經被節點上的其他容器或服務占用。
  • MatchNodeSelector:如果Pod對象定義了spec.nodeSelector屬性,則檢查節點標簽是否和該屬性匹配。
  • NoDiskConflict:檢查Pod對象請求的存儲卷在該節點上可用。
  • PodFitsResources:檢查節點上的資源(CPU、內存)可用性是否滿足Pod對象的運行需求。
  • PodToleratesNodeTaints:如果Pod對象中定義了spec.tolerations屬性,則需要檢查該屬性值是否可以接納節點定義的污點(taints)。
  • PodToleratesNodeNoExecuteTaints:如果Pod對象定義了spec.tolerations屬性,檢查該屬性是否接納節點的NoExecute類型的污點。
  • CheckNodeLabelPresence:僅檢查節點上指定的所有標簽的存在性,要檢查的標簽以及其可否存在取決於用戶的定義。
  • CheckServiceAffinity:根據當前Pod對象所屬的Service已有其他Pod對象所運行的節點調度,目前是將相同的Service的Pod對象放在同一個或同一類節點上。
  • MaxEBSVolumeCount:檢查節點上是否已掛載EBS存儲卷數量是否超過了設置的最大值,默認值:39
  • MaxGCEPDVolumeCount:檢查節點上已掛載的GCE PD存儲卷是否超過了設置的最大值,默認值:16
  • MaxAzureDiskVolumeCount:檢查節點上已掛載的Azure Disk存儲卷數量是否超過了設置的最大值,默認值:16
  • CheckVolumeBinding:檢查節點上已綁定和未綁定的PVC是否滿足Pod對象的存儲卷需求。
  • NoVolumeZoneConflct:在給定了區域限制的前提下,檢查在該節點上部署Pod對象是否存在存儲卷沖突。
  • CheckNodeMemoryPressure:在給定了節點已經上報了存在內存資源壓力過大的狀態,則需要檢查該Pod是否可以調度到該節點上。
  • CheckNodePIDPressure:如果給定的節點已經報告了存在PID資源壓力過大的狀態,則需要檢查該Pod是否可以調度到該節點上。
  • CheckNodeDiskPressure:如果給定的節點存在磁盤資源壓力過大,則檢查該Pod對象是否可以調度到該節點上。
  • MatchInterPodAffinity:檢查給定的節點能否可以滿足Pod對象的親和性和反親和性條件,用來實現Pod親和性調度或反親和性調度。

在上面的這些預選策略里面,CheckNodeLabelPressure和CheckServiceAffinity可以在預選過程中結合用戶自定義調度邏輯,這些策略叫做可配置策略。其他不接受參數進行自定義配置的稱為靜態策略。

2.優先環節:

通過上面的預選如果調度器發現有多個主機滿足條件,那么Priorities就用來判斷哪一個主機最適合運行Pod。Priorities是一個鍵值對,key表示名稱,value表示權重

通過某種策略進行可用節點的評分,最終選出最優節點

源碼位置:https://github.com/erlonglong/kubernetes/tree/master/pkg/scheduler/algorithm/priorities

用一組優先級函數處理每一個通過預選的節點,每一個優先級函數會返回一個0-10的分數,分數越高表示節點越優, 同時每一個函數也會對應一個表示權重的值。

它首先將每個優選函數的計算得分乘以權重,然后再將所有優選函數的得分相加,從而得出節點的最終優先級分值。權重可以讓管理員定義優選函數傾向性的能力,其計算優先級的得分公式如下:
finalScoreNode = (weight1 * priorityFunc1) + (weight2 * priorityFunc2) + … + (weightn * priorityFuncn)


示例:假設有個節點nodeA,有兩個打分函數priorityFunc1、priorityFunc2(每個方法都能返回一個score),兩個方法分別都有權重因子weight1、weight2。

則nodeA的總分為:finalScoreNodeA = (weight1 * priorityFunc1) + (weight2 * priorityFunc2)

下面是優先函數

詳細說明:

LeastRequestedPriority:

節點的優先級就由節點空閑資源與節點總容量的比值,即由(總容量-節點上Pod的容量總和-新Pod的容量)/總容量)來決定。
CPU和內存具有相同權重,資源空閑比越高的節點得分越高。
cpu((capacity – sum(requested)) * 10 / capacity) + memory((capacity – sum(requested)) * 10 / capacity) / 2
BalancedResourceAllocation:
CPU和內存使用率越接近的節點權重越高,該策略不能單獨使用,必須和LeastRequestedPriority組合使用,盡量選擇在部署Pod后各項資源更均衡的機器。
如果請求的資源(CPU或者內存)大於節點的capacity,那么該節點永遠不會被調度到。
InterPodAffinityPriority:
通過迭代 weightedPodAffinityTerm 的元素計算和,並且如果對該節點滿足相應的PodAffinityTerm,則將 “weight” 加到和中,具有最高和的節點是最優選的。 `
SelectorSpreadPriority:
為了更好的容災,對同屬於一個service、replication controller或者replica的多個Pod副本,盡量調度到多個不同的節點上。
如果指定了區域,調度器則會盡量把Pod分散在不同區域的不同節點上。當一個Pod的被調度時,會先查找Pod對於的service或者replication controller,
然后查找service或replication controller中已存在的Pod,運行Pod越少的節點的得分越高。
NodeAffinityPriority:
親和性機制。Node Selectors(調度時將pod限定在指定節點上),
支持多種操作符(In, NotIn, Exists, DoesNotExist, Gt, Lt),而不限於對節點labels的精確匹配。
另外支持兩種類型的選擇器,一種是“hard(requiredDuringSchedulingIgnoredDuringExecution)”選擇器,
它保證所選的主機必須滿足所有Pod對主機的規則要求。
這種選擇器更像是之前的nodeselector,在nodeselector的基礎上增加了更合適的表現語法。
另一種是“soft(preferresDuringSchedulingIgnoredDuringExecution)”選擇器,
它作為對調度器的提示,調度器會盡量但不保證滿足NodeSelector的所有要求。
NodePreferAvoidPodsPriority(權重1W):
如果 節點的 Anotation 沒有設置 key-value:scheduler. alpha.kubernetes.io/ preferAvoidPods = "...",則節點對該 policy 的得分就是10分,
加上權重10000,那么該node對該policy的得分至少10W分。如果Node的Anotation設置了,
scheduler.alpha.kubernetes.io/preferAvoidPods = "..." ,如果該 pod 對應的 Controller 是 ReplicationController 或 ReplicaSet,
則該 node 對該 policy 的得分就是0分。
TaintTolerationPriority :
使用 Pod 中 tolerationList 與 節點 Taint 進行匹配,配對成功的項越多,則得分越低。
ImageLocalityPriority:
根據Node上是否存在一個pod的容器運行所需鏡像大小對優先級打分,分值為0-10。遍歷全部Node,
如果某個Node上pod容器所需的鏡像一個都不存在,分值為0;
如果Node上存在Pod容器部分所需鏡像,則根據這些鏡像的大小來決定分值,鏡像越大,分值就越高;如果Node上存在pod所需全部鏡像,分值為10。
EqualPriority :
是一個優先級函數,它給予所有節點相等權重。
MostRequestedPriority :
在 ClusterAutoscalerProvider 中,替換 LeastRequestedPriority,給使用多資源的節點,更高的優先級。
計算公式為:(cpu(10 sum(requested) / capacity) + memory(10 sum(requested) / capacity)) / 2

 進一步總結:

Predicates階段回答“能不能”的問題:首先遍歷全部節點,過濾掉不滿足條件的節點,這一階段輸出的所有滿足要求的Node將被記錄並作為第二階段的輸入。
Priorities階段是回答“哪個更適合的問題”:即再次對節點進行篩選,篩選出最適合運行Pod的節點。
如果在預選(Predicates)過程中,如果所有的節點都不滿足條件,Pod 會一直處在Pending 狀態,直到有節點滿足條件,這期間調度器會不斷的重試。經過節點過濾后,如多個節點滿足條件,會按照節點優先級(priorities)大小對節點排序,最后選擇優先級最高的節點部署Pod

調度過程的簡單圖示如下:

 

 要想獲得所有節點最終的權重分值,就要先計算每個優先級函數對應該節點的分值,然后計算總和。因此不管過程如何,如果有 N 個節點,M 個優先級函數,一定會計算 M*N 個中間值,構成一個二維表格:

 

 最后,會把表格中按照節點把優先級函數的權重列表相加,得到最終節點的分值。上面代碼就是這個過程,中間過程可以並發計算(下文圖中的workQueue),以加快速度。

 參考文檔:

https://www.kubernetes.org.cn/1613.html

http://dockone.io/article/2885

http://dockone.io/article/8854



 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM