使用Capacity Scheduling
通過(guò)Kubernetes原生的ResourceQuota方式進(jìn)行固定資源分配,集群的整體資源利用率不高。阿里云借鑒Yarn Capacity Scheduling的設(shè)計(jì)思路,基于Scheduling Framework的擴(kuò)展機(jī)制,在調(diào)度時(shí)引入彈性配額組實(shí)現(xiàn)了Capacity Scheduling功能,在確保用戶資源分配的基礎(chǔ)上通過(guò)資源共享的方式來(lái)提升集群的整體資源利用率。本文介紹如何使用Capacity Scheduling功能。
前提條件
已創(chuàng)建Kubernetes版本大于等于1.20的ACK集群Pro版。詳細(xì)信息,請(qǐng)參見創(chuàng)建Kubernetes托管版集群。
背景信息
當(dāng)集群中有多個(gè)用戶時(shí),為了保障用戶有足夠的資源使用,管理員會(huì)將集群的資源固定分配給不同的用戶。傳統(tǒng)的方法是通過(guò)Kubernetes原生的ResourceQuota方式進(jìn)行固定資源的分配。因?yàn)椴煌挠脩羰褂觅Y源的周期和方式不同,可能會(huì)出現(xiàn)在某一時(shí)刻,一些用戶的資源不夠用,而另一些用戶的資源閑置。如果出現(xiàn)多個(gè)類似的情況,則整個(gè)集群會(huì)有很多資源浪費(fèi),導(dǎo)致集群的整體資源利用率下降。
Capacity Scheduling核心功能
針對(duì)上述問(wèn)題,阿里云基于Scheduling Framework的擴(kuò)展機(jī)制,在調(diào)度側(cè)實(shí)現(xiàn)了Capacity Scheduling的功能,在確保用戶的資源分配的基礎(chǔ)上通過(guò)資源共享的方式來(lái)提升整體資源的利用率。Capacity Scheduling具有以下功能:
支持定義不同層級(jí)的資源配額。如下圖所示,您可以根據(jù)具體情況(比如:公司的組織結(jié)構(gòu))配置多個(gè)層級(jí)的彈性配額。彈性配額組的葉子節(jié)點(diǎn)可以對(duì)應(yīng)多個(gè)Namespace,但同一個(gè)Namespace只能歸屬于一個(gè)葉子節(jié)點(diǎn)。
支持不同彈性配額之間的資源借用和回收。
Min:您可以使用的保障資源(Guaranteed Resource)。當(dāng)整個(gè)集群資源緊張時(shí),所有用戶使用的Min總和需要小于集群的總資源量。
Max:您可以使用的資源上限。
說(shuō)明您的工作負(fù)載可以向其他用戶借用其未使用的資源額度,但借用后可使用的資源總量依然不能超過(guò)Max。
您未使用的Min資源配額可以被其他用戶借用,但當(dāng)該用戶需要使用資源時(shí),可以通過(guò)搶占的方式回收借出的資源。
支持多種資源的配置。您除了可以配置CPU和內(nèi)存資源,也可以配置如GPU等任何Kubernetes支持的擴(kuò)展資源(Extended Resource)。
使用Capacity scheduling功能的使用示例
本文測(cè)試集群節(jié)點(diǎn)資源為1臺(tái)ecs.sn2.13xlarge機(jī)器(56 vCPU 224 GiB)。
執(zhí)行以下命令,創(chuàng)建對(duì)應(yīng)的Namespace。
kubectl create ns namespace1 kubectl create ns namespace2 kubectl create ns namespace3 kubectl create ns namespace4
使用以下YAML文件樣例,創(chuàng)建相應(yīng)的彈性配額組。
apiVersion: scheduling.sigs.k8s.io/v1beta1 kind: ElasticQuotaTree metadata: name: elasticquotatree namespace: kube-system # 只在kube-system下才會(huì)生效 spec: root: name: root # Root節(jié)點(diǎn)的Max必須等于Min max: cpu: 40 memory: 40Gi nvidia.com/gpu: 4 min: cpu: 40 memory: 40Gi nvidia.com/gpu: 4 children: # 配置第二級(jí) - name: root.a max: cpu: 40 memory: 40Gi nvidia.com/gpu: 4 min: cpu: 20 memory: 20Gi nvidia.com/gpu: 2 children: # 配置第三級(jí) - name: root.a.1 namespaces: # 配置對(duì)應(yīng)的Namespace - namespace1 max: cpu: 20 memory: 20Gi nvidia.com/gpu: 2 min: cpu: 10 memory: 10Gi nvidia.com/gpu: 1 - name: root.a.2 namespaces: # 配置對(duì)應(yīng)的Namespace - namespace2 max: cpu: 20 memory: 40Gi nvidia.com/gpu: 2 min: cpu: 10 memory: 10Gi nvidia.com/gpu: 1 - name: root.b max: cpu: 40 memory: 40Gi nvidia.com/gpu: 4 min: cpu: 20 memory: 20Gi nvidia.com/gpu: 2 children: # 配置第三級(jí) - name: root.b.1 namespaces: # 配置對(duì)應(yīng)的Namespace - namespace3 max: cpu: 20 memory: 20Gi nvidia.com/gpu: 2 min: cpu: 10 memory: 10Gi nvidia.com/gpu: 1 - name: root.b.2 namespaces: # 配置對(duì)應(yīng)的Namespace - namespace4 max: cpu: 20 memory: 20Gi nvidia.com/gpu: 2 min: cpu: 10 memory: 10Gi nvidia.com/gpu: 1
根據(jù)以上YAML文件示例配置,在
namespaces
字段配置對(duì)應(yīng)的命名空間,在children
字段配置對(duì)應(yīng)子級(jí)的彈性配額。配置需要滿足以下幾點(diǎn):同一個(gè)彈性配額中的Min≤Max。
子級(jí)彈性配額的Min之和≤父級(jí)的Min。
Root節(jié)點(diǎn)的Min=Max≤集群總資源。
Namespace只與彈性配額的葉子節(jié)點(diǎn)有一對(duì)多的對(duì)應(yīng)關(guān)系,且同一個(gè)Namespace只能歸屬于一個(gè)葉子節(jié)點(diǎn)。
執(zhí)行以下命令,查看彈性配額組是否創(chuàng)建成功。
kubectl get ElasticQuotaTree -n kube-system
預(yù)期輸出:
NAME AGE elasticquotatree 68s
使用以下YAML文件樣例,在
namespace1
中部署服務(wù),Pod的副本數(shù)為5個(gè),每個(gè)Pod請(qǐng)求CPU資源量為5核。apiVersion: apps/v1 kind: Deployment metadata: name: nginx1 namespace: namespace1 labels: app: nginx1 spec: replicas: 5 selector: matchLabels: app: nginx1 template: metadata: name: nginx1 labels: app: nginx1 spec: containers: - name: nginx1 image: nginx resources: limits: cpu: 5 requests: cpu: 5
執(zhí)行以下命令,查看集群Pod的部署情況。
kubectl get pods -n namespace1
預(yù)期輸出:
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
因?yàn)楫?dāng)前集群的資源有空閑(
root.max.cpu=40
),當(dāng)在namespace1
下的Pod申請(qǐng)CPU資源量超過(guò)root.a.1
設(shè)置的min.cpu=10
時(shí),還可以繼續(xù)借用其他處于空閑的資源,最多可以申請(qǐng)使用root.a.1
設(shè)置的配額max.cpu=20
。當(dāng)Pod申請(qǐng)CPU資源量超過(guò)
max.cpu=20
時(shí),再申請(qǐng)的Pod會(huì)處于Pending狀態(tài)。所以此時(shí)申請(qǐng)的5個(gè)Pod中,有4個(gè)處于Running狀態(tài),1個(gè)處于Pending狀態(tài)。
使用以下YAML文件樣例,在
namespace2
中部署服務(wù),其中Pod的副本數(shù)為5個(gè),每個(gè)Pod請(qǐng)求CPU資源量為5核。apiVersion: apps/v1 kind: Deployment metadata: name: nginx2 namespace: namespace2 labels: app: nginx2 spec: replicas: 5 selector: matchLabels: app: nginx2 template: metadata: name: nginx2 labels: app: nginx2 spec: containers: - name: nginx2 image: nginx resources: limits: cpu: 5 requests: cpu: 5
執(zhí)行以下命令,查看集群Pod的部署情況。
kubectl get pods -n namespace1
預(yù)期輸出:
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
預(yù)期輸出:
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
一樣,因?yàn)楫?dāng)前集群有資源空閑(root.max.cpu=40
),當(dāng)在namespace2
下Pod申請(qǐng)CPU資源量超過(guò)root.a.2
設(shè)置的min.cpu=10
時(shí),還可以繼續(xù)借用其他處于空閑的資源,最多可以申請(qǐng)使用root.a.2
設(shè)置的配額max.cpu=20
。當(dāng)Pod申請(qǐng)CPU資源量超過(guò)
max.cpu=20
時(shí),再申請(qǐng)的Pod處于Pending狀態(tài)。所以此時(shí)申請(qǐng)的5個(gè)Pod中,有4個(gè)處于Running狀態(tài),1個(gè)處于Pending狀態(tài)。此時(shí)集群中
namespace1
和namespace2
中的Pod所占用的資源已經(jīng)為root
設(shè)置的root.max.cpu=40
。
使用以下YAML文件樣例,在
namespace3
中部署服務(wù),其中Pod的副本數(shù)為5個(gè),每個(gè)Pod請(qǐng)求CPU資源量為5核。apiVersion: apps/v1 kind: Deployment metadata: name: nginx3 namespace: namespace3 labels: app: nginx3 spec: replicas: 5 selector: matchLabels: app: nginx3 template: metadata: name: nginx3 labels: app: nginx3 spec: containers: - name: nginx3 image: nginx resources: limits: cpu: 5 requests: cpu: 5
執(zhí)行以下命令,查看集群Pod的部署情況。
kubectl get pods -n namespace1
預(yù)期輸出:
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
預(yù)期輸出:
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
預(yù)期輸出:
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
設(shè)置為10
,為了保障其設(shè)置的min
資源,調(diào)度器會(huì)將root.a
下之前借用root.b
的Pod資源歸還,使得nginx3
能夠至少得到配額min.cpu=10
的資源量,保證其運(yùn)行。調(diào)度器會(huì)綜合考慮
root.a
下作業(yè)的優(yōu)先級(jí)、可用性以及創(chuàng)建時(shí)間等因素,選擇相應(yīng)的Pod歸還之前搶占的資源(10核)。因此,nginx3
得到配額min.cpu=10
的資源量后,有2個(gè)Pod處于Running狀態(tài),其他3個(gè)仍處于Pending狀態(tài)。使用以下YAML文件樣例,在
namespace4
中部署服務(wù)nginx4
,其中Pod的副本數(shù)為5個(gè),每個(gè)Pod請(qǐng)求CPU資源量為5核。apiVersion: apps/v1 kind: Deployment metadata: name: nginx4 namespace: namespace4 labels: app: nginx4 spec: replicas: 5 selector: matchLabels: app: nginx4 template: metadata: name: nginx4 labels: app: nginx4 spec: containers: - name: nginx4 image: nginx resources: limits: cpu: 5 requests: cpu: 5
執(zhí)行以下命令,查看集群Pod的部署情況。
kubectl get pods -n namespace1
預(yù)期輸出:
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
預(yù)期輸出:
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
預(yù)期輸出:
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
預(yù)期輸出:
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
設(shè)置為10
,為了保障其設(shè)置的min
資源,調(diào)度器會(huì)將root.a
下之前借用root.b
的Pod資源歸還,使得nginx4
能夠至少得到配額min.cpu=10
的資源量,保證其運(yùn)行。調(diào)度器會(huì)綜合考慮
root.a
下作業(yè)的優(yōu)先級(jí)、可用性以及創(chuàng)建時(shí)間等因素,選擇相應(yīng)的Pod歸還之前搶占的資源(10核)。因此,nginx4
得到配額min.cpu=10
資源量后,有2個(gè)Pod處于Running狀態(tài),其他3個(gè)仍處于Pending狀態(tài)。此時(shí),集群所有的彈性配額都使用其
min
設(shè)置的保障資源(Guaranteed Resource)。
相關(guān)文檔
kube-scheduler發(fā)布記錄,請(qǐng)參見kube-scheduler。
ACK基于新版的Kube-scheduler框架實(shí)現(xiàn)Gang scheduling的能力。Gang scheduling主要用于確保一組關(guān)聯(lián)的Pod能夠同時(shí)調(diào)度到集群中的節(jié)點(diǎn)上,或者如果無(wú)法滿足這種條件,則這些Pod都不會(huì)被調(diào)度,解決原生調(diào)度器無(wú)法支持All-or-Nothing作業(yè)調(diào)度的問(wèn)題。這種策略在執(zhí)行需要嚴(yán)格同步或共享資源的分布式應(yīng)用時(shí)非常有用,例如Spark、Hadoop等大數(shù)據(jù)處理任務(wù)。詳細(xì)信息,請(qǐng)參見使用Gang scheduling。