欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go語言開發(fā)kube-scheduler整體架構(gòu)深度剖析

 更新時(shí)間:2023年04月23日 11:25:44   作者:俯仰之間  
這篇文章主要為大家介紹了Go語言開發(fā)kube-scheduler整體架構(gòu)深度剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

k8s 的調(diào)度器 kube-scheduler

kube-scheduler 作為 k8s 的調(diào)度器,就好比人的大腦,將行動(dòng)指定傳遞到手腳等器官,進(jìn)而執(zhí)行對應(yīng)的動(dòng)作,對于 kube-scheduler 則是將 Pod 分配(調(diào)度)到集群內(nèi)的各個(gè)節(jié)點(diǎn),進(jìn)而創(chuàng)建容器運(yùn)行進(jìn)程,對于k8s來說至關(guān)重要。

為了深入學(xué)習(xí) kube-scheduler,本系從源碼和實(shí)戰(zhàn)角度深度學(xué) 習(xí)kube-scheduler,該系列一共分6篇文章,如下:

  • kube-scheduler 整體架構(gòu)
  • 初始化一個(gè) scheduler
  • 一個(gè) Pod 是如何被調(diào)度的
  • 如何開發(fā)一個(gè)屬于自己的scheduler插件
  • 開發(fā)一個(gè) prefilter 擴(kuò)展點(diǎn)的插件
  • 開發(fā)一個(gè) socre 擴(kuò)展點(diǎn)的插件

本篇先熟悉 kube-scheduler 的整體架構(gòu)設(shè)計(jì),看清全局,做到心里有數(shù),在后面的篇章再庖丁解牛,一步步挖掘細(xì)節(jié)。

官方描述scheduler

我們先看看官方是怎么描述 scheduler 的

The Kubernetes scheduler is a control plane process which assigns Pods to Nodes. The scheduler determines which Nodes are valid placements for each Pod in the scheduling queue according to constraints and available resources. The scheduler then ranks each valid Node and binds the Pod to a suitable Node. Multiple different schedulers may be used within a cluster; kube-scheduler is the reference implementation.

k8s scheduler 是一個(gè)控制面進(jìn)程,它分配 Pod 到 Nodes。根據(jù)限制和可用資源,scheduler 確定哪些節(jié)點(diǎn)符合調(diào)度隊(duì)列里的 Pod。然后對這些符合的節(jié)點(diǎn)進(jìn)行打分,然后把Pod綁定到合適的節(jié)點(diǎn)上。一個(gè)集群內(nèi)可以存在多個(gè)scheduler,而 kube-scheduler 是一個(gè)參考實(shí)現(xiàn)。

這段話簡單概括下就是:當(dāng)有 pod 需要 scheduler 調(diào)度的時(shí)候, scheduler 會(huì)根據(jù)一些列規(guī)則挑選出最符合的節(jié)點(diǎn),然后將Pod綁定到這個(gè)Node。

所以 scheduler 主要要做的事就是根據(jù) Nodes 當(dāng)前狀態(tài)和 pod 對資源的需求,按照順序運(yùn)行一系列指定的算法來挑選出一個(gè)Node。

我們可以通過下圖,對上述說的列算法有一個(gè)初步的認(rèn)識(shí),后面我們在展開詳細(xì)說

如圖中所示,圖中每一個(gè)綠色箭頭在k8s中叫擴(kuò)展點(diǎn)(extension point),從圖中可以看到一共有10個(gè)擴(kuò)展點(diǎn),我們可以分個(gè)類,如下圖

每一個(gè)擴(kuò)展點(diǎn)可以運(yùn)行一個(gè)或多個(gè)算法,在k8s中把這種算法叫做插件(Plugin)。顧名思義,擴(kuò)展點(diǎn)就是可以擴(kuò)展的,所以用戶可以開發(fā)自己的插件嵌入擴(kuò)展點(diǎn)中,我們既可以將自己開發(fā)的插件和系統(tǒng)默認(rèn)插件同時(shí)運(yùn)行,也可以關(guān)閉系統(tǒng)自帶的插件只運(yùn)行自己的插件,這部分在后面開發(fā)實(shí)踐階段會(huì)詳細(xì)介紹。

各個(gè)類型擴(kuò)展點(diǎn)

  • sort

sort 類型的擴(kuò)展點(diǎn)只有一個(gè):sort,而且這個(gè)擴(kuò)展點(diǎn)下面只能有一個(gè)插件可以運(yùn)行,如果同時(shí) enable 多個(gè) sort 插件,scheduler 會(huì)退出。

