AI / ML ワークロードでは、Pod 間通信が頻繁に行われます。この要件により、Pod 間のネットワーク帯域幅は、ワークロードの実行時間と費用に直接影響します。この帯域幅は、クラスタ内の仮想マシン(VM)インスタンスの配置によって異なります。
このドキュメントでは、パフォーマンスと信頼性の両方を考慮して、Google Kubernetes Engine(GKE)クラスタで大規模な AI または ML ワークロードのスケジューリングを最適化する方法について説明します。具体的には、低レイテンシ通信にトポロジ認識スケジューリング(TAS)を使用するようにクラスタを構成します。このアプローチにより、通信オーバーヘッドを最小限に抑え、ワークロードのパフォーマンスを最大限に高めることができます。
トポロジ認識スケジューリング(TAS)とは
TAS を使用すると、 大規模言語モデル(LLM)のトレーニングの効率を大幅に向上させることができます。TAS は、ワーカーが特定のランク順で通信する必要がある勾配集約時の通信オーバーヘッドを最小限に抑えるために、ワーカーをネットワーク トポロジに戦略的に配置します。TAS は、順次通信するワーカー間のネットワーク ホップを最小限に抑えることで、ネットワーク競合を減らし、帯域幅の使用率を最適化し、収束を高速化してトレーニング時間を短縮します。LLM モデルがますます大規模化する中、TAS は分散トレーニングのパフォーマンスとスケーラビリティを最大化するために不可欠です。
TAS は、予約によって取得できる密度の高い容量で最適に機能します。Flex Start VM または Spot VM の場合、容量が近くに割り当てられる可能性が低いため、このシナリオでは TAS が適切に機能しない可能性があります。
始める前に
作業を始める前に、次のタスクが完了していることを確認してください。
- Google Kubernetes Engine API を有効にする。 Google Kubernetes Engine API の有効化
- このタスクに Google Cloud CLI を使用する場合は、gcloud CLI をインストールして初期化する。gcloud CLI をインストール済みの場合は、
gcloud components updateコマンドを実行して最新のバージョンを取得します。以前のバージョンの gcloud CLI では、このドキュメントのコマンドを実行できない場合があります。
クラスタに接続するには、次のコマンドを実行します。
gcloud container clusters get-credentials CLUSTER_NAMECLUSTER_NAMEは、使用するクラスタの名前に置き換えます。
GKE クラスタを準備する
TAS でワークロードを実行するように GKE クラスタを準備する手順は次のとおりです。
TAS を有効にして Kueue をインストールする
TAS は、割り当てとジョブによる割り当ての使用方法を管理する Kubernetes ネイティブ システムである
Kueueで
使用することをおすすめします。TAS には Kueue バージョン 0.10.0 以降が必要であり、明示的に有効にする必要があります。
Kueue をインストールして TAS を有効にするには、次のいずれかのオプションを選択します。
Kueue マニフェスト
Kueue をインストールします。
kubectl apply --server-side -f https://github.com/kubernetes-sigs/kueue/releases/download/v0.10.0/manifests.yamlKueue で TAS を有効にします。
kubectl -n kueue-system patch deployment kueue-controller-manager \ --type json -p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--feature-gates=TopologyAwareScheduling=true"}]'
Helm チャート
Helm チャートを使用して、TAS を有効にして Kueue をインストールします。
helm install kueue oci://us-central1-docker.pkg.dev/k8s-staging-images/charts/kueue \
--version="v0.10.0" \
--create-namespace \
--namespace=kueue-system \
--set="controllerManager.featureGates[0].name=TopologyAwareScheduling,controllerManager.featureGates[0].enabled=true"
Kueue をインストールしたら、次のセクションで説明するように、管理するインフラストラクチャを認識するように構成する必要があります。
GKE クラスタのトポロジを表示する
Spot VM としてプロビジョニングされた A4X、A4、A3 Ultra、A3 Mega、A3 High(GPU 数 8) ノードのトポロジを表示する前に、 コンパクト プレースメントを GKE ノードに定義して、TAS の物理トポロジを公開する必要があります。それ以外の場合はエラーが発生します。
特定のノードプール内の GKE クラスタノードのトポロジを表示するには、次のコマンドを実行します。
kubectl get nodes -l cloud.google.com/gke-nodepool=NODE_POOL_NAME \
-ocustom-columns='NAME:.metadata.name,BLOCK:.metadata.labels.cloud\.google\.com/gce-topology-block,SUBBLOCK:.metadata.labels.cloud\.google\.com/gce-topology-subblock,HOST:.metadata.labels.cloud\.google\.com/gce-topology-host' | sort -k2,4
NODE_POOL_NAME は、ノードプールの名前に置き換えます。
出力の VM 上の GKE ノードの物理トポロジを把握するには、次のノードラベルを参照してください。
cloud.google.com/gce-topology-block: VM が配置されている予約済みブロックの組織固有の ID。cloud.google.com/gce-topology-subblock: VM が配置されているサブブロックの組織固有の ID。cloud.google.com/gce-topology-host: VM が配置されているホストの ID。kubernetes.io/hostname: Kubernetes ノードのホスト名。通常、このホスト名は GKE ノード名でもあります。
2 つの VM が共有するラベル値が多いほど、VM は物理的に近い場所に配置されます。これらの用語の詳細については、 用語をご覧ください。
Kueue を構成する
Kueue をインストールしたら、管理するインフラストラクチャを指定するように Kueue を構成する必要があります。通常、Kueue には、 ClusterQueue リソース 割り当て定義が必要です。これは、静的インフラストラクチャまたは クラスタの自動スケーリングが有効な動的インフラストラクチャのいずれかです。ClusterQueue は、ワークロードがリクエストするリソースが ClusterQueue で定義されたリソースプール以下の場合にのみ、ワークロードを受け入れます。このセクションで説明するように Kueue を構成すると、Kueue は TAS を使用して次のようにワークロードを受け入れます。
TAS ワークロード: Kueue は、物理 インフラストラクチャのトポロジと現在の使用状況の両方を確認します。
TAS 以外のワークロード: Kueue は、物理 インフラストラクチャのトポロジを確認しません。Kueue は構成で定義された割り当て全体を管理し、ノード割り当ては kube-scheduler に任せます。
ClusterQueue リソース割り当て定義を Kueue に提供する方法については、次の例をご覧ください。
非常に高い割り当て: Kueue は、リクエストされたリソースに基づいてワークロードの受け入れを停止することはほとんどありません。TAS の定義に基づいて、Kueue はインフラストラクチャ トポロジに基づいてワークロードを受け入れる場合と受け入れない場合があります。詳細については、非常に高いリソース割り当てをご覧ください。
現実的な割り当て: Kueue は、 ワークロードがリクエストするリソースがこのリソース割り当ての上限内にある場合にのみ、ワークロードを受け入れます。TAS の定義に基づいて、Kueue はワークロードを受け入れる前にインフラストラクチャ トポロジを確認します。詳細については、 現実的なリソース割り当てをご覧ください。
以降のセクションのリソース割り当てへの参照はすべて、ClusterQueue リソース割り当てを指します。
非常に高いリソース割り当て
次の例では、非常に高いリソース割り当てを使用しているため、Kueue は使用可能なリソース割り当てに基づいてワークロードを停止しません。代わりに、Kueue は使用可能なノードのトポロジ情報を使用して、トポロジをワークロードの要件に一致させようとします。
次のリソース割り当て定義を使用する手順は次のとおりです。
任意のファイル エディタを開きます。次に、次の割り当て定義を
kueue-tas-config-very-high-quota.yamlという名前の YAML ファイルに含めます。apiVersion: kueue.x-k8s.io/v1alpha1 kind: Topology metadata: name: "gke-default" spec: levels: - nodeLabel: "cloud.google.com/gce-topology-block" - nodeLabel: "cloud.google.com/gce-topology-subblock" - nodeLabel: "cloud.google.com/gce-topology-host" - nodeLabel: "kubernetes.io/hostname" --- kind: ResourceFlavor apiVersion: kueue.x-k8s.io/v1beta1 metadata: name: "tas-flavor" spec: nodeLabels: cloud.google.com/gke-nodepool: "NODE_POOL_NAME" topologyName: "gke-default" tolerations: - key: "nvidia.com/gpu" operator: "Exists" effect: NoSchedule --- apiVersion: kueue.x-k8s.io/v1beta1 kind: ClusterQueue metadata: name: "tas-cluster-queue" spec: namespaceSelector: {} resourceGroups: - coveredResources: ["nvidia.com/gpu"] flavors: - name: "tas-flavor" resources: - name: "nvidia.com/gpu" nominalQuota: 10000000 --- apiVersion: kueue.x-k8s.io/v1beta1 kind: LocalQueue metadata: namespace: "default" name: "tas-user-queue" spec: clusterQueue: "tas-cluster-queue"NODE_POOL_NAMEは、ノードプールの名前に置き換えます。Kueue ジョブ キューイング システムのリソース割り当て構成を作成して適用します。
kubectl create -f kueue-tas-config-very-high-quota.yaml
現実的なリソース割り当て
前の例では、GPU リソースのみを構成しました。ただし、Kueue は Kubernetes 互換のすべてのリソースを管理できます。
次の例では、CPU、メモリ、GPU など、より現実的なリソース割り当てを定義します。これは 100 台の a3-ultragpu-8g マシン用です。1 台のマシンには、224 個の vCPU、2,944 GB のメモリ、8 個の GPU が搭載されています。
次のリソース割り当て定義を使用する手順は次のとおりです。
任意のファイル エディタを開きます。次に、次の割り当て定義を
kueue-tas-config-real-quota.yamlという名前の YAML ファイルに含めます。apiVersion: kueue.x-k8s.io/v1alpha1 kind: Topology metadata: name: "gke-default" spec: levels: - nodeLabel: "cloud.google.com/gce-topology-block" - nodeLabel: "cloud.google.com/gce-topology-subblock" - nodeLabel: "cloud.google.com/gce-topology-host" - nodeLabel: "kubernetes.io/hostname" --- kind: ResourceFlavor apiVersion: kueue.x-k8s.io/v1beta1 metadata: name: "tas-flavor" spec: nodeLabels: cloud.google.com/gke-nodepool: "NODE_POOL_NAME" topologyName: "gke-default" tolerations: - key: "nvidia.com/gpu" operator: "Exists" effect: NoSchedule --- apiVersion: kueue.x-k8s.io/v1beta1 kind: ClusterQueue metadata: name: "tas-cluster-queue" spec: namespaceSelector: {} # match all resourceGroups: - coveredResources: ["cpu", "memory", "nvidia.com/gpu"] flavors: - name: "tas-flavor" resources: # numbers below represent quota of 100 a3-ultragpu-8g machines - name: "cpu" nominalQuota: 22400 - name: "memory" nominalQuota: 294400Gi - name: "nvidia.com/gpu" nominalQuota: 800 --- apiVersion: kueue.x-k8s.io/v1beta1 kind: LocalQueue metadata: namespace: "default" name: "tas-user-queue" spec: clusterQueue: "tas-cluster-queue"NODE_POOL_NAMEは、ノードプールの名前に置き換えます。Kueue ジョブ キューイング システムのリソース割り当て構成を作成して適用します。
kubectl create -f kueue-tas-config-real-quota.yaml出力は次のようになります。
topology.kueue.x-k8s.io/gke-default created resourceflavor.kueue.x-k8s.io/tas-flavor created clusterqueue.kueue.x-k8s.io/tas-cluster-queue created localqueue.kueue.x-k8s.io/tas-user-queue created
Kueue を使用して TAS でワークロードをスケジュールする
次のシナリオでは、トポロジ リクエスト タイプとトポロジ リクエスト レベルを使用して、一般的なワークロードとインフラストラクチャの組み合わせを管理するように Kueue と TAS に指示する方法を示します。
使用可能なトポロジ リクエスト タイプ(優先または必須)は次のとおりです。
kueue.x-k8s.io/podset-preferred-topology: Kueue は、特定のトポロジ レベル内でワークロード全体をスケジュールすることを優先しますが、このトポロジ レベルに収まらないワークロードも受け入れます。単一のトポロジ レベルに収まる可能性のあるワークロードの場合、Kueue はそのワークロードをそのトポロジ レベルの複数のインスタンスにスケジュールする可能性があります。kueue.x-k8s.io/podset-required-topology: ワークロード全体が選択したトポロジ レベルに収まるまで、Kueue はこのワークロードの受け入れを試行し続けます。
使用可能なトポロジ リクエスト レベルは次のとおりです。Job の実行を優先または 必須とする物理インフラストラクチャをより具体的に指定できます。
cloud.google.com/gce-topology-blockcloud.google.com/gce-topology-subblockcloud.google.com/gce-topology-hostkubernetes.io/hostname
これらの値を使用してワークロードをスケジュールするには、次の Job YAML ファイルを使用します。
apiVersion: batch/v1
kind: Job
metadata:
generateName: JOB_NAME
labels:
kueue.x-k8s.io/queue-name: tas-user-queue
spec:
parallelism: NUMBER_OF_REPLICAS
completions: NUMBER_OF_REPLICAS
completionMode: Indexed
template:
metadata:
annotations:
ANNOTATIONS_STRING
spec:
containers:
- name: dummy-job
image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
args: ["60s"]
resources:
requests:
nvidia.com/gpu: "1"
limits:
nvidia.com/gpu: "1"
restartPolicy: Never
次の変数を置き換えます。
JOB_NAME: Job の名前。NUMBER_OF_REPLICAS: 並行して実行されている Pod の数。ANNOTATIONS_STRING: 次の表をご覧ください。リクエストされたトポロジ タイプとレベル 説明 ANNOTATIONS_STRINGホスト名 内で実行することを優先 (推奨) この構成では、容量が断片化されていても、ワークロードのリソース要件を満たすのに十分なリソースが使用可能であれば、ワークロードを受け入れます。Kueue は、Pod をできるだけコンパクトにスケジュールします。 kueue.x-k8s.io/podset-preferred-topology: "kubernetes.io/hostname"ホスト 内で実行することが必須 この構成では、ワークロードのリソース要件を満たすのに十分なリソースを持つホストが使用可能な場合にのみ、ワークロードを受け入れます。
これは、ホストごとに複数の VM がある場合(小規模なマシンタイプなど)や、1 つのノードで複数の Pod を実行できる場合に便利です。このような場合、ワークロードが受け入れられると、単一のホストで実行されます。
kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-host"ホスト 内で実行することを優先 この構成では、容量が断片化されていても、ワークロードのリソース要件を満たすのに十分なリソースが使用可能であれば、ワークロードを受け入れます。Kueue は、ホスト内で Pod をスケジュールしようとし、必要に応じて追加のホストを使用します。 kueue.x-k8s.io/podset-preferred-topology: "cloud.google.com/gce-topology-host"サブブロック 内で実行することが必須 この構成では、ワークロードのリソース要件を満たすのに十分なリソースを持つサブブロックが使用可能な場合にのみ、ワークロードを受け入れます。 kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-subblock"サブブロック 内で実行することを優先 この構成では、容量が断片化されていても、ワークロードのリソース要件を満たすのに十分なリソースが使用可能であれば、ワークロードを受け入れます。Kueue は、サブブロック内で Pod をスケジュールしようとし、必要に応じて追加のサブブロックを使用します。この場合、Kueue は、要件を満たすのに十分な容量を持つサブブロックと比較して、断片化されていても使用可能な容量が多いサブブロックを上位にランク付けします。 kueue.x-k8s.io/podset-preferred-topology: "cloud.google.com/gce-topology-subblock"ブロック 内で実行することが必須 この構成では、ブロック内で使用可能なリソースがワークロードのリソース要件を満たす場合にのみ、ワークロードを受け入れます。受け入れられた場合、Kueue はワークロードをスケジュールするサブブロックとホストの数を最小限に抑えます。これにより、使用可能な容量が断片化される可能性があります。 kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"ブロック 内で実行することを優先 この構成では、容量が断片化されていても、ワークロードのリソース要件を満たすのに十分なリソースが使用可能であれば、ワークロードを受け入れます。Kueue は、ブロック内で Pod をスケジュールしようとし、必要に応じて追加のブロックを使用します。 kueue.x-k8s.io/podset-preferred-topology: "cloud.google.com/gce-topology-block"
Kueue を使用して TAS で PodGroup を使用してワークロードをスケジュールする
PodGroup を使用する場合は、PodGroup 内のすべての Pod に対して 3 つの追加フィールドを指定する必要があります。
ラベル:
kueue.x-k8s.io/pod-group-name: 集約に使用される PodGroup の名前。
kueue.x-k8s.io/pod-group-pod-index: PodGroup 内の個々の Pod のインデックス。
アノテーション:
- kueue.x-k8s.io/pod-group-total-count: PodGroup 内の Pod の合計数。
使用する ML フレームワークに応じて、PodGroup のリーダーに GPU が必要な場合と不要な場合があります。Kueue の制限により、これらのケースは別々に処理する必要があります。次の例では、1 つのリーダーと 2 つのワーカーで構成される 3 つの Pod の PodGroup を作成する方法を示します。
ケース 1: リーダーもワーカーであり、GPU が必要
リーダーがワーカーの 1 つであり、GPU も必要な場合、リーダーは PodGroup 内の任意の数を持つことができます。簡単にするため、次の例ではリーダーのインデックスは 0 です。
apiVersion: v1
kind: Pod
metadata:
generateName: tas-podgroup-leader-
labels:
kueue.x-k8s.io/queue-name: tas-user-queue
kueue.x-k8s.io/pod-group-name: "tas-podgroup-example-group"
kueue.x-k8s.io/pod-group-pod-index: "0"
annotations:
kueue.x-k8s.io/pod-group-total-count: "3"
kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"
spec:
containers:
- name: leader
image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
args: ["600s"]
resources:
requests:
nvidia.com/gpu: "1"
limits:
nvidia.com/gpu: "1"
restartPolicy: Never
---
apiVersion: v1
kind: Pod
metadata:
generateName: tas-podgroup-worker-1-
labels:
kueue.x-k8s.io/queue-name: tas-user-queue
kueue.x-k8s.io/pod-group-name: "tas-podgroup-example-group"
kueue.x-k8s.io/pod-group-pod-index: "1"
annotations:
kueue.x-k8s.io/pod-group-total-count: "3"
kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"
spec:
restartPolicy: Never
containers:
- name: worker
image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
args: ["600s"]
resources:
requests:
nvidia.com/gpu: "1"
limits:
nvidia.com/gpu: "1"
---
apiVersion: v1
kind: Pod
metadata:
generateName: tas-podgroup-worker-2-
labels:
kueue.x-k8s.io/queue-name: tas-user-queue
kueue.x-k8s.io/pod-group-name: "tas-podgroup-example-group"
kueue.x-k8s.io/pod-group-pod-index: "2"
annotations:
kueue.x-k8s.io/pod-group-total-count: "3"
kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"
spec:
restartPolicy: Never
containers:
- name: worker
image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
args: ["600s"]
resources:
requests:
nvidia.com/gpu: "1"
limits:
nvidia.com/gpu: "1"
ケース 2: リーダーはワーカーではなく、GPU は不要
Kueue の制限により、リーダーがワーカーの 1 つでない場合、Kueue が PodSet を作成する方法により、リーダーは PodGroup の最後のインデックスを持つ必要があります。リーダーが最後のインデックスを持たず、最初のワーカーが最初のインデックスを使用しない場合、Kueue はランク割り当てを適用しません。
次の例をご覧ください。
---
apiVersion: v1
kind: Pod
metadata:
generateName: tas-podgroup-leader-
labels:
kueue.x-k8s.io/queue-name: tas-user-queue
kueue.x-k8s.io/pod-group-name: "tas-podgroup-example-group2"
kueue.x-k8s.io/pod-group-pod-index: "2"
annotations:
kueue.x-k8s.io/pod-group-total-count: "3"
kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"
spec:
containers:
- name: leader
image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
args: ["600s"]
resources:
requests:
cpu: "1"
limits:
cpu: "1"
restartPolicy: Never
---
apiVersion: v1
kind: Pod
metadata:
generateName: tas-podgroup-worker-0-
labels:
kueue.x-k8s.io/queue-name: tas-user-queue
kueue.x-k8s.io/pod-group-name: "tas-podgroup-example-group2"
kueue.x-k8s.io/pod-group-pod-index: "0"
annotations:
kueue.x-k8s.io/pod-group-total-count: "3"
kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"
spec:
restartPolicy: Never
containers:
- name: worker
image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
args: ["600s"]
resources:
requests:
nvidia.com/gpu: "1"
limits:
nvidia.com/gpu: "1"
---
apiVersion: v1
kind: Pod
metadata:
generateName: tas-podgroup-worker-1-
labels:
kueue.x-k8s.io/queue-name: tas-user-queue
kueue.x-k8s.io/pod-group-name: "tas-podgroup-example-group2"
kueue.x-k8s.io/pod-group-pod-index: "1"
annotations:
kueue.x-k8s.io/pod-group-total-count: "3"
kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"
spec:
restartPolicy: Never
containers:
- name: worker
image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
args: ["600s"]
resources:
requests:
nvidia.com/gpu: "1"
limits:
nvidia.com/gpu: "1"
次のステップ
GKE クラスタでヘルスノード予測を有効にする方法については、 ノードのヘルス予測を有効にするをご覧ください。
GKE クラスタと AI ワークロードに関連する一般的なイベントの管理については、 AI 最適化 GKE クラスタを管理するをご覧ください。
Kueue を使用して GKE でジョブをスケジュールする方法については、 Kueue を使用してバッチシステムをデプロイするをご覧ください。