Kubernetes scheduler V2草案

Kubernetes scheduler V2草案

來自專欄進擊的雲計算14 人贊了文章

狀態: Draft

作者 :bsalamat

中文翻譯:wgliang

貢獻者 :misterikkit

原文地址:docs.google.com/documen

譯文地址:docs.google.com/documen


大家都知道目前Kubernetes的調度器在可擴展性和性能上面還存在很多不足,在業界,不管是國內外大企業還是創業的新型雲服務公司在面臨調度的一系列本地化需求時都會自己定製或者使用webhook機制來兼容,但仍然要面臨定製後不好和官方同步改動和webhook性能太差不夠靈活的問題。所以,我們對更高可擴展性的調度器需求愈來愈強烈。下面是新更新的官方第二版調度器的設計草案,因為有些設計和我們內部的調度器不謀而合(例如預過濾,預留機制,拒絕(回調)等等),覺得很有意思。最快大家將可在2019年第一季度可以嘗試使用Scheduler V2,一起期待吧。

摘要

本文檔描述了 Kubernetes調度框架(Kubernetes Scheduling Framework)。該調度框架僅實現基本的功能,但它為插件擴展其功能提供了許多擴展點。 計劃這個框架(及其插件)最終將取代當前的Kubernetes調度器。

目標

  • 使調度程序更具可擴展性
  • 通過將它的一些功能移植到插件來使調度程序的核心變得更簡單。
  • 調度程序很容易擴展,同時具備很高的性能
  • 允許調度程序輕鬆擴展。
  • 提出框架的擴展點
  • 提出註冊插件的機制
  • 提出一種機制來過濾應該發送給每個插件的Pod
  • 建議一種機制來接收插件的結果,並根據收到的結果決定繼續或中止。
  • 提出一種機制來處理錯誤並通過它與插件進行通信。

術語

Scheduler v1, 當前的調度程序,指代Kubernetes已經存在的調度器

Scheduler v2, 調度框架,指代在本文提出的新的調度器

背景

許多功能都被添加到了Kubernetes默認調度程序中,他們不斷地讓代碼越來越多,邏輯更複雜。複雜到調度程序難以維護,它的錯誤也難以發現和修復,而運行自定義的調度程序的用戶很難趕上並整合新的更改。

目前的Kubernetes調度器提供 webhooks 來擴展其功能。但是,這些在幾個方面是有限制的:

  1. 擴展點的數量是有限的:在默認predicate函數之後調用「Filter」擴展器。在默認predicate函數之後調用「Prioritize」擴展器。運行默認preemption機制後調用「Preempt」擴展器。擴展器的「Bind」操作用於綁定Pod。只有其中的一個擴展器可以是一個綁定中的擴展器,並且該擴展器執行綁定而不是調度器來執行。擴展器不能在其他位置調用,例如,在運行predicate函數之前不能調用擴展器。
  2. 每次調用擴展器都需要編碼和解碼json文件。調用webhook(HTTP請求)也比調用本地函數慢。
  3. 很難通知擴展器調度器已經中止Pod的調度。例如,如果擴展器提供集群資源,並且調度程序聯繫擴展器並要求其為調度的Pod提供資源實例,然後當調度器面臨調度Pod的錯誤並決定中止調度,則很難將該錯誤通知擴展器,並要求它撤銷資源的供應。
  4. 由於當前擴展程序作為單獨的進程運行,因此它們不能使用調度程序的緩存。他們必須從apiserver那裡來構建自己的緩存,或者只處理從默認調度程序收到的信息。

上述限制妨礙了構建高性能和多功能的調度程序擴展。理想情況下,我們希望有一個足夠快的擴展機制,以允許在調度程序核心中保留最少的邏輯,並將默認調度程序的許多現有功能(例如認predicate和predicate功能以及搶佔功能都轉換為插件)轉換。這些插件將與調度程序一起編譯。我們還想提供一個不需要重新編譯調度程序的擴展機制。這些插件的預期性能低於進程內插件。在快速調用插件不是約束的情況下,應該使用這種進程外插件。