在 k8s 中,待調(diào)度的 Pod 會(huì)放在一個(gè)叫 activeQ 隊(duì)列中,這個(gè)隊(duì)列是一個(gè)基于堆實(shí)現(xiàn)的優(yōu)先隊(duì)列(priority queue),為什么是優(yōu)先隊(duì)列呢?

因?yàn)槟憧梢詫?Pod 設(shè)置優(yōu)先級(jí),將你認(rèn)為需要優(yōu)先調(diào)度的 Pod 優(yōu)先級(jí)調(diào)大,如果隊(duì)列里有多個(gè) Pod 需要調(diào)度,就會(huì)出現(xiàn)搶占現(xiàn)象,優(yōu)先級(jí)高的 Pod 會(huì)移動(dòng)到隊(duì)列頭部,scheduler 會(huì)優(yōu)先取出這個(gè) Pod 進(jìn)行調(diào)度。那么這個(gè)優(yōu)先級(jí)怎么設(shè)置呢?有兩種方法:

  • 如使用 k8s 默認(rèn) sort 插件,則可以給 Pod (deployment等方式) 設(shè)置 PriorityClass(創(chuàng)建 PriorityClass 資源并配置deployment);如果你的所有 Pod 都沒有設(shè)置 PriorityClass,那么會(huì)根據(jù) Pod 創(chuàng)建的時(shí)間先后順序進(jìn)行調(diào)度。PriorityClass 和 Pod 創(chuàng)建時(shí)間是系統(tǒng)默認(rèn)的排序依據(jù)。

  • 實(shí)現(xiàn)自己的 sort 插件定制排序算法,根據(jù)該排序算法實(shí)現(xiàn)搶占,例如你可以將包含特定標(biāo)簽的 Pod 移到隊(duì)頭。后面會(huì)詳細(xì)講述如何實(shí)現(xiàn)自己的插件來改變系統(tǒng)默認(rèn)行為。

  • filter

filter 類型擴(kuò)展點(diǎn)有3個(gè):prefilter,filter,postfilter。各個(gè)擴(kuò)展點(diǎn)有多個(gè)插件組成的插件集合根據(jù) Pod 的配置共同過濾 Node,如下圖:

preFilter 擴(kuò)展點(diǎn)主要有兩個(gè)作用,一是為后面的擴(kuò)展點(diǎn)計(jì)算 Pod 的一些信息,例如 preFilter 階段的 NodeResourcesFit 算法不會(huì)去判斷節(jié)點(diǎn)合適與否,而是計(jì)算這個(gè)Pod需要多少資源,然后存儲(chǔ)這個(gè)信息,在 filter 擴(kuò)展點(diǎn)的 NodeResourcesFit 插件中會(huì)把之前算出來的資源拿出來做判斷;另外一個(gè)作用就是過濾一些明顯不符合要求的節(jié)點(diǎn),這樣可以減少后續(xù)擴(kuò)展點(diǎn)插件一些無意義的計(jì)算。

filter 擴(kuò)展點(diǎn)主要的作用就是根據(jù)各個(gè)插件定義的順序依次執(zhí)行,篩選出符合 Pod 的節(jié)點(diǎn),這些插件會(huì)在 preFilter 后留下的每個(gè) Node 上運(yùn)行,如果能夠通過所有插件的”考驗(yàn)“,那么這個(gè)節(jié)點(diǎn)就留下來了。如果某個(gè)插件判斷這個(gè)節(jié)點(diǎn)不符合,那么剩余的所有插件都不會(huì)對該節(jié)點(diǎn)做計(jì)算。

postFilter 擴(kuò)展點(diǎn)只會(huì)在filter結(jié)束后沒有任何 Node 符合 Pod 的情況下才會(huì)運(yùn)行,否則這個(gè)擴(kuò)展點(diǎn)會(huì)被跳過。我們可以看到,這個(gè)擴(kuò)展點(diǎn)在系統(tǒng)只有一個(gè)默認(rèn)的插件, 這個(gè)默認(rèn)插件的作用遍歷這個(gè) Pod 所在的命名空間下面的所有 Pod,查找是否有可以被搶占的 Pod,如果有的話選出一個(gè)最合適的 Pod 然后 delete 掉這個(gè)Pod,并在待調(diào)度的 Pod 的 status 字段下面配置 nominateNode 為這個(gè)被搶占的 Pod。

  • score

