如何定製Kubernetes調度算法?

語言: CN / TW / HK

隨着雲計算和容器技術的發展,以Docker為核心的容器技術迅速在開發者和科技公司中應用,Kubernetes憑藉豐富的企業級、生產級功能成為事實上的容器集羣管理系統。可是Kubernetes的 通用性 削弱了調度算法的 定製性 ,本文將調研定製化調度算法的方法,並且給出一個開源實現。

Kubernetes與調度器架構

圖1是Kubernetes的整體架構圖,集羣節點分為兩種角色: Master節點Node節點 。Master節點是整個集羣的管理中心,負責集羣管理、容器調度、狀態存儲等組件都運行在Master節點上;Node節點是實際上的工作節點,負責運行具體的容器。

圖1 Kubernetes整體架構

Kubernetes調度器是獨立運行的進程,內部運行過程從邏輯上可以分為多個模塊。圖2展示了默認調度器內部包含的具體模塊,配置模塊負責讀取調度器相關配置信息,並且根據配置內容初始化調度器。

  • 優先隊列模塊是一個優先堆數據結構,負責將待調度Pod根據優先級排序,優先級高的Pod排在前面,調度器會輪詢優先隊列, 當隊列中存在待調度Pod時就會執行調度過程
  • 調度模塊由 算法模塊Node緩存調度擴展點 三部分組成,算法模塊提供對Node進行評分的一系列基礎算法,比如均衡節點CPU和內存使用率的NodeResourcesBalancedAllocation算法,算法模塊是可擴展的,用户可以修改和添加自己的調度算法;Node緩存模塊負責緩存集羣節點的最新狀態數據,為調度算法提供數據支撐;調度擴展點由一系列擴展點構成,每個擴展點負責不同的功能,最重要的擴展點是Filter、Score和Bind這三個擴展點。
  • 最後是綁定模塊,負責將調度器選擇的Node和Pod綁定在一起。

圖2 Kubernetes調度器架構

Kubernetes調度器代碼採用可插拔的插件化設計思路,包括核心部分和可插拔部分。圖2中的配置模塊、優先隊列和Node緩存是核心部分,算法模塊、調度擴展點屬於可插拔部分。 這種插件化設計允許調度器一些功能通過插件的方式實現,方便代碼修改和功能擴展,同時保持調度器核心代碼簡單可維護

圖3列出了調度器擴展點模塊中包含的具體擴展點。Pod的調度過程分為 調度週期綁定週期 ,調度和綁定週期共同構成Pod的調度上下文。調度上下文由一系列擴展點構成,每個擴展點負責一部分功能,最重要的擴展點是調度週期中的預選(Filter)和優選(Score)擴展點和綁定週期中的綁定(Bind)擴展點。

預選擴展點負責判斷每個節點是否能夠滿足Pod的資源需求,不滿足就過濾掉該節點。優選擴展點部分會對每個Pod運行默認的評分算法,並且將最終評分加權彙總,得到最後所有節點的綜合評分;調度器會選擇綜合評分最高的節點,如果有多個節點評分相同且最高,調度器會通過 水塘採樣算法 在多個節點中隨機選擇一個作為調度結果,然後將該節點上Pod申請的資源用量進行保留操作,防止被其它Pod使用。在綁定週期中,調度器將Pod綁定到評分最高的節點上,這一步本質是修改Pod對象中節點相關的信息,並且更新到存儲組件etcd中。

圖3 Kubernetes調度器擴展點架構

定製化算法方案

如果要實現自定義調度算法,主要有三種方案:

  1. 修改默認調度器的源代碼,加入自己的調度算法,然後重新編譯和部署調度器,論文 kcsskubecg 中的調度器研究基於此方案實現;
  2. 開發自己的調度器,和默認調度器同時運行在集羣中;
  3. 基於 Kubernetes Scheduler Extender機制 ,在擴展調度器中實現自定義算法,論文 dynamic IO 中的算法實現基於這種方案。

上述三種自定義調度算法實現方案的優缺點見表1。綜合來講:

  • 方案1改動最小,但是這樣做會破壞開源軟件的可維護性,當Kubernetes主幹代碼更新時,改動後的調度器要和上游代碼保持一致, 這會帶來大量的維護和測試工作
  • 方案2是實現自己的調度器,並且在集羣中運行多個調度器,多個調度器之間沒有集羣資源數據同步,存在併發調度數據競爭和數據不一致的問題。
  • 方案3需要默認調度器通過API和Extender交互,新增的網絡請求會增加整個調度過程的耗時。

表1 自研調度算法方案對比:

本文的調度器實現採用方案3,設計並開發符合Scheduler Extender機制和API規範的擴展調度器,將其命名為 Liang 。代碼1是擴展調度器JOSN格式的策略配置文件,通過配置文件參數將該策略文件傳遞給Kubernetes默認調度器,其中urlPrefix表示擴展調度器Liang運行後監聽的API地址,prioritizeVerb表示優選擴展點在擴展調度器中的路由。當默認調度器在優選擴展點運行完評分插件後會發送HTTP POST網絡請求到Liang的API地址,並將Pod和候選節點信息放在HTTP Body中一起傳遞過去。接收到POST請求後,擴展調度器Liang會根據評分算法對節點進行評分並將結果返回給默認調度器。

