リソースが限られ、優先度が競合する場合、さまざまなチームからの大量の RayJob の管理は困難になります。このガイドでは、ElasticQuotaTree と Kube Queue を使用して、チーム間の RayJob スケジューリングを自動化する方法を説明します。リソースクォータ、優先度に基づくプリエンプション、ギャングスケジューリング (協調スケジューリング) を活用することで、優先度の高いジョブが常に最初にリソースを確保できるようにします。
前提条件
開始する前に、以下をご確認ください。
バージョン v1.24 以降の ACK Pro マネージドクラスターまたは ACK Lingjun クラスター
kubectl がインストールされ、クラスターに接続されています。詳細については、「kubeconfig ファイルを取得して kubectl を使用してクラスターに接続する」をご参照ください。
KubeRay Operator がインストールされていること。詳細については、「Kuberay-Operator のインストール」をご参照ください。
バージョン v1.21.4 以降の Kube Queue (ack-kube-queue) で、RayJob リソースをサポートするように設定されていること。 詳細については、「ack-kube-queue を使用して AI と機械学習のワークロードを管理する」をご参照ください。
8 vCPU および 32 GiB 以上の ECS インスタンスが少なくとも 3 つあるデフォルトのノードプール
このガイドでは、公式の Ray イメージ rayproject/ray:2.36.1 を使用します。ネットワークの問題で Docker Hub からのイメージのプルに失敗する場合は、次のいずれかの代替策を使用してください。
中国本土以外のレジストリからイメージをサブスクライブするには、Container Registry を使用します。詳細については、「中国以外のイメージをサブスクライブする」をご参照ください。
クロスリージョンのイメージプル用に、Global Accelerator インスタンスを作成します。詳細については、「GA を使用した ACK におけるクロスドメインのコンテナイメージプルの高速化」をご参照ください。
仕組み
このガイドでは、3 レイヤーのリソース管理パイプラインをセットアップします。
ElasticQuotaTreeでクォータを定義 — 各ノードがチームまたは部門ごとの保証される最小リソースと最大上限を設定するツリー構造です。キュー作成の自動化 — Kube Queue は
ElasticQuotaTreeを読み取り、各リーフノードに対してキューを作成します。バインドされた名前空間で送信された RayJob は、対応するキューに自動的にルーティングされます。ジョブスケジューリングの制御 —
suspend: trueの RayJob はキューに入り待機します。ジョブのリソースリクエストが利用可能なクォータ内に収まると、Kube Queue は自動的にsuspendをfalseに設定し、ジョブがスケジューリングに進むことを許可します。
すべてのノードが同時に起動する必要がある分散タスクの場合、ギャングスケジューリングによって部分的な割り当てやリソースのデッドロックが防止されます。
ジョブキューの表示
ElasticQuotaTree が適用されると、Kube Queue は各リーフノードに対して自動的にキューを作成します。algorithm 配下の video チームの場合、キュー root-algorithm-video が kube-queue 名前空間に作成されます。
suspend: true を指定した RayJob が video 名前空間に送信されると、Kube Queue は次の処理を行います。
対応する
QueueUnitリソースを作成しますジョブを
root-algorithm-videoキューに配置します総リソース要件を計算します:Head Pod のリクエスト + (レプリカ数 × WorkerGroup ごとの単一 Pod のリクエスト)
クォータが利用可能になると
suspendをfalseに設定し、ジョブがスケジューリングに進むことを許可します
videoチーム用に自動作成されたキューを確認します。kubectl get queue -n kube-queue root-algorithm-video-k42kq -o yaml出力は次のようになります。
apiVersion: scheduling.x-k8s.io/v1alpha1 kind: Queue metadata: annotations: kube-queue/parent-quota-fullname: algorithm kube-queue/quota-fullname: root/algorithm/video generateName: root-algorithm-video- name: root-algorithm-video-k42kq namespace: kube-queue spec: queuePolicy: Round status: queueItemDetails: active: [] # スケジューリングを待機しているジョブ、優先度順 backoff: [] # スケジューリング試行の失敗後にリトライを待機しているジョブすべてのキューをリスト表示して、完全な階層を確認します。
kubectl get queue -n kube-queue出力は次のようになります。
NAME AGE root-algorithm-n54fm 51s root-algorithm-text-hgbvz 51s root-algorithm-video-k42kq 51s root-devops-2zccw 51s root-infrastructure-devops-d6zqq 51s root-infrastructure-vbpkt 51s root-k8htb 51s
RayJob の作成と送信
ConfigMap の作成
video 名前空間に ConfigMap を作成し、RayJob が RayCluster で実行する Python コードを定義します。
apiVersion: v1
kind: ConfigMap
metadata:
name: rayjob-video
namespace: video
data:
sample_code.py: |
import ray
import os
import requests
ray.init()
@ray.remote
class Counter:
def __init__(self):
# runtimeEnv を検証するために使用
self.name = os.getenv("counter_name")
assert self.name == "test_counter"
self.counter = 0
def inc(self):
self.counter += 1
def get_counter(self):
return "{} got {}".format(self.name, self.counter)
counter = Counter.remote()
for _ in range(2):
ray.get(counter.inc.remote())
print(ray.get(counter.get_counter.remote()))
# ジョブに正しいランタイム環境が使用されたことを確認
assert requests.__version__ == "2.26.0"キューイング動作の確認
kubectl create -fを使用して 2 つの RayJob を作成します。kubectl get rayjob -n video期待される出力:
NAME JOB STATUS DEPLOYMENT STATUS START TIME END TIME AGE rayjob-video-g2lvn Initializing 2025-01-10T01:36:24Z 6s rayjob-video-h4x2q Suspended 2025-01-10T01:36:25Z 5srayjob-video-g2lvnはすぐにデキューされ、初期化中です。rayjob-video-h4x2qはまだ一時停止状態です — キューには入りましたが、クォータを待機しています。最初のジョブのエンキューとデキューのタイムスタンプを確認します。
kubectl -n video get rayjob rayjob-video-g2lvn -o yamlアノテーションには両方のタイムスタンプが表示され、デキューされたことが確認できます。
annotations: kube-queue/job-dequeue-timestamp: 2025-01-10 01:36:24.641181026 +0000 UTC kube-queue/job-enqueue-timestamp: 2025-01-10 01:36:24.298639916 +0000 UTC2 番目のジョブについては、エンキューのタイムスタンプのみが表示されます — デキューのタイムスタンプがないことは、まだスケジュールされていないことを意味します。
kubectl -n video get rayjob rayjob-video-h4x2q -o yamlannotations: kube-queue/job-enqueue-timestamp: 2025-01-10 01:36:25.505182364 +0000 UTCどの Pod が実行中かを確認します。
kubectl -n video get pod期待される出力 — 最初のジョブの Pod のみが実行中です。
NAME READY STATUS RESTARTS AGE rayjob-video-g2lvn-9gz66 1/1 Running 0 28s rayjob-video-g2lvn-raycluster-v8tfh-head-6trq5 1/1 Running 0 49s rayjob-video-g2lvn-raycluster-v8tfh-small-group-worker-hkt7m 1/1 Running 0 49s rayjob-video-g2lvn-raycluster-v8tfh-small-group-worker-rbzjn 1/1 Running 0 49sキューをチェックして、2 番目のジョブが待機していることを確認します。
kubectl -n kube-queue get queue root-algorithm-video-k42kq -o yaml2 番目のジョブは
backoffに表示され、リソースが解放されるのを待っています。status: queueItemDetails: active: [] backoff: - name: rayjob-video-h4x2q-ray-qu namespace: video position: 1
ギャングスケジューリング失敗のトラブルシューティング
リソースが不足している場合、スケジューラは配置できなかった各 Pod に対して GangFailedScheduling 警告イベントをログに記録します。次のコマンドを実行してこれらのイベントをフィルターし、原因を特定します。
kubectl get events -n algorithm-text \
--field-selector='type=Warning,reason=GangFailedScheduling' \
| grep "cycle 1"期待される出力:
5m48s Warning GangFailedScheduling pod/rayjob-sample-dtmtl-raycluster-r9jc7-small-group-worker-89mlq rayjob-sample-dtmtl-raycluster-r9jc7-small-group-worker-89mlq in gang failed to be scheduled in cycle 1: 0/0 nodes are available: 3 Insufficient cpu.
5m48s Warning GangFailedScheduling pod/rayjob-sample-dtmtl-raycluster-r9jc7-small-group-worker-8fwmr rayjob-sample-dtmtl-raycluster-r9jc7-small-group-worker-8fwmr in gang failed to be scheduled in cycle 1: 0/0 nodes are available: 3 Insufficient cpu.各イベントには、スケジューリングの試行を識別する cycle xx 番号と、Pod を配置できなかった理由が含まれています。これを使用して、問題が CPU、メモリ、GPU の不足、または許容されないノードの Taint であるかどうかを判断します。