這個(gè)類型的擴(kuò)展點(diǎn)的作用就是為上面 filter 擴(kuò)展點(diǎn)篩選出來的所有 Node 進(jìn)行打分,挑選出一個(gè)得分最高(最合適的),這個(gè) Node 就是 Pod 要被調(diào)度上去的節(jié)點(diǎn)。這個(gè)這個(gè)類型的擴(kuò)展有 preScore 和 score 兩個(gè),前者是為后者打分做前置準(zhǔn)備的,preScore 的各個(gè)插件會(huì)計(jì)算一些信息供 score使用,這個(gè)和 prefilter 比較類似。

  • reserve

reserve 類型擴(kuò)展點(diǎn)系統(tǒng)默認(rèn)只實(shí)現(xiàn)了一個(gè)插件:VolumeBinding,更新 Pod 聲明的 PVC 和對應(yīng)的 PV緩存信息,表示該 PV 已經(jīng)被 Pod占用。

  • permit

該類型擴(kuò)展點(diǎn),系統(tǒng)沒有實(shí)現(xiàn)默認(rèn)的插件,我們就不說了

  • bind

該類型擴(kuò)展點(diǎn)有三個(gè)擴(kuò)展點(diǎn):preBind、bind和postBind。

preBind 擴(kuò)展點(diǎn)有一個(gè)內(nèi)置插件 VolumeBinding,這個(gè)插件會(huì)調(diào)用 pv controller 完成綁定操作,在前面的 reserve 也有同名插件,這個(gè)插件只是更新了本地緩存中的信息,沒有實(shí)際做綁定。

bind 擴(kuò)展點(diǎn)也只有一個(gè)默認(rèn)的內(nèi)置插件:DefaultBinder,這個(gè)插件只做了一件很簡單的事,將 Pod.Spec.nodeName 更新為選出來的那個(gè) node。后面的“故事”就是 kubelet 監(jiān)聽到了 nodeName=Kubelet所在nodename,然后開始創(chuàng)建Pod(容器)。 到了這里,整個(gè)調(diào)度流程就結(jié)束了。

從文章開頭的那張圖中我們能夠看到 scheduler 分兩個(gè) cycle: scheduling cycle 和 binding cycle。區(qū)分這兩個(gè) cycle 的原因是為了提升調(diào)度效率。從上面的描述中我們能夠看到,在 bind cycle 中,會(huì)有兩次外部 api 調(diào)用:調(diào)用 pv controller 綁定 pv 和調(diào)用 kube-apiserver 綁定 Node,api調(diào)用是耗時(shí)的,所以將 bind 擴(kuò)展點(diǎn)拆分出來,另起一個(gè) go 協(xié)程進(jìn)行 bind。而在 scheduling cycle 中為了提升效率的一個(gè)重要原則就是 Pod、 Node 等信息從本地緩存中獲取,而具體的實(shí)現(xiàn)原理就是先使用 list 獲取所有 Node、Pod 的信息,然后再 watch 他們的變化更新本地緩存。

上面我們主要從擴(kuò)展點(diǎn)和插件方面說明了 scheduler 的架構(gòu)。下面我們從源碼架構(gòu)說說 scheduler 是怎么工作。

kube-scheduler 代碼的主要框架

我們先來看看 kube-scheduler 中的幾個(gè)關(guān)鍵組件

  • schedulerCache

schedulerCache 緩存 Pod,Node 等信息,各個(gè)擴(kuò)展點(diǎn)的插件在計(jì)算時(shí)所需要的 Node 和 Pod 信息都是從 schedulerCache 獲取。schedulerCache 具體在內(nèi)部是一個(gè)實(shí)現(xiàn)了 Cache 接口的 結(jié)構(gòu)體 cacheImpl,我們看下這個(gè)結(jié)構(gòu)體:

type cacheImpl struct {
	stop   <-chan struct{}
	ttl    time.Duration
	period time.Duration
	// This mutex guards all fields within this cache struct.
	mu sync.RWMutex
	// a set of assumed pod keys.
	// The key could further be used to get an entry in podStates.
	assumedPods sets.String
	// a map from pod key to podState.
	podStates map[string]*podState
	nodes     map[string]*nodeInfoListItem
	// headNode points to the most recently updated NodeInfo in "nodes". It is the
	// head of the linked list.
	headNode *nodeInfoListItem
	nodeTree *nodeTree
	// A map from image name to its imageState.
	imageStates map[string]*imageState
}

說他是緩存,從這個(gè)結(jié)構(gòu)體可以看到,實(shí)際上就是map,用來存儲(chǔ) Pod 和 Node 的信息。那么這些數(shù)據(jù)是怎么來的呢?我們來看下一個(gè)組件informer

  • informer