概述

調度程序v2 允許內置和外置擴展。這種新的架構是一個調度框架,公開了幾個在調度周期的擴展點。調度程序插件可以註冊在一個或多個擴展點。

非目標

  • 我們將保持Kubernetes API向後兼容性,但保持scheduler v1向後兼容性是非目標。 特別是,調度策略配置和v1擴展器在這個新框架中不起作用。
  • 解決所有調度程序v1的限制,儘管我們希望確保新的框架允許我們在未來解決已知的限制。
  • 提供插件和回調函數的實現細節,例如它們的所有參數和返回值。

詳細設計

調度的流程

未分配給給任何節點的Pod被移到調度隊列,並按插件指定的順序排序(介紹 此處)。調度框架選擇隊列的頭部並啟動 調度周期 來調度該Pod。在周期結束時,調度程序確定該Pod是否可調度。如果該Pod不可調度,則其狀態會被更新並返回到調度隊列。如果Pod是可調度的(找到一個或多個可運行Pod的Node節點),則開始評分過程。評分過程找到運行Pod的最佳節點。一個執行綁定操作的goroutine開始綁定該吊艙。

上述過程與Kubernetes調度程序v1所做的相同。調度程序v1的一些基本特性,如領導者選舉,也將被轉移到調度框架中。

在本節的其餘部分中,我們將介紹如何使用各種插件來豐富此基本工作流程。在本節中,我們將重點放在進程內插件上。進程外插件將在稍後的文檔中討論。

插件的通信和狀態

調度框架提供了一個庫插件可以通過它將信息傳遞給其他插件。 該庫保存為一個字元串類型的鍵到類型為interface {}的不透明指針的map。 寫操作需要一個鍵和一個指針,並使用給定的鍵將不透明指針存儲在映射中。其他插件可以提供鍵獲取並接收不透明指針。多個插件可以共享狀態信息或通過此機制進行通信。

保存的狀態僅在單個調度周期中保留。在計劃周期結束時,該map被破壞。所以,插件無法在多個調度周期內保持共享狀態。但是,它們可以通過緩存提供的介面來更新調度程序的緩存。緩存介面允許跨多個調度周期的有限的狀態保存。

值得注意的是插件都被認為是 可信的。調度程序不會阻止一個插件訪問或修改另一個插件的狀態。

插件註冊

插件註冊是通過提供一個擴展點和一個應該在該擴展點上調用的函數來完成的。這一步將是這樣的:

register("pre-filter", plugin.foo)

函數簽名的細節將在稍後提供。

擴展點

下圖顯示了Pod的調度周期以及調度框架公開的擴展點。在此圖片中,「Filter」相當於調度程序v1中的「Predicate」,「Scoring」相當於「Priority function」。 插件是go函數。他們被註冊為這些擴展點之一。 框架會按照它們為每個擴展點註冊的順序調用它們。

在下面的章節中,我們按照它們在調度周期中被調用的相同順序來描述每個擴展點。

調度隊列排序

這些插件表示應該如何在調度隊列中對Pod進行排序。此時註冊的插件只返回更大,更小或等於表示兩個Pod之間的順序。換句話說,這個擴展點上的插件返回「less(pod1,pod2)」的答案。此時可能會註冊多個插件。在這一點上註冊的插件按順序調用,只要插件返回「相等」,調用就會繼續。一旦插件返回「更大」或「更小」,這些插件的調用就會停止。

預過濾

這些插件通常用於檢查集群或Pod必須滿足的某些條件。這些對於在Pod上執行預處理並存儲一些關於可以被其他插件使用的Pod的信息也很有用。

pod指針作為參數傳遞給這些插件。如果這些插件中的任何一個返回錯誤,則調度周期將中止。

這些插件以已註冊的相同的順序連續被調用。

過濾

過濾器插件過濾掉無法運行Pod的節點。調度程序按照它們註冊的順序為每個節點運行這些插件,但調度程序可以並行地為多個節點運行這些過濾器函數。所以,這些插件在修改狀態時必須使用同步。

