进击的Kubernetes调度系统(一):SchedulingFramework
作者:王慶璨 張凱
前言
Kubernetes已經(jīng)成為目前事實(shí)標(biāo)準(zhǔn)上的容器集群管理平臺(tái)。它為容器化應(yīng)用提供了自動(dòng)化部署、運(yùn)維、資源調(diào)度等全生命周期管理功能。經(jīng)過3年多的快速發(fā)展,Kubernetes在穩(wěn)定性、擴(kuò)展性和規(guī)模化方面都有了長足進(jìn)步。 尤其是Kubernetes控制平面的核心組件日臻成熟。而作為決定容器能否在集群中運(yùn)行的調(diào)度器Kube-scheduler,更是由于長久以來表現(xiàn)穩(wěn)定,且已能滿足大部分Pod調(diào)度場景,逐漸不被開發(fā)人員特別關(guān)注。
伴隨著Kubernetes在公有云以及企業(yè)內(nèi)部IT系統(tǒng)中廣泛應(yīng)用,越來越多的開發(fā)人員嘗試使用Kubernetes運(yùn)行和管理Web應(yīng)用和微服務(wù)以外的工作負(fù)載。典型場景包括機(jī)器學(xué)習(xí)和深度學(xué)習(xí)訓(xùn)練任務(wù),高性能計(jì)算作業(yè),基因計(jì)算工作流,甚至是傳統(tǒng)的大數(shù)據(jù)處理任務(wù)。此外,Kubernetes集群所管理的資源類型也愈加豐富,不僅有GPU,TPU和FPGA,RDMA高性能網(wǎng)絡(luò),還有針對(duì)領(lǐng)域任務(wù)的各種定制加速器,比如各種AI芯片,NPU,視頻編解碼器等。開發(fā)人員希望在Kubernetes集群中能像使用CPU和內(nèi)存那樣簡單地聲明式使用各種異構(gòu)設(shè)備。
總的來說,圍繞Kubernetes構(gòu)建一個(gè)容器服務(wù)平臺(tái),統(tǒng)一管理各種新算力資源,彈性運(yùn)行多種類型應(yīng)用,最終把服務(wù)按需交付到各種運(yùn)行環(huán)境(包括公共云、數(shù)據(jù)中心、邊緣節(jié)點(diǎn),甚至是終端設(shè)備),已然成為云原生技術(shù)的發(fā)展趨勢。
阿里云容器服務(wù)團(tuán)隊(duì)結(jié)合多年Kubernetes產(chǎn)品化與客戶支持經(jīng)驗(yàn),對(duì)Kube-scheduler進(jìn)行了大量擴(kuò)展和改進(jìn),逐步使其在多種場景下依然能穩(wěn)定、高效地調(diào)度復(fù)雜工作負(fù)載類型。
《進(jìn)擊的Kubernetes調(diào)度系統(tǒng)》系列文章將把我們的經(jīng)驗(yàn)、技術(shù)思考和實(shí)現(xiàn)細(xì)節(jié)全面地展現(xiàn)給Kubernetes用戶和開發(fā)者,期望幫助大家更好地了解Kubernetes調(diào)度系統(tǒng)的強(qiáng)大能力和未來發(fā)展方向。
早期方案
首先,讓我們來了解一下Kubernetes社區(qū)都有過哪些提升調(diào)度器擴(kuò)展能力的方案。
要統(tǒng)一管理和調(diào)度異構(gòu)資源與更多復(fù)雜工作負(fù)載類型,首先面對(duì)挑戰(zhàn)的就是Kube-scheduler。在Kubernetes社區(qū)里關(guān)于提升調(diào)度器擴(kuò)展能力的討論一直不斷。sig-scheduling給出的判斷是,越多功能加入,使得調(diào)度器代碼量龐大,邏輯復(fù)雜,導(dǎo)致維護(hù)的難度越來越大,很多bug難以發(fā)現(xiàn)、處理。而對(duì)于使用了自定義調(diào)度的用戶來說,跟上每一次調(diào)度器功能更新,都充滿挑戰(zhàn)。
在阿里云,我們的用戶遇到了同樣的挑戰(zhàn)。Kubernetes原生調(diào)度器循環(huán)處理單個(gè)Pod容器的固定邏輯,無法及時(shí)、簡單地支持用戶在不同場景的需求。所以針對(duì)特定的場景,我們會(huì)基于原生Kube-scheduler擴(kuò)展自己的調(diào)度策略。
最初對(duì)于Kube-scheduler進(jìn)行擴(kuò)展的方式主要有兩種,一種是調(diào)度器擴(kuò)展(Scheduler Extender), 另外一種是多調(diào)度器(Multiple schedulers)。接下來我們對(duì)這兩種方式分別進(jìn)行介紹和對(duì)比。
Scheduler Extender
社區(qū)最初提供的方案是通過Extender的形式來擴(kuò)展scheduler。Extender是外部服務(wù),支持Filter、Preempt、Prioritize和Bind的擴(kuò)展,scheduler運(yùn)行到相應(yīng)階段時(shí),通過調(diào)用Extender注冊(cè)的webhook來運(yùn)行擴(kuò)展的邏輯,影響調(diào)度流程中各階段的決策結(jié)果。
以Filter階段舉例,執(zhí)行過程會(huì)經(jīng)過2個(gè)階段:
?
?
我們可以發(fā)現(xiàn)Extender存在以下問題:
基于以上介紹,Extender的方式在集群規(guī)模較小,調(diào)度效率要求不高的情況下,是一個(gè)靈活可用的擴(kuò)展方案,但是在正常生產(chǎn)環(huán)境的大型集群中,Extender無法支持高吞吐量,性能較差。
Multiple schedulers
Scheduler在Kubernetes集群中其實(shí)類似于一個(gè)特殊的Controller,通過監(jiān)聽Pod和Node的信息,給Pod挑選最佳的節(jié)點(diǎn),更新Pod的spec.NodeName的信息來將調(diào)度結(jié)果同步到節(jié)點(diǎn)。所以對(duì)于部分有特殊的調(diào)度需求的用戶,有些開發(fā)者通過自研Custom Scheduler來完成以上的流程,然后通過和default scheduler同時(shí)部署的方式,來支持自己特殊的調(diào)度需求。
Custom Scheduler會(huì)存在一下問題:
Scheduler Extender的性能較差可是維護(hù)成本較小,Custom Scheduler的研發(fā)和維護(hù)的成本特別高但是性能較好,這種情況是開發(fā)者面臨這種兩難處境。這時(shí)候Kubernetes Scheduling Framework V2橫空出世,給我們帶來魚和熊掌可以兼得的方案。
?
新一代調(diào)度框架 Scheduling Framework之解析
社區(qū)也逐漸的發(fā)現(xiàn)開發(fā)者所面臨的困境,為了解決如上問題,使Kube-scheduler擴(kuò)展性更好、代碼更簡潔,社區(qū)從Kubernetes 1.16版本開始, 構(gòu)建了一種新的調(diào)度框架Kubernetes Scheduling Framework的機(jī)制。
Scheduling Framework在原有的調(diào)度流程中, 定義了豐富擴(kuò)展點(diǎn)接口,開發(fā)者可以通過實(shí)現(xiàn)擴(kuò)展點(diǎn)所定義的接口來實(shí)現(xiàn)插件,將插件注冊(cè)到擴(kuò)展點(diǎn)。Scheduling Framework在執(zhí)行調(diào)度流程時(shí),運(yùn)行到相應(yīng)的擴(kuò)展點(diǎn)時(shí),會(huì)調(diào)用用戶注冊(cè)的插件,影響調(diào)度決策的結(jié)果。通過這種方式來將用戶的調(diào)度邏輯集成到Scheduling Framework中。
?
Framework的調(diào)度流程是分為兩個(gè)階段scheduling cycle和binding cycle. scheduling cycle是同步執(zhí)行的,同一個(gè)時(shí)間只有一個(gè)scheduling cycle,是線程安全的。binding cycle是異步執(zhí)行的,同一個(gè)時(shí)間中可能會(huì)有多個(gè)binding cycle在運(yùn)行,是線程不安全的。
scheduling cycle
scheduling cycle是調(diào)度的核心流程,主要的工作是進(jìn)行調(diào)度決策,挑選出唯一的節(jié)點(diǎn)。
Queue sort
// QueueSortPlugin is an interface that must be implemented by "QueueSort" plugins. // These plugins are used to sort pods in the scheduling queue. Only one queue sort // plugin may be enabled at a time. type QueueSortPlugin interface {Plugin// Less are used to sort pods in the scheduling queue.Less(*PodInfo, *PodInfo) bool }Scheduler中的優(yōu)先級(jí)隊(duì)列是通過heap實(shí)現(xiàn)的,我們可以在QueueSortPlugin中定義heap的比較函數(shù)來決定的排序結(jié)構(gòu)。但是需要注意的是heap的比較函數(shù)在同一時(shí)刻只有一個(gè),所以QueueSort插件只能Enable一個(gè),如果用戶Enable了2個(gè)則調(diào)度器啟動(dòng)時(shí)會(huì)報(bào)錯(cuò)退出。下面是默認(rèn)的比較函數(shù),可供參考。
// Less is the function used by the activeQ heap algorithm to sort pods. // It sorts pods based on their priority. When priorities are equal, it uses // PodQueueInfo.timestamp. func (pl *PrioritySort) Less(pInfo1, pInfo2 *framework.QueuedPodInfo) bool {p1 := pod.GetPodPriority(pInfo1.Pod)p2 := pod.GetPodPriority(pInfo2.Pod)return (p1 > p2) || (p1 == p2 && pInfo1.Timestamp.Before(pInfo2.Timestamp)) }PreFilter
PreFilter在scheduling cycle開始時(shí)就被調(diào)用,只有當(dāng)所有的PreFilter插件都返回success時(shí),才能進(jìn)入下一個(gè)階段,否則Pod將會(huì)被拒絕掉,標(biāo)識(shí)此次調(diào)度流程失敗。PreFilter類似于調(diào)度流程啟動(dòng)之前的預(yù)處理,可以對(duì)Pod的信息進(jìn)行加工。同時(shí)PreFilter也可以進(jìn)行一些預(yù)置條件的檢查,去檢查一些集群維度的條件,判斷否滿足pod的要求。
Filter
Filter插件是scheduler v1版本中的Predicate的邏輯,用來過濾掉不滿足Pod調(diào)度要求的節(jié)點(diǎn)。為了提升效率,Filter的執(zhí)行順序可以被配置,這樣用戶就可以將可以過濾掉大量節(jié)點(diǎn)的Filter策略放到前邊執(zhí)行,從而減少后邊Filter策略執(zhí)行的次數(shù),例如我們可以把NodeSelector的Filter放到第一個(gè),從而過濾掉大量的節(jié)點(diǎn)。Node節(jié)點(diǎn)執(zhí)行Filter策略是并發(fā)執(zhí)行的,所以在同一調(diào)度周期中多次調(diào)用過濾器。
PostFilter
新的PostFilter的接口定義在1.19的版本會(huì)發(fā)布,主要是用于處理當(dāng)Pod在Filter階段失敗后的操作,例如搶占,Autoscale觸發(fā)等行為。
PreScore
PreScore在之前版本稱為PostFilter,現(xiàn)在修改為PreScore,主要用于在Score之前進(jìn)行一些信息生成。此處會(huì)獲取到通過Filter階段的節(jié)點(diǎn)列表,我們也可以在此處進(jìn)行一些信息預(yù)處理或者生成一些日志或者監(jiān)控信息。
Scoring
Scoring擴(kuò)展點(diǎn)是scheduler v1版本中Priority的邏輯,目的是為了基于Filter過濾后的剩余節(jié)點(diǎn),根據(jù)Scoring擴(kuò)展點(diǎn)定義的策略挑選出最優(yōu)的節(jié)點(diǎn)。
Scoring擴(kuò)展點(diǎn)分為兩個(gè)階段:
Reserve
Reserve擴(kuò)展點(diǎn)是scheduler v1版本的assume的操作,此處會(huì)對(duì)調(diào)度結(jié)果進(jìn)行緩存,如果在后邊的階段發(fā)生了錯(cuò)誤或者失敗的情況,會(huì)直接進(jìn)入U(xiǎn)nreserve階段,進(jìn)行數(shù)據(jù)回滾。
Permit
Permit擴(kuò)展點(diǎn)是framework v2版本引入的新功能,當(dāng)Pod在Reserve階段完成資源預(yù)留之后,Bind操作之前,開發(fā)者可以定義自己的策略在Permit節(jié)點(diǎn)進(jìn)行攔截,根據(jù)條件對(duì)經(jīng)過此階段的Pod進(jìn)行allow、reject和wait的3種操作。allow表示pod允許通過Permit階段。reject表示pod被Permit階段拒絕,則Pod調(diào)度失敗。wait表示將Pod處于等待狀態(tài),開發(fā)者可以設(shè)置超時(shí)時(shí)間。
binding cycle
binding cycle需要調(diào)用apiserver的接口,耗時(shí)較長,為了提高調(diào)度的效率,需要異步執(zhí)行,所以此階段線程不安全。
Bind
Bind擴(kuò)展點(diǎn)是scheduler v1版本中的Bind操作,會(huì)調(diào)用apiserver提供的接口,將pod綁定到對(duì)應(yīng)的節(jié)點(diǎn)上。
PreBind 和 PostBind
開發(fā)者可以在PreBind 和 PostBind分別在Bind操作前后執(zhí)行,這兩個(gè)階段可以進(jìn)行一些數(shù)據(jù)信息的獲取和更新。
UnReserve
UnReserve擴(kuò)展點(diǎn)的功能是用于清理到Reserve階段的的緩存,回滾到初始的狀態(tài)。當(dāng)前版本UnReserve與Reserve是分開定義的,未來會(huì)將UnReserve與Reserve統(tǒng)一到一起,即要求開發(fā)者在實(shí)現(xiàn)Reserve同時(shí)需要定義UnReserve,保證數(shù)據(jù)能夠有效的清理,避免留下臟數(shù)據(jù)。
實(shí)現(xiàn)自己的調(diào)度插件
scheduler-plugins
Kubernetes負(fù)責(zé)Kube-scheduler的小組sig-scheduling為了更好的管理調(diào)度相關(guān)的Plugin,新建了項(xiàng)目scheduler-plugins?來方便用戶管理不同的插件,用戶可以直接基于這個(gè)項(xiàng)目來定義自己的插件。接下來我們以其中的Qos的插件來為例,演示是如何開發(fā)自己的插件。
QoS的插件主要基于Pod的?QoS(Quality of Service) class?來實(shí)現(xiàn)的,目的是為了實(shí)現(xiàn)調(diào)度過程中如果Pod的優(yōu)先級(jí)相同時(shí),根據(jù)Pod的Qos來決定調(diào)度順序,調(diào)度順序是: 1. Guaranteed (requests == limits) 2. Burstable (requests < limits) 3. BestEffort (requests and limits not set)
插件構(gòu)造
首先插件要定義插件的對(duì)象和構(gòu)造函數(shù)
// QoSSort is a plugin that implements QoS class based sorting. type Sort struct{}// New initializes a new plugin and returns it. func New(_ *runtime.Unknown, _ framework.FrameworkHandle) (framework.Plugin, error) {return &Sort{}, nil }然后,根據(jù)我們插件要對(duì)應(yīng)的extention point來實(shí)現(xiàn)對(duì)應(yīng)的接口,Qos是作用于QueueSort的部分,所以我們要實(shí)現(xiàn)QueueSort接口的函數(shù)。如下所示,QueueSortPlugin接口只定義了一個(gè)函數(shù)Less,所以我們實(shí)現(xiàn)這個(gè)函數(shù)即可。
// QueueSortPlugin is an interface that must be implemented by "QueueSort" plugins. // These plugins are used to sort pods in the scheduling queue. Only one queue sort // plugin may be enabled at a time. type QueueSortPlugin interface {Plugin// Less are used to sort pods in the scheduling queue.Less(*PodInfo, *PodInfo) bool }實(shí)現(xiàn)的函數(shù)如下。默認(rèn)的default QueueSort在比較的時(shí)候,首先比較優(yōu)先級(jí),然后再比較pod的timestamp。我們重新定義了Less函數(shù),在優(yōu)先級(jí)相同的情況下,通過比較Qos來決定優(yōu)先級(jí)。
// Less is the function used by the activeQ heap algorithm to sort pods. // It sorts pods based on their priority. When priorities are equal, it uses // PodInfo.timestamp. func (*Sort) Less(pInfo1, pInfo2 *framework.PodInfo) bool {p1 := pod.GetPodPriority(pInfo1.Pod)p2 := pod.GetPodPriority(pInfo2.Pod)return (p1 > p2) || (p1 == p2 && compQOS(pInfo1.Pod, pInfo2.Pod)) }func compQOS(p1, p2 *v1.Pod) bool {p1QOS, p2QOS := v1qos.GetPodQOS(p1), v1qos.GetPodQOS(p2)if p1QOS == v1.PodQOSGuaranteed {return true} else if p1QOS == v1.PodQOSBurstable {return p2QOS != v1.PodQOSGuaranteed} else {return p2QOS == v1.PodQOSBestEffort} }插件注冊(cè)
我們?cè)趩?dòng)的main函數(shù)中注冊(cè)自己定義的插件和相應(yīng)的構(gòu)造函數(shù)
// cmd/main.go func main() {rand.Seed(time.Now().UnixNano())command := app.NewSchedulerCommand(app.WithPlugin(qos.Name, qos.New),)if err := command.Execute(); err != nil {os.Exit(1)} }代碼編譯
$ makeScheduler啟動(dòng)
kube-scheduler啟動(dòng)時(shí),配置./manifests/qos/scheduler-config.yaml中kubeconfig的路徑,啟動(dòng)時(shí)傳入集群的kubeconfig文件以及插件的配置文件即可。
$ bin/kube-scheduler --kubeconfig=scheduler.conf --config=./manifests/qos/scheduler-config.yaml至此,相信大家已經(jīng)通過我們的介紹和示例了解了Kubernetes Scheduling Framework的架構(gòu)和開發(fā)方法。
后續(xù)工作
Kubernetes Scheduling Framework作為調(diào)度器的新架構(gòu)方向,在可擴(kuò)展性和定制化方面進(jìn)步很大。基于此Kubernetes可以逐步承載更多類型的應(yīng)用負(fù)載了, 一個(gè)平臺(tái)一套IT架構(gòu)和技術(shù)堆棧的愿景向前演進(jìn)。同時(shí)為了更好的支持?jǐn)?shù)據(jù)計(jì)算類型的任務(wù)遷移到Kubernetes平臺(tái)中,我們也在努力將數(shù)據(jù)計(jì)算類型中常用Coscheduling/Gang Scheduling、Capacity Scheduling、Dominant Resource Fairness和多隊(duì)列管理等特性,通過Scheduling Framework的插件機(jī)制來融入到原生的Kube-scheduler中。
接下來,本系列文章將圍繞AI、大數(shù)據(jù)處理和高規(guī)格計(jì)算資源集群等場景,介紹我們是如何開發(fā)相應(yīng)調(diào)度器插件的。敬請(qǐng)期待。
原文鏈接
本文為云棲社區(qū)原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。
總結(jié)
以上是生活随笔為你收集整理的进击的Kubernetes调度系统(一):SchedulingFramework的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: “新基建”提速,工业互联网大数据发展迎新
- 下一篇: 万师傅使用云产品,上手简单、开箱即用、省