分散ジョブで必要な Pod をすべて同時に起動するか、または 1 つも起動しないようにしてデッドロックを防止します。
仕組み
ACK は、PodGroup リソースを使用してギャングスケジューリングを実装します。各ポッドは、最小ポッド数 (min-available) が指定された PodGroup に割り当てられます。スケジューラは、最小数が満たされるまでグループを保留状態に保持し、その後すべてのポッドをまとめてディスパッチします。
ACK は PodGroup を定義する 3 つの方法をサポートしています:
| 方法 | Pod のグルーピング方法 | 最適な用途 |
|---|---|---|
| ラベル | kube-scheduler が PodGroup を自動作成 | シンプルなジョブ。個別の PodGroup オブジェクトが不要 |
| PodGroup CRD | タイムアウト制御を備えた明示的な PodGroup リソース | scheduleTimeoutSeconds が必要なジョブ |
| Koordinator アノテーション | アノテーションベースのグルーピング | Koordinator のスケジューリングスタックを使用するクラスター |
すべての方法で、Pod とその PodGroup は同じ名前空間に存在する必要があります。また、PodGroup 内のすべての Pod は同じ優先度を共有する必要があります。
前提条件
開始する前に、次の要件が満たされていることを確認してください:
-
Kubernetes 1.16 以降を実行しているACK マネージド Pro クラスター。必要に応じてクラスターをアップグレードしてください。
-
高度な設定 (GangGroup および マッチポリシー): Kubernetes 1.22 以降を実行し、kube-scheduler のバージョンが
1.xx.xx-aliyun-4.0より後であるクラスター。
弾性ノードプールに十分な最大リソースキャパシティと、Pod のスケジューリングに一致するノードラベルがあることを確認してください。そうしないと、弾性ノードプールによってスケールアウトされたノードを Pod が使用できない場合があります。
ギャングスケジューリングの有効化
方法 1:ラベル (推奨)
各ポッドに 2 つのラベルを追加します。kube-scheduler は、pod-group.scheduling.sigs.k8s.io/name の値を名前とする PodGroup を自動的に作成します。
labels:
pod-group.scheduling.sigs.k8s.io/name: tf-smoke-gpu # PodGroup名 (有効な DNS サブドメインである必要があります)
pod-group.scheduling.sigs.k8s.io/min-available: "3" # ジョブの開始に必要な最小Pod数
pod-group.scheduling.sigs.k8s.io/name の値は、有効な DNS サブドメイン名 である必要があります。
方法 2:PodGroup CRD
PodGroup リソースを作成し、その後、各 Pod からラベルで参照します。
ACK 1.31 以降、scheduling.x-k8s.io/v1alpha1 のみがサポートされています。scheduling.sigs.k8s.io/v1alpha1 はサポートされなくなりました。
# PodGroupリソース
apiVersion: scheduling.x-k8s.io/v1alpha1
kind: PodGroup
metadata:
name: nginx
spec:
scheduleTimeoutSeconds: 10 # min-availableが満たされない場合にグループを拒否するまでの待機秒数
minMember: 3 # ジョブの開始に必要な最小Pod数
---
# Podラベル — PodGroupの名前と名前空間に一致する必要があります
labels:
pod-group.scheduling.sigs.k8s.io/name: nginx
方法 3:Koordinator アノテーション
各ポッドにアノテーションを追加します。この方法では、Koordinator API の total-number または mode パラメーターをサポートしていません。
annotations:
gang.scheduling.koordinator.sh/name: "gang-example"
gang.scheduling.koordinator.sh/min-available: "2"
高度な構成
複数ギャングのグルーピング (GangGroup)
パラメーターサーバーとワーカーを持つ PyTorch ジョブのように、ジョブによってはロールごとに異なる min-available 要件を持つものがあります。単一の PodGroup ではロールごとの最小要件を表現できず、個別の PodGroup ではロール間で連携できません。
GangGroup は複数の PodGroup をリンクします。ジョブは、すべての gang がそれぞれの min-available を満たした場合にのみ開始されます。各 pod または PodGroup に次のラベルを追加します (Koordinator メソッドの場合はアノテーションキーを使用します):
| 方法 | リソース | キー |
|---|---|---|
| ラベル | Pod | pod-group.scheduling.sigs.k8s.io/groups |
| PodGroup CRD | PodGroup | pod-group.scheduling.sigs.k8s.io/groups |
| Koordinator アノテーション | Pod | gang.scheduling.koordinator.sh/groups |
値の例 (<namespace>/<gang-name> エントリの JSON 配列):
pod-group.scheduling.sigs.k8s.io/groups: "[\"default/gang-example1\", \"default/gang-example2\"]"
GangGroup には、kube-scheduler のバージョンが 1.xx.xx-aliyun-4.0 より後である、バージョン 1.22 以降の Kubernetes が必要です。
マッチポリシーの設定
デフォルトでは、PodGroup はリソースの事前割り当てが完了したポッド (only-waiting) のみをカウントします。match-policy を使用すると、たとえば前のサイクルのポッドがまだ実行中である場合などに、他の状態のポッドを最小数に含めることができます。
ラベルを各 Pod (ラベルメソッド) または PodGroup リソース (PodGroup CRD メソッド) に追加します。Koordinator アノテーションメソッドは once-satisfied のみをサポートします。
| マッチポリシー | min-available にカウントされる Pod | 使用する場面 |
|---|---|---|
only-waiting |
リソースの事前割り当てを完了した Pod | 最も厳格です。前サイクルからの持ち越しがないステートレスジョブで使用します。 |
waiting-and-running |
Running 状態の Pod + 事前割り当てを完了した Pod | 前サイクルの実行中 Pod も最小数に含める必要がある場合に使用します。 |
waiting-running-succeed |
Succeeded 状態の Pod + Running + 事前割り当てを完了した Pod | 部分的な再起動を許容するジョブで使用します。すでに成功した Pod もカウントされます。 |
once-satisfied |
リソースの事前割り当てを完了した Pod。満たされた時点で PodGroup は無効になります | ワンショットジョブで使用します。ギャングがディスパッチされた後、PodGroup は無効化されます。 |
ラベル方式の例:
pod-group.scheduling.sigs.k8s.io/match-policy: "waiting-and-running"
PodGroup CRD の例 (Pod ではなく PodGroup に追加します):
pod-group.scheduling.sigs.k8s.io/match-policy: "waiting-and-running"
マッチポリシー設定には、Kubernetes 1.22 以降、およびバージョンが 1.xx.xx-aliyun-4.0 より後の kube-scheduler が必要です。
例:分散 TensorFlow ジョブ
この例では、ギャングスケジューリングを使用する場合と使用しない場合の分散 TensorFlow ジョブを比較します。クラスターには GPU が 4 つあります。ジョブには PS Pod が 1 つと worker Pod が 4 つあり、各 worker は GPU を 2 つ必要とします。min-available は 5 に設定されています。
手順 1: Arena をインストールし、TensorFlow ジョブ用にクラスターを準備します。
Arena は Kubeflow のサブプロジェクトであり、環境セットアップ、データ準備、モデル開発、トレーニング、予測など、機械学習ジョブのライフサイクルを CLI または SDK で管理します。
ステップ 2: TensorFlow ジョブを送信します。PS とワーカーの両方のテンプレートには、min-available: "5" というギャングスケジューリングラベルが含まれています。
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=2
- --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
ギャングスケジューリングを有効にしない場合:
Pod のステータスを確認します:
kubectl get pods
GPU が 4 つしかないため、worker が 2 つ Running になってすべての GPU を確保します。残りの 2 つは 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 のログを確認します:
kubectl logs -f tf-smoke-gpu-worker-0
worker は Pending の 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
ギャングスケジューリングを有効にした場合:
クラスターが min-available: 5 を満たすのに十分なリソースを確保するまで、5 つのポッドはすべて 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
クラスターに GPU を 4 つ追加すると、スケジューラーが 5 つの 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 のログを確認し、トレーニングが開始されたことを確認します:
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 が存在する場合、kube-scheduler のバックオフキューは、あるサイクルで事前割り当てを完了した Pod を、後続の PodGroup の処理時に拒否することがあります。
これは想定どおりの動作です。20 分以内に解消する場合は、このエラーを無視してください。解消しない場合は、チケットを送信してください。
次のステップ
-
キャパシティスケジューリングと併用 — Elastic Quota グループを使用してクラスターのリソース使用率を向上させます