通過使用 Gang scheduling 能力,可有效解決原生調度器無法支持 All-or-Nothing 作業調度的問題。
前提條件
已安裝智算套件。
背景信息
Gang scheduling 是一種保證一組相關任務同步執行的調度策略,多個任務的作業調度時,要么全部成功,要么全部失敗,這種調度場景,稱作為Gang scheduling。其中一個經典使用場景是分布式機器學習訓練:在大規模機器學習模型的訓練中,數據可能被分布到多個節點上,每個節點都需要運行一個模型的副本。這些模型副本需要同時開始訓練,以保證參數更新的同步。隨著大規模和復雜的工作負載在Kubernetes上的普及,需要對應的調度策略適配這種場景,避免資源浪費和延遲。由于Kubernetes的核心調度器默認不支持Gang scheduling,使得一些工作負載無法很好地遷移至Kubernetes。為了適配這種場景,目前的云容器引擎基于調度器框架實現Gang scheduling功能,可以在云容器引擎中非常方便使用該能力。
功能介紹
為了實現All-or-Nothing的特性,首先需要將一組同時調度的Pod通過annotations標識出來,這個標識可稱為PodGroup。提交作業的時候調度器可根據工作負載的相關annotations,獲取調度的配置并進行調度。只有當集群資源滿足該任務最少運行個數時,才會統一調度,否則作業將一直處于Pending狀態。
使用方法
下面使用kubeflow的TFJob作為例子展示Gang scheduling的能力。
apiVersion: "kubeflow.org/v1"
kind: TFJob
metadata:
name: gang-example
spec:
tfReplicaSpecs:
Worker:
replicas: 2
restartPolicy: OnFailure
template:
spec:
schedulerName: roc # 指定使用智算調度器
containers:
- name: tensorflow
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ["sleep", "30s"]
resources:
limits:
nvidia.com/gpu: 1作業提交到集群后,可看到調度組件自動為這個任務創建PodGroup自定義資源對象:
[root@pm-b86b yaml]# kubectl get pg
NAME STATUS MINMEMBER RUNNINGS AGE
gang-example Running 2 21s
[root@pm-b86b yaml]# kubectl get pg gang-example -oyaml
apiVersion: scheduling.roc/v1beta1
kind: PodGroup
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"kubeflow.org/v1","kind":"TFJob","metadata":{"annotations":{},"name":"gang-example","namespace":"default"},"spec":{"tfReplicaSpecs":{"Worker":{"replicas":2,"restartPolicy":"OnFailure","template":{"spec":{"containers":[{"command":["sleep","5m"],"image":"busybox:latest","imagePullPolicy":"IfNotPresent","name":"tensorflow","resources":{"limits":{"nvidia.com/gpu":1}}}],"schedulerName":"roc"}}}}}}
creationTimestamp: "2024-04-14T03:32:54Z"
generation: 5
name: gang-example
namespace: default
ownerReferences:lastTransitionTime: "2024-04-14T03:33:19Z"reason: tasks in gang are ready to be scheduledstatus: "True"transitionID: 2afbaf4b-5424-414c-b89a-a3416925b9b0type: Scheduledphase: Runningrunning: 2
關鍵字段
minMember:minMember表示該podgroup下最少需要運行的pod或任務數量。如果集群資源不滿足miniMember數量任務的運行需求,調度器將不會調度任何一個該podgroup 內的任務。
queue:queue表示該podgroup所屬的queue。queue必須提前已創建且狀態為open。
priorityClassName:priorityClassName表示該podgroup的優先級,用于調度器為該queue中所有podgroup進行調度時進行排序。system-node-critical和system-cluster-critical 是2個預留的值,表示最高優先級。不特別指定時,默認使用default優先級或zero優先級。
minResources:minResources表示運行該podgroup所需要的最少資源。當集群可分配資源不滿足minResources時,調度器將不會調度任何一個該podgroup內的任務。
phase:phase表示該podgroup當前的狀態。
conditions:conditions表示該podgroup的具體狀態日志,包含了podgroup生命周期中的關鍵事件。
檢查運行狀態
由于集群資源足夠作業的所有pod運行,通過命令可知Pod已在運行中。
[root@pm-b86b yaml]# kubectl get po | grep gang
gang-example-worker-0 1/1 Running 0 31s
gang-example-worker-1 1/1 Running 0 31s
如果集群資源不足以讓所有pod運行,則所有Pod都會調度失敗,可通過PodGroup查看調度狀態。
[root@pm-b86b yaml]# kubectl get pg gang-example -oyaml
apiVersion: scheduling.roc/v1beta1
kind: PodGroup
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"kubeflow.org/v1","kind":"TFJob","metadata":{"annotations":{},"name":"gang-example","namespace":"default"},"spec":{"tfReplicaSpecs":{"Worker":{"replicas":10,"restartPolicy":"OnFailure","template":{"spec":{"containers":[{"command":["sleep","5m"],"image":"busybox:latest","imagePullPolicy":"IfNotPresent","name":"tensorflow","resources":{"limits":{"nvidia.com/gpu":1}}}],"schedulerName":"roc"}}}}}}
creationTimestamp: "2024-04-14T03:47:09Z"
generation: 4
name: gang-example
namespace: default
ownerReferences:
apiVersion: kubeflow.org/v1
blockOwnerDeletion: true
controller: true
kind: TFJob
name: gang-example
uid: 8caecc94-7220-4bbc-bde2-6c94fe478a35
resourceVersion: "40583543"
uid: 69034c3f-3c51-4159-b8db-8a965a3838f7
spec:
minMember: 10
minResources:
nvidia.com/gpu: "10"
status:
conditions:
lastTransitionTime: "2024-04-14T03:47:40Z"message: '10/0 tasks in gang unschedulable: pod group is not ready, 10 minAvailable'reason: NotEnoughResourcesstatus: "True"transitionID: 3359ff1a-d558-4148-949f-f3f53f501a4ctype: Unschedulablephase: Pending