{  

"kind": "Policy",  

"apiVersion": "v1",  

"extenders": [  

    {  

        "urlPrefix": "http://localhost:8000/v1",  

        "prioritizeVerb": "prioritizeVerb",  

        "weight": 1,  

        "enableHttps": false,  

        "httpTimeout": 1000000000,  

        "nodeCacheCapable": true,  

        "ignorable": false  

    }  

]  

} 

代碼1

圖4是帶擴展的默認調度器(kube-scheduler)啟動過程,通過kube-policy.json配置文件將擴展調度器Liang的配置信息吿訴默認調度器。

圖4 擴展調度器通過配置文件傳遞給默認調度器啟動

擴展調度器Liang

擴展調度器Liang獨立於Kubernetes默認調度器,Liang的模塊設計和組織架構如圖5所示,包括多維資源採集存儲和API服務兩大部分。多維資源數據採集通過在集羣中運行Prometheus和node-exporter實現,擴展調度器Liang負責從Prometheus獲取多維指標然後運用調度算法,將結果返回給默認調度器。

圖5 擴展調度器Liang整體架構

  1. API Server模塊,負責實現符合擴展調度器數據格式和傳輸規範的API接口,Liang接收到Kubernetes的評分請求後,解析得到請求中的Pod和候選節點信息,作為參數傳遞給內部的調度算法,得到候選節點的評分結果並返回給默認調度器。
  2. 調度算法模塊,擴展調度器Liang的核心模塊,負責實現自定義的調度算法。得益於擴展調度器機制,Liang中可以實現多個自定義調度算法。本文主要設計並實現了BNP和CMDN兩個調度算法。
  3. 數據緩存模塊,主要功能有兩個:
    1. 通過請求Prometheus的API得到整個Kubernetes集羣中所有節點的狀態數據。
    2. 實現基於內存的指標數據緩存機制,提供指標數據的寫入和讀取接口,提高算法運行時獲取多維指標數據的速度。

Liang使用Go語言開發,代碼量約3400行,Liang開源地址: https://github.com/adolphlwq/liang

表2是擴展調度器是否使用緩存機制和默認調度器做出調度決策的耗時對比,調度耗時通過在Kubernetes調度器源代碼中打印時間戳的方式獲取,分別運行9次然後計算平均值。從表2中可以看到,默認調度器做出調度決策的耗時非常小,不到1ms。加上擴展調度器和緩存機制的情況下,平均調度決策耗時為4.439ms,比默認調度器增加了約3ms,增加的時間主要是默認調度器與擴展調度器Liang之間網絡請求耗時以及Liang運行調度算法所需的時間。

當擴展調度器不加緩存機制時,每次做出調度決策的平均耗時為1110.439ms,調度耗時迅速增加超過100倍,主要是每次做出調度決策都要請求Prometheus計算和獲取集羣中的指標數據。因此,擴展調度器加上緩存機制可以避免請求Prometheus帶來的網絡請求時間,降低擴展調度器的決策時間,提升了擴展調度器的性能。

表2 不同調度器架構決策耗時

BNP算法

BNP算法在Liang中實現,它將網絡IO使用情況納入KKubernetes調度算法的考量,能夠均衡集羣中的網絡IO用量。

圖6是實驗中默認調度算法和BNP算法中,整個集羣中網絡IO資源的變化情況,每部署一個Pod統計一次數據,共部署九個Pod。可以明顯看到,BNP實驗中網絡IO資源要比默認調度算法分配更均衡。

圖6 BNP算法網絡IO使用率變化情況

CMDN算法

CMDN算法在Liang中實現,它的目標是讓集羣中的多維資源分配更加均衡或者更加緊湊,核心步驟是針對CPU、內存、磁盤IO和網絡IO以及網卡帶寬這五個指標進行綜合排序,選擇最佳Node部署Pod。圖7是實驗中CPU使用率變化對比情況,可以明顯看到,CMDN均衡策略下CPU使用率均衡程度要比默認調度算法分配更均衡。

圖7 CMDN算法均衡策略下CPU使用率變化情況

總結

Kubernetes調度算法的通用性削弱了算法的定製性。本文研究了Kubernetes調度器架構和擴展機制,對比了三種定製化調度算法方案,選擇擴展方案實現 擴展調度器Liang ,並在Liang中實現了兩個調度算法BNP和CMDN用於展示定製化算法能力。

擴展方案極大豐富了定製化調度算法的能力,可以滿足非常多定製化場景的需求。同時也需要注意,定製調度算法往往需要更多的數據,這就需要在Kubernetes集羣中額外部署數據採集模塊,增加了運維成本,降低了定製化調度算法的通用性。

原文鏈接: https://mp.weixin.qq.com/s/-n4MgcsK38XaCOIk8p7sig