一旦這些過濾器中的一個過濾器失敗,調度程序就會停止運行節點的剩餘過濾器函數。

Post過濾器

已經通過過濾Pod的Pod和一組節點被傳遞給這些Post插件。它們被稱為Pod是否可調度(不管節點集是空的還是非空的)。

如果這些插件中的任何一個返回錯誤,或者Pod確定為不可調度,則調度周期將中止。

這些插件被稱為 Serially。

評分

這些插件與調度程序v1中的priority函數類似。它們被用來對已經通過過濾階段的節點進行排序。與過濾器插件類似, 每個節點按照已註冊的順序依次調用它們,但調度程序可以並行地為多個節點運行它們。

這些函數中的每一個都會為給定節點返回一個分數。得分乘以函數的權重並與其他得分函數的結果匯總以得出節點的總得分。

這些函數永遠不會阻止調度。在發生錯誤的情況下,它們應該為被排名的節點返回零分。

Post評分/預先假設

調用完所有評分插件並確定節點的分數後,框架將選出評分最高的最佳節點,然後調用Post評分插件。 Pod和選定的節點被傳遞給這些Post評分插件。這些插件還有一次機會檢查任何有關將Pod分配給此節點的條件,並在需要時拒絕該節點。

預留

這不是一個插件點。 此時,調度程序通過為Pod更新Node緩存來「預留」資源(部分或全部)來。在調度程序v1中,這個階段被稱為「假設」。此時,只有調度程序緩存被更新以反映節點(部分地)被保留給Pod。節點到Pod的實際分配發生在「綁定」階段。這是當apiserver使用節點信息更新Pod對象時。

承認

Admit 插件在單獨的goroutine中運行(並行)。每個插件可以返回三個可能值之一:1)「承認」,2)「拒絕」,或3)「等待」。如果在此擴展點上註冊的所有插件都返回「允許」,則將該容器發送到下一步進行綁定。如果任何一個插件返回「拒絕」,則會拒絕該容器並將其發送回調度隊列。如果任何一個插件返回「等待」, 則Pod將保持保留狀態,直到明確批准進行綁定為止。返回「等待」的插件也必須返回「超時」。如果超時到期,則該Pod被拒絕並返回到調度隊列。

批准Pod綁定

雖然任何插件都可以從緩存中接收保留Pod的列表並批准它們,但我們只希望「Admit」插件批准綁定處於「等待」狀態的保留Pod。一旦Pod被批准,它就會被發送到綁定階段。

拒絕

被稱為「Admit」的插件可能會執行一些操作,如果Pod假定失敗,則應該撤消這些操作。 「拒絕」擴展點允許進行這種清理操作。如果Pod的假設被取消,則調用此時註冊的插件。 如果任何「Admit」插件返回「拒絕」或處於「等待」狀態的Pod假設超時,則預留被取消。

預先綁定

當Pod被批准綁定時,它會到達這個階段。這些插件在Pod到節點的實際綁定發生之前運行。只有當所有這些插件都返回true時,綁定才會啟動。如果有任何返回false,則Pod被拒絕並被發送回調度隊列。這些插件運行在一個單獨的去程序中。當所有這些插件返回true時,相同的常式運行「綁定」這些插件。

綁定

一旦所有預綁定插件返回true,綁定插件就會被執行。 這個擴展點可能會註冊多個插件。每個插件可能會返回true或false(或錯誤)。如果插件返回false,則會調用下一個插件,直到插件返回true。一旦返回true ,剩餘的插件就會被跳過。如果任何插件返回錯誤或者所有插件都返回false,那麼Pod將被拒絕並返回到調度隊列。

後期綁定

後期綁定插件對預定後的內務管理非常有用。這些插件不會返回任何值,也不會影響在調度周期中做出的調度決策。

USE-CASES

在本節中,我們提供了一些關於如何使用調度框架來解決常見調度場景的示例。

集群級資源的動態綁定

