使用Gang scheduling
ACK基于新版的kube-scheduler框架實(shí)現(xiàn)Gang scheduling的能力。Gang scheduling主要用于確保一組關(guān)聯(lián)的Pod能夠同時(shí)調(diào)度到集群中的節(jié)點(diǎn)上,或者如果無法滿足這種條件,則這些Pod都不會(huì)被調(diào)度,解決原生調(diào)度器無法支持All-or-Nothing作業(yè)調(diào)度的問題。這種策略在執(zhí)行需要嚴(yán)格同步或共享資源的分布式應(yīng)用時(shí)非常有用,例如Spark、Hadoop等大數(shù)據(jù)處理任務(wù)。本文介紹如何使用Gang scheduling。
重要提示
請(qǐng)預(yù)留足夠資源:使用彈性節(jié)點(diǎn)池時(shí)請(qǐng)保證彈性節(jié)點(diǎn)池的最大資源量以及節(jié)點(diǎn)標(biāo)簽?zāi)軌驖M足Pod需求,否則可能導(dǎo)致Pod無法使用彈性節(jié)點(diǎn)池彈出的節(jié)點(diǎn),造成損失。
前提條件
已創(chuàng)建1.16及以上版本的ACK集群Pro版。具體步驟,請(qǐng)參見創(chuàng)建ACK托管集群。
目前Gang scheduling僅支持ACK集群Pro版。如需在ACK專有集群中使用,請(qǐng)提交工單申請(qǐng)白名單。
功能介紹
Kubernetes目前已經(jīng)廣泛的應(yīng)用于在線服務(wù)編排。為了提升集群的利用率和運(yùn)行效率,ACK希望將Kubernetes作為一個(gè)統(tǒng)一的管理平臺(tái)來管理在線服務(wù)和離線作業(yè)。由于調(diào)度器的限制,使得一些離線的工作負(fù)載無法遷移到Kubernetes。例如,某些有All-or-Nothing特點(diǎn)的作業(yè)要求所有的任務(wù)在同一時(shí)間被調(diào)度,如果只是部分任務(wù)啟動(dòng)的話,啟動(dòng)的任務(wù)將持續(xù)等待剩余的任務(wù)被調(diào)度。在最壞的情況下,所有作業(yè)都處于掛起狀態(tài),從而導(dǎo)致死鎖。此情況下,調(diào)度器需要Gang scheduling策略。
Gang scheduling策略可在并發(fā)系統(tǒng)中將多個(gè)相關(guān)聯(lián)的進(jìn)程調(diào)度到不同處理器上同時(shí)運(yùn)行。最主要的原則是保證所有相關(guān)聯(lián)的進(jìn)程能夠同時(shí)啟動(dòng),防止部分進(jìn)程的異常,避免整個(gè)關(guān)聯(lián)進(jìn)程組的阻塞。例如,當(dāng)您提交一個(gè)包含多個(gè)任務(wù)的批量Job時(shí),可能會(huì)出現(xiàn)多個(gè)任務(wù)全部調(diào)度成功或者都調(diào)度失敗的情況。這種All-or-Nothing調(diào)度場(chǎng)景,就被稱作Gang scheduling。
ACK將一組需要同時(shí)調(diào)度的Pod稱為PodGroup。您在提交All-or-Nothing作業(yè)時(shí),可以設(shè)置labels
字段,指定所屬PodGroup的名稱以及保證作業(yè)正常運(yùn)行Task的最少運(yùn)行個(gè)數(shù)。調(diào)度器會(huì)根據(jù)您指定的最少運(yùn)行個(gè)數(shù)進(jìn)行調(diào)度,只有當(dāng)集群資源滿足該Task最少運(yùn)行個(gè)數(shù)時(shí),才會(huì)統(tǒng)一調(diào)度,否則作業(yè)將一直處于Pending狀態(tài)。
相關(guān)視頻
下方視頻介紹如何安裝Arena并使用Arena提交Gang Scheduling任務(wù)。
使用方式
使用Gang scheduling時(shí),在創(chuàng)建的Pod處通過設(shè)置
labels
的形式配置min-available
和name
。使用這種方式時(shí),調(diào)度器會(huì)自動(dòng)創(chuàng)建對(duì)應(yīng)的PodGroup,并將pod-group.scheduling.sigs.k8s.io/name
的值作為PodGroup的Name,因此pod-group.scheduling.sigs.k8s.io/name
的值必須滿足DNS子域名的命名規(guī)則。詳細(xì)要求,請(qǐng)參見對(duì)象名稱和ID。labels: pod-group.scheduling.sigs.k8s.io/name: tf-smoke-gpu pod-group.scheduling.sigs.k8s.io/min-available: "3"
name
:PodGroup的名稱。min-available
:該批Pod滿足min-available的數(shù)量時(shí),才能被統(tǒng)一創(chuàng)建及調(diào)度。
您可以使用以下兩種方式使用Gang scheduling策略。對(duì)于1.22及以上版本的集群,調(diào)度器版本需要高于
1.xx.xx-aliyun-4.0
。創(chuàng)建對(duì)應(yīng)的PodGroup自定義資源,通過
pod-group.scheduling.sigs.k8s.io
或者pod-group.scheduling.sigs.k8s.io/name
聲明Pod對(duì)應(yīng)的PodGroup,此時(shí)Pod與PodGroup處于同一命名空間下。重要自1.31版本起,ACK將不再支持
scheduling.sigs.k8s.io/v1alpha1
版本的PodGroup資源,僅支持scheduling.x-k8s.io/v1alpha1
版本的PodGroup資源。# PodGroup CRD spec apiVersion: scheduling.sigs.k8s.io/v1alpha1 kind: PodGroup metadata: name: nginx spec: scheduleTimeoutSeconds: 10 minMember: 3 --- # 為容器添加標(biāo)簽“pod-group.scheduling.sigs.k8s.io/name”。 labels: pod-group.scheduling.sigs.k8s.io/name: nginx
在創(chuàng)建的Pod處通過設(shè)置annotations的形式設(shè)置min-available和name。不支持koordinator API中的total-number和mode參數(shù)。
annotations: gang.scheduling.koordinator.sh/name: "gang-example" gang.scheduling.koordinator.sh/min-available: "2"
屬于同一個(gè)PodGroup的Pod必須保持相同的優(yōu)先級(jí)。
高級(jí)用法
使用限制
對(duì)于1.22及以上版本的集群,調(diào)度器版本需要高于1.xx.xx-aliyun-4.0
。
聲明GangGroup
使用Gang scheduling時(shí),部分任務(wù)可能存在多種不同角色,例如PyTorch任務(wù)中的PS與Worker,這些角色對(duì)min-available的需求可能存在差異。使用單一的PodGroup時(shí)可能導(dǎo)致多個(gè)角色各自的min-available無法得到滿足,使用多個(gè)PodGroup時(shí)又會(huì)導(dǎo)致整體失去Gang的保證。此情況下推薦您使用GangGroup功能,該功能允許您將多個(gè)Gang合并為一組。調(diào)度器在進(jìn)行調(diào)度時(shí)只在多個(gè)Gang的min-available條件均滿足時(shí)允許任務(wù)執(zhí)行,保證任務(wù)的多個(gè)角色均滿足min-available特性。
當(dāng)您使用Label方式時(shí),可以在Pod上使用以下Label。
pod-group.scheduling.sigs.k8s.io/groups: "[\"default/gang-example1\", \"default/gang-example2\"]"
當(dāng)您使用PodGroup方式時(shí),可以在PodGroup自定義資源上使用以下Label。
pod-group.scheduling.sigs.k8s.io/groups: "[\"default/gang-example1\", \"default/gang-example2\"]"
當(dāng)您使用Annotation方式時(shí),可以在Pod上使用以下Annotation。
gang.scheduling.koordinator.sh/groups: "[\"default/gang-example1\", \"default/gang-example2\"]"
聲明matchpolicy
使用Gang scheduling時(shí),您可以通過聲明match-policy以使PodGroup在對(duì)Pod進(jìn)行計(jì)數(shù)時(shí)考慮不同類型的。
當(dāng)您使用Label方式時(shí),可以在Pod上使用以下Label。
pod-group.scheduling.sigs.k8s.io/match-policy: "waiting-and-running"
當(dāng)您使用PodGroup方式時(shí),可以在PodGroup自定義資源上使用以下Label。
pod-group.scheduling.sigs.k8s.io/match-policy: "waiting-and-running"
如果您使用的是Annotation方式,目前僅支持
once-satisfied
匹配。
支持的各種匹配方式以及功能如下表所示。
匹配方式取值 | 說明 |
| 匹配時(shí)只關(guān)注完成資源預(yù)占的Pod。 |
| 匹配時(shí)關(guān)注狀態(tài)為Running的Pod以及完成資源預(yù)占的Pod。 |
| 匹配時(shí)關(guān)注狀態(tài)為Succeed、Running的Pod以及完成資源預(yù)占的Pod。 |
| 匹配時(shí)只關(guān)注完成資源預(yù)占的Pod,匹配成功后該P(yáng)odGroup不再生效。 |
示例
本文通過運(yùn)行TensorFlow的分布式作業(yè)來展示Gang scheduling的效果。當(dāng)前測(cè)試集群有4個(gè)GPU卡。
安裝Arena,在Kubernetes集群中部署Tensorflow作業(yè)運(yùn)行環(huán)境。具體操作,請(qǐng)參見安裝Arena。
說明Arena是基于Kubernetes的機(jī)器學(xué)習(xí)系統(tǒng)開源社區(qū)Kubeflow中的子項(xiàng)目之一。Arena用命令行和SDK的形式支持了機(jī)器學(xué)習(xí)任務(wù)的主要生命周期管理(包括環(huán)境安裝、數(shù)據(jù)準(zhǔn)備,到模型開發(fā)、模型訓(xùn)練、模型預(yù)測(cè)等),有效提升了數(shù)據(jù)科學(xué)家工作效率。
使用以下模板向集群中提交Tensorflow分布式作業(yè),含有1個(gè)PS和4個(gè)Worker,每個(gè)Worker類型的Pod需要2個(gè)GPU。
apiVersion: "kubeflow.org/v1" kind: "TFJob" metadata: name: "tf-smoke-gpu" spec: tfReplicaSpecs: PS: replicas: 1 template: metadata: creationTimestamp: null labels: pod-group.scheduling.sigs.k8s.io/name: tf-smoke-gpu pod-group.scheduling.sigs.k8s.io/min-available: "5" spec: containers: - args: - python - tf_cnn_benchmarks.py - --batch_size=32 - --model=resnet50 - --variable_update=parameter_server - --flush_stdout=true - --num_gpus=1 - --local_parameter_device=cpu - --device=cpu - --data_format=NHWC image: registry.cn-hangzhou.aliyuncs.com/kubeflow-images-public/tf-benchmarks-cpu:v20171202-bdab599-dirty-284af3 name: tensorflow ports: - containerPort: 2222 name: tfjob-port resources: limits: cpu: '1' workingDir: /opt/tf-benchmarks/scripts/tf_cnn_benchmarks restartPolicy: OnFailure Worker: replicas: 4 template: metadata: creationTimestamp: null labels: pod-group.scheduling.sigs.k8s.io/name: tf-smoke-gpu pod-group.scheduling.sigs.k8s.io/min-available: "5" spec: containers: - args: - python - tf_cnn_benchmarks.py - --batch_size=32 - --model=resnet50 - --variable_update=parameter_server - --flush_stdout=true - --num_gpus=1 - --local_parameter_device=cpu - --device=gpu - --data_format=NHWC image: registry.cn-hangzhou.aliyuncs.com/kubeflow-images-public/tf-benchmarks-gpu:v20171202-bdab599-dirty-284af3 name: tensorflow ports: - containerPort: 2222 name: tfjob-port resources: limits: nvidia.com/gpu: 2 workingDir: /opt/tf-benchmarks/scripts/tf_cnn_benchmarks restartPolicy: OnFailure
不使用Gang scheduling功能
執(zhí)行以下命令查看Pod狀態(tài)。
kubectl get pods
系統(tǒng)輸出類似以下結(jié)果,表示集群中只有2個(gè)Worker類型的Pod處于Running狀態(tài),剩余2個(gè)Worker類型的Pod處于Pending狀態(tài)。
NAME READY STATUS RESTARTS AGE tf-smoke-gpu-ps-0 1/1 Running 0 6m43s tf-smoke-gpu-worker-0 1/1 Running 0 6m43s tf-smoke-gpu-worker-1 1/1 Running 0 6m43s tf-smoke-gpu-worker-2 0/1 Pending 0 6m43s tf-smoke-gpu-worker-3 0/1 Pending 0 6m43s
執(zhí)行以下命令查看其中正在運(yùn)行的Worker類型Pod的日志。
kubectl logs -f tf-smoke-gpu-worker-0
系統(tǒng)輸出類似以下結(jié)果,表示已啟動(dòng)的兩個(gè)Worker類型的Pod處于等待剩余兩個(gè)Worker類型的Pod啟動(dòng)的狀態(tài),已啟動(dòng)的兩個(gè)Worker類型的Pod占用GPU卻沒有使用。
INFO|2020-05-19T07:02:18|/opt/launcher.py|27| 2020-05-19 07:02:18.199696: I tensorflow/core/distributed_runtime/master.cc:221] CreateSession still waiting for response from worker: /job:worker/replica:0/task:3 INFO|2020-05-19T07:02:28|/opt/launcher.py|27| 2020-05-19 07:02:28.199798: I tensorflow/core/distributed_runtime/master.cc:221] CreateSession still waiting for response from worker: /job:worker/replica:0/task:2
使用Gang scheduling功能
執(zhí)行以下命令查看Pod狀態(tài)。
kubectl get pods
系統(tǒng)輸出以下結(jié)果,表示因?yàn)榧旱馁Y源無法滿足設(shè)定的最小數(shù)要求,PodGroup無法正常調(diào)度,所有的Pod一直處于Pending狀態(tài)。
NAME READY STATUS RESTARTS AGE tf-smoke-gpu-ps-0 0/1 Pending 0 43s tf-smoke-gpu-worker-0 0/1 Pending 0 43s tf-smoke-gpu-worker-1 0/1 Pending 0 43s tf-smoke-gpu-worker-2 0/1 Pending 0 43s tf-smoke-gpu-worker-3 0/1 Pending 0 43s
當(dāng)集群中新增4個(gè)GPU卡的資源時(shí),當(dāng)前集群的資源滿足設(shè)定的最小數(shù)要求。此時(shí)PodGroup正常調(diào)度,4個(gè)Worker類型Pod開始運(yùn)行。執(zhí)行以下命令查看Pod狀態(tài)。
kubectl get pods
預(yù)期輸出:
NAME READY STATUS RESTARTS AGE tf-smoke-gpu-ps-0 1/1 Running 0 3m16s tf-smoke-gpu-worker-0 1/1 Running 0 3m16s tf-smoke-gpu-worker-1 1/1 Running 0 3m16s tf-smoke-gpu-worker-2 1/1 Running 0 3m16s tf-smoke-gpu-worker-3 1/1 Running 0 3m16s
執(zhí)行以下命令查看其中一個(gè)Worker類型Pod的日志。顯示訓(xùn)練任務(wù)已經(jīng)開始。
kubectl logs -f tf-smoke-gpu-worker-0
系統(tǒng)輸出類似以下結(jié)果,表示訓(xùn)練任務(wù)已經(jīng)開始。
INFO|2020-05-19T07:15:24|/opt/launcher.py|27| Running warm up INFO|2020-05-19T07:21:04|/opt/launcher.py|27| Done warm up INFO|2020-05-19T07:21:04|/opt/launcher.py|27| Step Img/sec loss INFO|2020-05-19T07:21:05|/opt/launcher.py|27| 1 images/sec: 31.6 +/- 0.0 (jitter = 0.0) 8.318 INFO|2020-05-19T07:21:15|/opt/launcher.py|27| 10 images/sec: 31.1 +/- 0.4 (jitter = 0.7) 8.343 INFO|2020-05-19T07:21:25|/opt/launcher.py|27| 20 images/sec: 31.5 +/- 0.3 (jitter = 0.7) 8.142
錯(cuò)誤信息
錯(cuò)誤信息:"rejected by podgroup xxx"。
原因:當(dāng)集群中同時(shí)存在多個(gè)PodGroup調(diào)度時(shí),由于調(diào)度器存在BackOff隊(duì)列,可能存在一個(gè)PodGroup的所有Pod的調(diào)度沒有完全聚合在一起的情況。此時(shí)已經(jīng)預(yù)占資源的Pod可能會(huì)影響后續(xù)PodGroup的Pod調(diào)度,因此在后續(xù)PodGroup的Pod調(diào)度時(shí),會(huì)拒絕上一個(gè)調(diào)度的PodGroup中已經(jīng)預(yù)占資源的Pod。這是一種正常現(xiàn)象,通常不會(huì)持續(xù)很久,若持續(xù)時(shí)間超過二十分鐘,您可以提交工單進(jìn)行排查。
相關(guān)文檔
kube-scheduler發(fā)布記錄,請(qǐng)參見kube-scheduler。
通過Kubernetes原生的ResourceQuota方式進(jìn)行固定資源分配,集群的整體資源利用率不高。阿里云借鑒Yarn Capacity Scheduling的設(shè)計(jì)思路,基于Scheduling Framework的擴(kuò)展機(jī)制,在調(diào)度側(cè)通過引入彈性配額組實(shí)現(xiàn)了Capacity Scheduling功能,在確保用戶資源分配的基礎(chǔ)上通過資源共享的方式來提升集群的整體資源利用率。詳細(xì)信息,請(qǐng)參見使用Capacity Scheduling。