全部產品
Search
文件中心

Container Service for Kubernetes:使用Gang scheduling

更新時間:Oct 19, 2024

ACK基於新版的kube-scheduler架構實現Gang scheduling的能力。Gang scheduling主要用於確保一組關聯的Pod能夠同時調度到叢集中的節點上,或者如果無法滿足這種條件,則這些Pod都不會被調度,解決原生調度器無法支援All-or-Nothing作業調度的問題。這種策略在執行需要嚴格同步或共用資源的分布式應用時非常有用,例如Spark、Hadoop等巨量資料處理任務。本文介紹如何使用Gang scheduling。

重要提示

請預留足夠資源:使用彈性節點池時請保證彈性節點池的最大資源量以及節點標籤能夠滿足Pod需求,否則可能導致Pod無法使用彈性節點池彈出的節點,造成損失。

前提條件

已建立1.16及以上版本的ACK叢集Pro版。具體步驟,請參見建立ACK託管叢集

重要

目前Gang scheduling僅支援ACK叢集Pro版。如需在ACK專有叢集中使用,請提交工單申請白名單。

功能介紹

Kubernetes目前已經廣泛的應用於線上服務編排。為了提升叢集的利用率和運行效率,ACK希望將Kubernetes作為一個統一的管理平台來管理線上服務和離線作業。由於調度器的限制,使得一些離線的工作負載無法遷移到Kubernetes。例如,某些有All-or-Nothing特點的作業要求所有的任務在同一時間被調度,如果只是部分任務啟動的話,啟動的任務將持續等待剩餘的任務被調度。在最壞的情況下,所有作業都處於掛起狀態,從而導致死結。此情況下,調度器需要Gang scheduling策略。

Gang scheduling策略可在並發系統中將多個相關聯的進程調度到不同處理器上同時運行。最主要的原則是保證所有相關聯的進程能夠同時啟動,防止部分進程的異常,避免整個關聯進程組的阻塞。例如,當您提交一個包含多個任務的批量Job時,可能會出現多個任務全部調度成功或者都調度失敗的情況。這種All-or-Nothing調度情境,就被稱作Gang scheduling。

ACK將一組需要同時調度的Pod稱為PodGroup。您在提交All-or-Nothing作業時,可以設定labels欄位,指定所屬PodGroup的名稱以及保證作業正常運行Task的最少運行個數。調度器會根據您指定的最少運行個數進行調度,只有當叢集資源滿足該Task最少運行個數時,才會統一調度,否則作業將一直處於Pending狀態。

使用方式

  1. 使用Gang scheduling時,在建立的Pod處通過設定labels的形式配置min-availablename。使用這種方式時,調度器會自動建立對應的PodGroup,並將pod-group.scheduling.sigs.k8s.io/name的值作為PodGroup的Name,因此pod-group.scheduling.sigs.k8s.io/name的值必須滿足DNS子網域名稱的命名規則。詳細要求,請參見對象名稱和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的數量時,才能被統一建立及調度。

  2. 您可以使用以下兩種方式使用Gang scheduling策略。對於1.22及以上版本的叢集,調度器版本需要高於1.xx.xx-aliyun-4.0

    • 建立對應的PodGroup自訂資源,通過pod-group.scheduling.sigs.k8s.io或者pod-group.scheduling.sigs.k8s.io/name聲明Pod對應的PodGroup,此時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
      ---
      # 為容器添加標籤“pod-group.scheduling.sigs.k8s.io/name”。
      labels: 
       pod-group.scheduling.sigs.k8s.io/name: nginx
    • 在建立的Pod處通過設定annotations的形式設定min-availablename。不支援koordinator API中的total-numbermode參數。

      annotations:  
       gang.scheduling.koordinator.sh/name: "gang-example" 
       gang.scheduling.koordinator.sh/min-available: "2"
說明

屬於同一個PodGroup的Pod必須保持相同的優先順序。

進階用法

使用限制

對於1.22及以上版本的叢集,調度器版本需要高於1.xx.xx-aliyun-4.0

聲明GangGroup

使用Gang scheduling時,部分任務可能存在多種不同角色,例如PyTorch任務中的PS與Worker,這些角色對min-available的需求可能存在差異。使用單一的PodGroup時可能導致多個角色各自的min-available無法得到滿足,使用多個PodGroup時又會導致整體失去Gang的保證。此情況下推薦您使用GangGroup功能,該功能允許您將多個Gang合并為一組。調度器在進行調度時只在多個Gang的min-available條件均滿足時允許任務執行,保證任務的多個角色均滿足min-available特性。

  • 當您使用Label方式時,可以在Pod上使用以下Label。

    pod-group.scheduling.sigs.k8s.io/groups: "[\"default/gang-example1\", \"default/gang-example2\"]"
  • 當您使用PodGroup方式時,可以在PodGroup自訂資源上使用以下Label。

    pod-group.scheduling.sigs.k8s.io/groups: "[\"default/gang-example1\", \"default/gang-example2\"]"
  • 當您使用Annotation方式時,可以在Pod上使用以下Annotation。

    gang.scheduling.koordinator.sh/groups: "[\"default/gang-example1\", \"default/gang-example2\"]"

