Kubernetes調度由淺入深:框架

今天zouyee先帶各位盤點CNCF上週的一些有趣的事情:node

  1. Kubernetes社區GB表明選舉結束 Paris Pittman當選git

  2. CNCF孵化項目OPA進入畢業流程github

  3. 上週helm項目發佈v3.5.0功能性版本web

  4. CoreDNS項目經過Docker鏡像倉庫放開拉取限制的申請算法

書接上文《Kubernetes調度系統由淺入深系列:初探》,今天zouyee爲你們帶來《kuberneter調度由淺入深:框架》,該系列對應版本爲1.20.+.api


1、前文回顧

在《Kubernetes調度系統由淺入深系列:初探》中,給出總體的交互圖,來構建Pod調度的直觀感覺,咱們拓展了一下交互圖,以下所示。緩存

注:該交互圖非專業UML,還請諒解。安全

圖1 交互流程圖

上述以建立一個Pod爲例,簡要介紹調度流程:markdown

  1. 用戶經過命令行建立Pod(選擇直接建立Pod而不是其餘workload,是爲了省略kube-controller-manager)網絡

  2. kube-apiserver通過對象校驗、admission、quota等准入操做,寫入etcd

  3. kube-apiserver將結果返回給用戶

  4. 同時kube-scheduler一直監聽節點、Pod事件等(流程1)

  5. kube-scheduler將spec.nodeName的pod加入到調度隊列中,調度系統選擇pod,進入調度週期(本文介紹內容)(流程2-3)

  6. kube-scheduler將pod與得分最高的節點進行binding操做(流程4)

  7. kube-apiserver將binding信息寫入etcd

  8. kubelet監聽分配給本身的Pod,調用CRI接口進行Pod建立(該部份內容後續出系列,進行介紹)

  9. kubelet建立Pod後,更新Pod狀態等信息,並向kube-apiserver上報

  10. kube-apiserver寫入數據

2、框架背景

​ Kubernetes 隨着功能的增多,代碼與邏輯也日益複雜。代碼體量及複雜度的提高必然帶來維護成本的增長,隱形的增長錯誤定位和修復的難度。舊版本的Kubernetes調度程序(1.16前)提供了webhooks進行擴展。但有如下缺陷:

  • 用戶能夠擴展的點比較有限,位置比較固定,沒法支持靈活的擴展與調配,例如只能在執行完默認的 Filter 策略後才能調用。

  • 調用擴展接口使用 HTTP 請求,其受到網絡影響,性能遠低於本地的函數調用。同時每次調用都須要將 Pod 和 Node 的信息進行 序列化與反序列化 操做,會進一步下降性能。

  • Pod當前的相關信息,沒法及時傳遞(利用調度Cache)。

爲了解決上述問題,使調度系統代碼精簡、擴展性更好,社區從 Kubernetes 1.16 版本開始, 引入了一種新的調度框架- Scheduling Framework 。

Scheduling Framework 在原有調度流程的基礎之上, 定義了豐富的擴展點接口,開發者能夠經過實現擴展點所定義的接口來實現插件,將插件註冊到擴展點。Scheduling Framework 在執行調度流程時,運行到相應的擴展點時,執行用戶註冊的插件,生成當前階段的結果。經過這種方式來將用戶的調度邏輯集成到 Scheduling Framework 中。Scheduling Framework明確瞭如下目標:

  • 擴展性:調度更具擴展性
  • 維護性:將調度器的一些特性移到插件中
  • 功能性
    • 框架提供擴展
    • 提供一種機制來接收插件結果並根據接收到的結果繼續或終止
    • 提供一種機制處理錯誤與插件通訊
3、框架原理

​ Framework 的調度流程是分爲兩個階段:

  • 調度階段是同步執行的,同一個週期內只有一個 scheduling cycle,線程安全
  • 綁定階段(gouroutine)是異步執行的,同一個週期內可能會有多個 binding cycle在運行,線程不安全

在介紹Framework 的調度流程以前,先介紹上圖的調度流程,即schedulerOne的處理邏輯:

a. 調度階段

1. **過濾**操做即findNodesThatFitPod函數
 - 執行PreFilterPlugins
 - 執行FilterPlugins
 - 執行擴展 Filter
 - 若出現FitError,執行PostFilter
2. **評分**操做即prioritizeNodes函數
 	- 執行PreScorePlugins
 	- 執行ScorePlugins
 	- 執行擴展Prioritize
3. 挑選節點即select函數(符合條件節點,按照評分排序及採樣選擇)
4. 節點預分配即assume(只是預先分配,可收回)
5. 相關調度數據緩存即RunReservePlugins,從該節點開始,後續階段發生錯誤,須要調用UnReserve,進行回滾(相似事務)
6.  執行准入操做即RunPermitPlugins
複製代碼

b. 綁定階段

1. 執行WaitOnPermit,失敗時調用RunReservePluginsUnreserve
2. 執行預綁定即RunPreBindPlugins,失敗時調用RunReservePluginsUnreserve
3. 執行擴展bingding即extendersBinding,失敗時調用RunReservePluginsUnreserve
4. 執行綁定收尾工做即RunPostBindPlugins
複製代碼
擴展點介紹

上述涉及到的各種Plugins(圖中紫色部分),針對下圖,各位應該看了不少篇了,須要注意的是Unreserve的時機,各插件功能說明以下:

pkg/scheduler/framework/interface.go

擴展點 用途說明
QueueSort 用來支持自定義 Pod 的排序。若是指定 QueueSort 的排序算法,在調度隊列裏面就會按照指定的排序算法來進行排序,只能enable一個
Prefilter 對 Pod 信息的預處理,好比 Pod 的緩存等
Filter 對應舊式的Predicate ,過濾不知足要求的節點
PostFilter 用於處理當 Pod 在 Filter 階段失敗後的操做,例如搶佔等行爲
PreScore 用於在 Score 以前進行一些信息生成,也能夠在此處生成一些日誌或者監控信息
Score 對應舊式的Priority,根據 擴展點定義的評分策略挑選出最優的節點(打分與歸一化處理)
Reserver 調度階段的最後一個插件, 防止調度成功後資源的競爭, 確保集羣的資源信息的準確性
Permit 主要提供了Pod綁定的攔截功能,根據條件對pod進行allow、reject或者wait。
PreBind 在真正 bind node 以前,執行一些操做
Bind 一個 Pod 只會被一個 BindPlugin 處理,建立Bind對象
PostBind bind 成功以後執行的邏輯
Unreserve 在 Permit 到 Bind 這幾個階段只要報錯就回滾數據至初始狀態,相似事務。
4、使用場景

​ 下述爲一些關於如何使用調度框架來解決常見調度場景的示例。

  1. 聯合調度

    相似kube-batch,容許調度以必定數量的Pod爲總體的任務。其可以將一個訓練任務的多個worker當作一個總體進行調度,只有當任務全部worker的資源都知足,纔會將容器在節點上啓動。

  2. 集羣資源的動態綁定

    Volume topology-aware調度能夠經過filter和prebind方式實現。

  3. 調度拓展

    該框架容許自定義插件,以main函數封裝scheduler方式運行。

關於框架部分,該文就介紹到此處,接下里將進入源碼階段,後續內容爲調度配置及第三方調度集成的相關內容,敬請關注。

後續相關內容,請查看公衆號:DCOS

5、參考資料
1. https://kubernetes.io/docs/concepts/scheduling-eviction/kube-scheduler/
2. https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/
3. https://github.com/kubernetes/enhancements/blob/master/keps/sig-scheduling/624-scheduling-framework/README.md
複製代碼
相關文章
相關標籤/搜索