informer 是 client-go 提供的能力,他的作用是監(jiān)聽目標(biāo)資源的變化,同步到本地緩存。幾乎,在 k8s 的所有組件包括 controller-manager,kube-proxy,kubelet 等都使用了 informer 來監(jiān)聽 kube-apiserver 來獲取資源的變化。舉個(gè)例子,比如你執(zhí)行了 kubectl edit 命令改變了一個(gè) deployment 的鏡像版本,k8s 是怎么感知到這個(gè)變化,進(jìn)一步做 Pod 的重建的工作的呢?就是 kube-scheduler 使用了 informer 來監(jiān)聽 Pod 的變化實(shí)現(xiàn)的。

具體來說,kube-scheduler 使用 informer 監(jiān)聽了:Node, Pod, CSINode, CSIDriver, CSIStorageCapacity, PersistentVolume, PersistentVolumeClaim, StorageClass。監(jiān)聽 Node,Pod 我們可以理解,那么為什么要監(jiān)聽后面那些資源呢?后面的那些資源都是跟存儲(chǔ)有關(guān),在 preFilter 和 filter 擴(kuò)展點(diǎn)的插件里面有 Volumebinding 這么一個(gè)插件,是檢查系統(tǒng)當(dāng)前是否能夠滿足 Pod 聲明的 PVC,如果不能滿足,那么只能把 Pod 放入 unscheduleableQ 里。但是,后續(xù)如果系統(tǒng)如果可以滿足 Pod 對存儲(chǔ)的需要了,這個(gè) Pod 需要第一時(shí)間能夠被創(chuàng)建出來,所以系統(tǒng)必須要能夠?qū)崟r(shí)感知到系統(tǒng) PVC 等資源的變化及時(shí)將 unscheduleableQ 里面調(diào)度失敗的 Pod 進(jìn)行重新調(diào)度。這就是 informer 存在的意義了。具體的 informer 的實(shí)現(xiàn)原理可以參考這篇文章。

  • schedulerQueue

schedulerQueue包含三個(gè)隊(duì)列:activeQ, podBackoffQ,unschedulablePods。

activeQ 是一個(gè)優(yōu)先隊(duì)列,基于堆實(shí)現(xiàn),用于存放待調(diào)度的 Pod,優(yōu)先級(jí)高的會(huì)放在隊(duì)列頭部,優(yōu)先被調(diào)度。該隊(duì)列存放的 Pod 可能的情況有:剛創(chuàng)建未被調(diào)度的Pod;backOffPod 隊(duì)列中轉(zhuǎn)移過來的Pod;unschedule 隊(duì)列里轉(zhuǎn)移過來的 Pod。

podBackoffQ 也是一個(gè)優(yōu)先隊(duì)列,用于存放那些異常的Pod,這種 Pod 需要等待一定的時(shí)間才能夠被再次調(diào)度,會(huì)有協(xié)程定期去讀取這個(gè)隊(duì)列,然后加入到 activeQ 隊(duì)列然后重新調(diào)度。

unschedulablePods 嚴(yán)格上來說不屬于隊(duì)列,用于存放調(diào)度失敗的 Pod。這個(gè)隊(duì)列也會(huì)有協(xié)程定期(默認(rèn)30s)去讀取,然后判斷當(dāng)前時(shí)間距離上次調(diào)度時(shí)間的差是否超過5Min,如果超過這個(gè)時(shí)間則把 Pod 移動(dòng)到 activeQ 重新調(diào)度。

func (p *PriorityQueue) Run() {
	go wait.Until(p.flushBackoffQCompleted, 1.0*time.Second, p.stop)
	go wait.Until(p.flushUnschedulablePodsLeftover, 30*time.Second, p.stop)
}

