通過Kubernetes原生的ResourceQuota方式進行固定資源分派,叢集的整體資源使用率不高。阿里雲借鑒Yarn Capacity Scheduling的設計思路,基於Scheduling Framework的擴充機制,在調度時引入彈性配額組實現了Capacity Scheduling功能,在確保使用者資源分派的基礎上通過資源共用的方式來提升叢集的整體資源使用率。本文介紹如何使用Capacity Scheduling功能。
前提條件
已建立Kubernetes版本大於等於1.20的ACK叢集Pro版。詳細資料,請參見建立Kubernetes託管版叢集。
背景資訊
當叢集中有多個使用者時,為了保障使用者有足夠的資源使用,管理員會將叢集的資源固定分配給不同的使用者。傳統的方法是通過Kubernetes原生的ResourceQuota方式進行固定資源的分配。因為不同的使用者使用資源的周期和方式不同,可能會出現在某一時刻,一些使用者的資源不夠用,而另一些使用者的資源閑置。如果出現多個類似的情況,則整個叢集會有很多資源浪費,導致叢集的整體資源使用率下降。
Capacity Scheduling核心功能
針對上述問題,阿里雲基於Scheduling Framework的擴充機制,在調度側實現了Capacity Scheduling的功能,在確保使用者的資源分派的基礎上通過資源共用的方式來提升整體資源的利用率。Capacity Scheduling具有以下功能:
支援定義不同層級的資源配額。如下圖所示,您可以根據具體情況(比如:公司的組織圖)配置多個層級的彈性配額。彈性配額組的葉子節點可以對應多個Namespace,但同一個Namespace只能歸屬於一個葉子節點。
支援不同彈性配額之間的資源借用和回收。
Min:您可以使用的保障資源(Guaranteed Resource)。當整個叢集資源緊張時,所有使用者使用的Min總和需要小於叢集的總資源量。
Max:您可以使用的資源上限。
說明您的工作負載可以向其他使用者借用其未使用的資源額度,但借用後可使用的資源總量依然不能超過Max。
您未使用的Min資源配額可以被其他使用者借用,但當該使用者需要使用資源時,可以通過搶佔的方式回收借出的資源。
支援多種資源的配置。您除了可以配置CPU和記憶體資源,也可以配置如GPU等任何Kubernetes支援的擴充資源(Extended Resource)。
使用Capacity scheduling功能的使用樣本
本文測試叢集節點資源為1台ecs.sn2.13xlarge機器(56 vCPU 224 GiB)。
執行以下命令,建立對應的Namespace。
kubectl create ns namespace1 kubectl create ns namespace2 kubectl create ns namespace3 kubectl create ns namespace4
使用以下YAML檔案範例,建立相應的彈性配額組。
根據以上YAML檔案樣本配置,在
namespaces
欄位配置對應的命名空間,在children
欄位配置對應子級的彈性配額。配置需要滿足以下幾點:同一個彈性配額中的Min≤Max。
子級彈性配額的Min之和≤父級的Min。
Root節點的Min=Max≤叢集總資源。
Namespace只與彈性配額的葉子節點有一對多的對應關係,且同一個Namespace只能歸屬於一個葉子節點。
執行以下命令,查看彈性配額組是否建立成功。
kubectl get ElasticQuotaTree -n kube-system
預期輸出:
NAME AGE elasticquotatree 68s
使用以下YAML檔案範例,在
namespace1
中部署服務,Pod的副本數為5個,每個Pod請求CPU資源量為5核。執行以下命令,查看叢集Pod的部署情況。
kubectl get pods -n namespace1
預期輸出:
NAME READY STATUS RESTARTS AGE nginx1-744b889544-52dbg 1/1 Running 0 70s nginx1-744b889544-6l4s9 1/1 Running 0 70s nginx1-744b889544-cgzlr 1/1 Running 0 70s nginx1-744b889544-w2gr7 1/1 Running 0 70s nginx1-744b889544-zr5xz 0/1 Pending 0 70s
因為當前叢集的資源有空閑(
root.max.cpu=40
),當在namespace1
下的Pod申請CPU資源量超過root.a.1
設定的min.cpu=10
時,還可以繼續借用其他處於閒置資源,最多可以申請使用root.a.1
設定的配額max.cpu=20
。當Pod申請CPU資源量超過
max.cpu=20
時,再申請的Pod會處於Pending狀態。所以此時申請的5個Pod中,有4個處於Running狀態,1個處於Pending狀態。
使用以下YAML檔案範例,在
namespace2
中部署服務,其中Pod的副本數為5個,每個Pod請求CPU資源量為5核。執行以下命令,查看叢集Pod的部署情況。
kubectl get pods -n namespace1
預期輸出:
NAME READY STATUS RESTARTS AGE nginx1-744b889544-52dbg 1/1 Running 0 111s nginx1-744b889544-6l4s9 1/1 Running 0 111s nginx1-744b889544-cgzlr 1/1 Running 0 111s nginx1-744b889544-w2gr7 1/1 Running 0 111s nginx1-744b889544-zr5xz 0/1 Pending 0 111s
kubectl get pods -n namespace2
預期輸出:
NAME READY STATUS RESTARTS AGE nginx2-556f95449f-4gl8s 1/1 Running 0 111s nginx2-556f95449f-crwk4 1/1 Running 0 111s nginx2-556f95449f-gg6q2 0/1 Pending 0 111s nginx2-556f95449f-pnz5k 1/1 Running 0 111s nginx2-556f95449f-vjpmq 1/1 Running 0 111s
同
nginx1
一樣,因為當前叢集有資源空閑(root.max.cpu=40
),當在namespace2
下Pod申請CPU資源量超過root.a.2
設定的min.cpu=10
時,還可以繼續借用其他處於閒置資源,最多可以申請使用root.a.2
設定的配額max.cpu=20
。當Pod申請CPU資源量超過
max.cpu=20
時,再申請的Pod處於Pending狀態。所以此時申請的5個Pod中,有4個處於Running狀態,1個處於Pending狀態。此時叢集中
namespace1
和namespace2
中的Pod所佔用的資源已經為root
設定的root.max.cpu=40
。
使用以下YAML檔案範例,在
namespace3
中部署服務,其中Pod的副本數為5個,每個Pod請求CPU資源量為5核。執行以下命令,查看叢集Pod的部署情況。
kubectl get pods -n namespace1
預期輸出:
NAME READY STATUS RESTARTS AGE nginx1-744b889544-52dbg 1/1 Running 0 6m17s nginx1-744b889544-cgzlr 1/1 Running 0 6m17s nginx1-744b889544-nknns 0/1 Pending 0 3m45s nginx1-744b889544-w2gr7 1/1 Running 0 6m17s nginx1-744b889544-zr5xz 0/1 Pending 0 6m17s
kubectl get pods -n namespace2
預期輸出:
NAME READY STATUS RESTARTS AGE nginx2-556f95449f-crwk4 1/1 Running 0 4m22s nginx2-556f95449f-ft42z 1/1 Running 0 4m22s nginx2-556f95449f-gg6q2 0/1 Pending 0 4m22s nginx2-556f95449f-hfr2g 1/1 Running 0 3m29s nginx2-556f95449f-pvgrl 0/1 Pending 0 3m29s
kubectl get pods -n namespace3
預期輸出:
NAME READY STATUS RESTARTS AGE nginx3-578877666-msd7f 1/1 Running 0 4m nginx3-578877666-nfdwv 0/1 Pending 0 4m10s nginx3-578877666-psszr 0/1 Pending 0 4m11s nginx3-578877666-xfsss 1/1 Running 0 4m22s nginx3-578877666-xpl2p 0/1 Pending 0 4m10s
nginx3
的彈性配額root.b.1
的min
設定為10
,為了保障其設定的min
資源,調度器會將root.a
下之前借用root.b
的Pod資源歸還,使得nginx3
能夠至少得到配額min.cpu=10
的資源量,保證其運行。調度器會綜合考慮
root.a
下作業的優先順序、可用性以及建立時間等因素,選擇相應的Pod歸還之前搶佔的資源(10核)。因此,nginx3
得到配額min.cpu=10
的資源量後,有2個Pod處於Running狀態,其他3個仍處於Pending狀態。使用以下YAML檔案範例,在
namespace4
中部署服務nginx4
,其中Pod的副本數為5個,每個Pod請求CPU資源量為5核。執行以下命令,查看叢集Pod的部署情況。
kubectl get pods -n namespace1
預期輸出:
NAME READY STATUS RESTARTS AGE nginx1-744b889544-cgzlr 1/1 Running 0 8m20s nginx1-744b889544-cwx8l 0/1 Pending 0 55s nginx1-744b889544-gjkx2 0/1 Pending 0 55s nginx1-744b889544-nknns 0/1 Pending 0 5m48s nginx1-744b889544-zr5xz 1/1 Running 0 8m20s
kubectl get pods -n namespace2
預期輸出:
NAME READY STATUS RESTARTS AGE nginx2-556f95449f-cglpv 0/1 Pending 0 3m45s nginx2-556f95449f-crwk4 1/1 Running 0 9m31s nginx2-556f95449f-gg6q2 1/1 Running 0 9m31s nginx2-556f95449f-pvgrl 0/1 Pending 0 8m38s nginx2-556f95449f-zv8wn 0/1 Pending 0 3m45s
kubectl get pods -n namespace3
預期輸出:
NAME READY STATUS RESTARTS AGE nginx3-578877666-msd7f 1/1 Running 0 8m46s nginx3-578877666-nfdwv 0/1 Pending 0 8m56s nginx3-578877666-psszr 0/1 Pending 0 8m57s nginx3-578877666-xfsss 1/1 Running 0 9m8s nginx3-578877666-xpl2p 0/1 Pending 0 8m56s
kubectl get pods -n namespace4
預期輸出:
nginx4-754b767f45-g9954 1/1 Running 0 4m32s nginx4-754b767f45-j4v7v 0/1 Pending 0 4m32s nginx4-754b767f45-jk2t7 0/1 Pending 0 4m32s nginx4-754b767f45-nhzpf 0/1 Pending 0 4m32s nginx4-754b767f45-tv5jj 1/1 Running 0 4m32s
同理,
nginx4
的彈性配額root.b.2
的min
設定為10
,為了保障其設定的min
資源,調度器會將root.a
下之前借用root.b
的Pod資源歸還,使得nginx4
能夠至少得到配額min.cpu=10
的資源量,保證其運行。調度器會綜合考慮
root.a
下作業的優先順序、可用性以及建立時間等因素,選擇相應的Pod歸還之前搶佔的資源(10核)。因此,nginx4
得到配額min.cpu=10
資源量後,有2個Pod處於Running狀態,其他3個仍處於Pending狀態。此時,叢集所有的彈性配額都使用其
min
設定的保障資源(Guaranteed Resource)。
相關文檔
kube-scheduler發布記錄,請參見kube-scheduler。
ACK基於新版的Kube-scheduler架構實現Gang scheduling的能力。Gang scheduling主要用於確保一組關聯的Pod能夠同時調度到叢集中的節點上,或者如果無法滿足這種條件,則這些Pod都不會被調度,解決原生調度器無法支援All-or-Nothing作業調度的問題。這種策略在執行需要嚴格同步或共用資源的分布式應用時非常有用,例如Spark、Hadoop等巨量資料處理任務。詳細資料,請參見使用Gang scheduling。