聲明matchpolicy

使用Gang scheduling時,您可以通過聲明match-policy以使PodGroup在對Pod進行計數時考慮不同類型的。

  • 當您使用Label方式時,可以在Pod上使用以下Label。

    pod-group.scheduling.sigs.k8s.io/match-policy: "waiting-and-running"
  • 當您使用PodGroup方式時,可以在PodGroup自訂資源上使用以下Label。

    pod-group.scheduling.sigs.k8s.io/match-policy: "waiting-and-running"
  • 如果您使用的是Annotation方式,目前僅支援once-satisfied匹配。

支援的各種匹配方式以及功能如下表所示。

匹配方式取值

說明

only-waiting

匹配時只關注完成資源預占的Pod。

waiting-and-running

匹配時關注狀態為Running的Pod以及完成資源預占的Pod。

waiting-running-succeed

匹配時關注狀態為Succeed、Running的Pod以及完成資源預占的Pod。

once-satisfied

匹配時只關注完成資源預占的Pod,匹配成功後該PodGroup不再生效。

樣本

本文通過運行TensorFlow的分布式作業來展示Gang scheduling的效果。當前測試叢集有4個GPU卡。

  1. 安裝Arena,在Kubernetes叢集中部署Tensorflow作業運行環境。具體操作,請參見安裝Arena

    說明

    Arena是基於Kubernetes的機器學習系統開源社區Kubeflow中的子專案之一。Arena用命令列和SDK的形式支援了機器學習任務的主要生命週期管理(包括環境安裝、資料準備,到模型開發、模型訓練、模型預測等),有效提升了資料科學家工作效率。

  2. 使用以下模板向叢集中提交Tensorflow分布式作業,含有1個PS和4個Worker,每個Worker類型的Pod需要2個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功能

      執行以下命令查看Pod狀態。

      kubectl get pods

      系統輸出類似以下結果,表示叢集中只有2個Worker類型的Pod處於Running狀態,剩餘2個Worker類型的Pod處於Pending狀態。

      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

      執行以下命令查看其中正在啟動並執行Worker類型Pod的日誌。

      kubectl logs -f tf-smoke-gpu-worker-0

      系統輸出類似以下結果,表示已啟動的兩個Worker類型的Pod處於等待剩餘兩個Worker類型的Pod啟動的狀態,已啟動的兩個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功能

      執行以下命令查看Pod狀態。

      kubectl get pods

      系統輸出以下結果,表示因為叢集的資源無法滿足設定的最小數要求,PodGroup無法正常調度,所有的Pod一直處於Pending狀態。

      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

      當叢集中新增4個GPU卡的資源時,當前叢集的資源滿足設定的最小數要求。此時PodGroup正常調度,4個Worker類型Pod開始運行。執行以下命令查看Pod狀態。

      kubectl get pods

      預期輸出:

      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

      執行以下命令查看其中一個Worker類型Pod的日誌。顯示訓練任務已經開始。

      kubectl logs -f tf-smoke-gpu-worker-0

      系統輸出類似以下結果,表示訓練任務已經開始。

      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

錯誤資訊

  • 錯誤資訊:"rejected by podgroup xxx"。

  • 原因:當叢集中同時存在多個PodGroup調度時,由於調度器存在BackOff隊列,可能存在一個PodGroup的所有Pod的調度沒有完全彙總在一起的情況。此時已經預佔資源的Pod可能會影響後續PodGroup的Pod調度,因此在後續PodGroup的Pod調度時,會拒絕上一個調度的PodGroup中已經預佔資源的Pod。這是一種正常現象,通常不會持續很久,若期間超過二十分鐘,您可以提交工單進行排查。

相關文檔

  • kube-scheduler發布記錄,請參見kube-scheduler

  • 通過Kubernetes原生的ResourceQuota方式進行固定資源分派,叢集的整體資源使用率不高。阿里雲借鑒Yarn Capacity Scheduling的設計思路,基於Scheduling Framework的擴充機制,在調度側通過引入彈性配額組實現了Capacity Scheduling功能,在確保使用者資源分派的基礎上通過資源共用的方式來提升叢集的整體資源使用率。詳細資料,請參見使用Capacity Scheduling