集群級資源是不在調度Pod時的立即確定可用的節點的資源。調度程序需要確保此類集群級資源綁定到選定的節點,然後才能調度需要此類資源的節點的節點。在調度Pod作為動態資源綁定時,我們將這種類型的資源綁定到節點。

事實證明,動態資源綁定在Scheduler v1中是一個挑戰,因為Scheduler v1不夠靈活,無法在不同的調度階段支持各種類型的插件。因此,存儲卷的綁定被集成到調度程序代碼中,並且對調度程序擴展程序進行了一些不重要的更改以支持網路GPU的動態綁定。

調度框架以更清晰的方式允許這種動態綁定。調度框架的主線程處理待處理的Pod,它請求網路資源並為Pod找到節點並保留Pod。 在「預綁定」階段安裝動態資源聯編程序插件(在單獨的線程中)。它分析Pod,當檢測到Pod需要動態綁定資源時,插件會嘗試將集群資源附加到所選節點,然後返回true,以便可以綁定Pod。 如果資源附件失敗,則返回false並重試Pod。

當有多個這樣的網路資源時,它們中的每一個都安裝一個「預先綁定」插件。每個插件都查看Pod,如果Pod沒有請求他們感興趣的資源,他們只需返回「真正」的pod。

Gang調度

Gang調度允許同時安排一定數量的Pod。如果該團伙的所有成員不能同時調度,他們都不應該調度。 Gang調度也可能具有其他各種功能,但在此情況下,我們對Pod的同時調度感興趣。

調度框架中的Gang調度可以使用「Admit」插件完成。 主調度線程逐個處理pod並為它們預留節點。每個吊艙都會調用准入階段的幫派調度插件。當它發現吊艙屬於一個幫派時,它會檢查幫派的屬性。如果沒有足夠的成員定期或處於「等待」狀態,該插件返回「等待」。當數字達到期望值時,處於等待狀態的所有Pod均被批准並發送進行綁定。

進程外插件(OUT OF PROCESS PLUGINS)

進程外插件(OOPP通過HTTP介面通過JSON調用)。換句話說,調度器將支持最多(也許是全部)擴展點的webhook。發送到OOPP的數據必須編碼為JSON,並且收到的數據必須解碼。所以,調用一個OOPP比在進程中的插件要慢很多。

我們不打算在第一版的調度框架中構建OOPP。所以,關於它們的更多細節將被確定。

配置調度框架

兼容性 使用SCHEDULER v1

我們將為調度程序v2構建一組新的插件,以確保調度程序v1在將節點放置在節點上時的現有行為得以保留。這包括 構建複製預設謂詞和優先順序插件 scheduler v1的函數及其綁定機制的,但為scheduler v1構建的調度程序擴展器將不兼容調度程序v2。此外,在調度程序v2中不保證預設情況下未啟用的謂詞和優先順序功能(如服務關聯)。

開發計劃

我們將開發調度框架作為SIG-scheduling中的孵化器項目。它將在獨立於調度程序v1的獨立代碼庫中構建,但我們 可能會使用來自調度程序v1的很多代碼。

測試計劃

我們將在構建調度框架的功能時添加單元測試。調度框架最終應該能夠通過調度程序v1的集成和e2e測試,排除那些涉及調度程序擴展的測試。 e2e和集成測試可能需要稍微修改,因為調度框架的初始化和配置將與調度程序v1不同。

工作評估

我們期望在兩個發布周期(2018年底)看到一個早期版本的調度框架。如果事情順利,我們將在2019年第一季度末開始提供它作為調度程序v1的替代品,並啟動調度程序v1的棄用。我們將在2019年第二季度將其作為Kubernetes的默認調度程序,但我們將保留使用調度程序v1至少兩個更多發布周期的選項。


推薦閱讀:

如何使用 Buildah 構建容器鏡像
systemd和Docker究竟要相殺多久?
Kubernetes 1.11開箱亮點:定製化資源、pod優先和搶佔等更新
kubernetes kustomize 初體驗

TAG:Kubernetes | 調度演算法 | 雲計算 |