說完這幾個(gè)組件,我們再來看看,當(dāng)一個(gè)新的 Pod 創(chuàng)建出來后,這個(gè)流程是怎么走的

  • informer 監(jiān)聽到了有新建 Pod,根據(jù) Pod 的優(yōu)先級(jí)把 Pod 加入到 activeQ 中適當(dāng)位置(即執(zhí)行sort插件);
  • scheduler 從 activeQ 隊(duì)頭取一個(gè)Pod(如果隊(duì)列沒有Pod可取,則會(huì)一直阻塞;此時(shí)假設(shè)就是上述說的新建的 Pod),開始調(diào)度;
  • 執(zhí)行 filter 類型擴(kuò)展點(diǎn)(包括preFilter,filter,postFilter)插件,選出所有符合 Pod 的 Node,如果無法找到符合的 Node, 則把 Pod 加入 unscheduleableQ 中,此次調(diào)度結(jié)束;
  • 執(zhí)行 score 擴(kuò)展點(diǎn)插件,找出最符合 Pod 的 那個(gè)Node;
  • assume Pod。這一步就是樂觀假設(shè) Pod 已經(jīng)調(diào)度成功,更新緩存中 Node 和 PodStats 信息,到了這里scheduling cycle就已經(jīng)結(jié)束了,然后會(huì)開啟新的一輪調(diào)度。至于真正的綁定,則會(huì)新起一個(gè)協(xié)程。
  • 執(zhí)行 reserve 插件;
  • 啟動(dòng)協(xié)程綁定 Pod 到 Node上。實(shí)際上就是修改 Pod.spec.nodeName: 選定的node名字,然后調(diào)用 kube-apiserver 接口寫入 etcd。如果綁定失敗了,那么移除緩存中此前加入的信息,然后把 Pod 放入activeQ 中,后續(xù)重新調(diào)度。
  • 執(zhí)行 postBinding,該步?jīng)]有實(shí)現(xiàn)的插件沒所以沒有做任何事。

以上就是 kube-scheduler 的基本原理。

在后面的文章中,我們會(huì)繼續(xù)聊聊 kube-scheduler 是怎么初始化出來的,要想開發(fā)一個(gè)自己的插件要做哪些事,更多關(guān)于Go kube-scheduler架構(gòu)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • windows下安裝make及使用makefile文件

    windows下安裝make及使用makefile文件

    這篇文章主要為大家介紹了windows下安裝make及使用makefile文件方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • 探索Golang?Redis實(shí)現(xiàn)發(fā)布訂閱功能實(shí)例

    探索Golang?Redis實(shí)現(xiàn)發(fā)布訂閱功能實(shí)例

    這篇文章主要介紹了Golang?Redis發(fā)布訂閱功能實(shí)例探索,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • 詳解Golang實(shí)現(xiàn)請求限流的幾種辦法

    詳解Golang實(shí)現(xiàn)請求限流的幾種辦法

    這篇文章主要介紹了詳解Golang實(shí)現(xiàn)請求限流的幾種辦法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Go構(gòu)建高性能的事件管理器實(shí)例詳解

    Go構(gòu)建高性能的事件管理器實(shí)例詳解

    這篇文章主要為大家介紹了Go構(gòu)建高性能的事件管理器實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • Go語言如何利用Mutex保障數(shù)據(jù)讀寫正確

    Go語言如何利用Mutex保障數(shù)據(jù)讀寫正確

    這篇文章主要介紹了互斥鎖的實(shí)現(xiàn)機(jī)制,以及?Go?標(biāo)準(zhǔn)庫的互斥鎖?Mutex?的基本使用方法,文中的示例代碼講解詳細(xì),需要的小伙伴可以參考一下
    2023-05-05
  • Go語言中的閉包詳解

    Go語言中的閉包詳解

    本文詳細(xì)講解了Go語言中的閉包,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • 基于Go語言實(shí)現(xiàn)猜謎游戲

    基于Go語言實(shí)現(xiàn)猜謎游戲

    這篇文章主要為大家詳細(xì)介紹了如何基于Go語言實(shí)現(xiàn)猜謎游戲,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)
    2023-09-09
  • Go語言中init函數(shù)與匿名函數(shù)使用淺析

    Go語言中init函數(shù)與匿名函數(shù)使用淺析

    這篇文章主要介紹了Go語言中init函數(shù)與匿名函數(shù)使用淺析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2023-01-01
  • Golang基于Vault實(shí)現(xiàn)敏感信息保護(hù)

    Golang基于Vault實(shí)現(xiàn)敏感信息保護(hù)

    Vault?是一個(gè)強(qiáng)大的敏感信息管理工具,自帶了多種認(rèn)證引擎和密碼引擎,本文主要探討應(yīng)用程序如何安全地從?Vault?獲取敏感信息,并進(jìn)一步實(shí)現(xiàn)自動(dòng)輪轉(zhuǎn),感興趣的可以了解一下
    2023-06-06
  • go基于Gin框架的HTTP接口限速實(shí)踐

    go基于Gin框架的HTTP接口限速實(shí)踐

    HTTP接口在各個(gè)業(yè)務(wù)模塊之間扮演著重要的角色,本文主要介紹了go基于Gin框架的HTTP接口限速實(shí)踐,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-09-09

最新評論