このページでは、Standard モードの Google Kubernetes Engine(GKE)クラスタで高性能 GPU ワークロードのネットワーク帯域幅とスループットを最大にする方法について説明します。このページは、ML ワークロードを利用する機械学習(ML)エンジニアとプラットフォーム管理者を対象としています。ネットワーク インターフェース カード(NIC)や TCP などのネットワーク テクノロジーと、NVIDIA Collective Communications Library(NCCL)などのアクセラレータ テクノロジーに精通している必要があります。
人工知能(AI)、ML、ハイ パフォーマンス コンピューティング(HPC)アプリケーションでは、ジョブの完了時間を短縮してパフォーマンスを最適化するために、強力なアクセラレーションが必要となります。たとえば、会話型 AI と画像生成に焦点を当てた ML モデルには、高いスケーラビリティとコンピューティング能力が求められます。
Google Cloud GPU スーパーコンピュータについて
Google Cloud には、スケーラブルで大規模なモデル用に構築され、アクセラレータ用に最適化されたスーパーコンピュータがあります。このマシンには次のような利点があります。
- 1 マシンあたり 8 個の NVIDIA H100 GPU。
- プライマリ NIC で最大 200 Gbps の帯域幅。
- 最大 4 つのセカンダリ NIC。それぞれが GPU データ転送用に最大 200 Gbps の帯域幅をサポート。
利点の詳細については、Compute Engine ドキュメントの A3 マシンシリーズをご覧ください。
GKE ワークロードでは、単一ノードで使用可能なすべての GPU とセカンダリ NIC を使用し、使用可能な帯域幅の大半を使用する必要があります。このドキュメントで説明するソリューションは、高パフォーマンス、高スループット、低レイテンシを必要とするワークロードに最適です。
帯域幅を最大化するために必要な機能
GPU スーパーコンピュータ ノードのネットワーク帯域幅を最大化するには、次の機能をすべて使用します。
- GPUDirect-TCPX: GPU との間のパケット ペイロードの転送に必要なオーバーヘッドを削減します。GPUDirect-TCPX を使用しない GPU と比較するとスループットが大幅に向上します。
- gVNIC: パケット ヘッダー分割、フロー ステアリング、バッファ管理などの GPUDirect-TCPX 機能を有効にします。GPUDirect-TCPX を使用するには、gVNIC が必要です。gVNIC の詳細については、GPU ノードのネットワーク トラフィック速度を上げるをご覧ください。
- マルチネットワーキング: アクセラレータ最適化マシンにセカンダリ NIC を追加します。A3 マシンの場合、NIC が 4 つ追加されます。競合を避けるため、各 NIC はそれぞれの VPC 内の個別のサブネットに関連付けられます。マルチネットワーク サポートの詳細については、Pod のマルチネットワーク サポートを設定するをご覧ください。
- 配置ポリシー: リソース配置ポリシーを使用して、特定のワークロードのすべての GPU ノードを物理的に近いサーバーに配置し、レイテンシを最小限に抑えます。詳細については、GKE ノードのコンパクト プレースメントを定義するをご覧ください。
手順の概要
これらの機能をすべて一緒に使用する手順は次のとおりです。
- Virtual Private Cloud(VPC)とサブネットを作成する
- GKE 環境を作成します。
- マルチネットワーキングを有効にしたクラスタを作成する
- 次の特性を持つノードプールを作成します。
- gVNIC が有効
- 各セカンダリ NIC に指定されたマルチネットワーキング サブネット
- ノードをバックアップする H100 GPU(4 つのセカンダリ NIC と 8 つの GPU)を備えた A3 マシンシリーズ
- 最新の NVIDIA ドライバのインストール
- GPUDirect-TCPX バイナリと NCCL プラグインをインストールする
- テスト ワークロードをデプロイして GPUDirect-TCPX の設定を確認する
始める前に
作業を始める前に、次のことを確認してください。
- Google Kubernetes Engine API を有効にします。 Google Kubernetes Engine API の有効化
- このタスクに Google Cloud CLI を使用する場合は、gcloud CLI をインストールして初期化します。すでに gcloud CLI をインストールしている場合は、
gcloud components update
を実行して最新のバージョンを取得します。
- H100 GPU に十分な割り当てがあることを確認します。追加の割り当てをリクエストするには、GPU 割り当てをご覧ください。
要件
- GPUDirect-TCPX は GKE バージョン 1.27 以降でサポートされており、要件は次のとおりです。
- GKE バージョン 1.27 の場合は、GKE パッチ バージョン 1.27.7-gke.1121000 以降を使用します。
- GKE バージョン 1.28 の場合は、GKE パッチ バージョン 1.28.8-gke.1095000 以降を使用します。
- GKE バージョン 1.29 の場合は、GKE パッチ バージョン 1.29.3-gke.1093000 以降を使用します。
- GPU ノードでは、NVIDIA ドライバ バージョン 535 以降を使用する必要があります。
- GKE Dataplane V2 を使用する必要があります。
制限事項
次の制限が適用されます。
- Autopilot クラスタで GPUDirect-TCPX を使用できない
- GPUDirect-TCPX は、GKE バージョン 1.27 以降で、次のパッチ バージョンを使用する場合にのみ使用できます。
- GKE バージョン 1.27 の場合は、GKE パッチ バージョン 1.27.7-gke.1121000 以降を使用します。
- GKE バージョン 1.28 の場合は、GKE パッチ バージョン 1.28.8-gke.1095000 以降を使用します。
- GKE バージョン 1.29 の場合は、GKE パッチ バージョン 1.29.3-gke.1093000 以降を使用します。
- GPUDirect-TCPX は、マルチインスタンス GPU または GPU タイム シェアリングでは使用できません。
- NCCL FastSocket は使用できません。
- ご使用の環境の Pod 仕様で
hostNetwork: true
の設定がサポートされている必要があります。 Pod ストレージにローカル SSD を使用するには、
--ephemeral-storage-local-ssd=count=SSD_COUNT
フラグ(エフェメラル ストレージの場合)または--local-nvme-ssd-block=count=SSD_COUNT
フラグ(ブロック アクセスの場合)を使用して、基盤となる A3 VM にアタッチするローカル SSD の正確な数を指定する必要があります。このフラグを省略すると、Pod でローカル SSD を使用できなくなります。これらのフラグは、データアクセスにローカル SSD を使用する場合にのみ必要です。GKE でサポートされているマシンサイズは
a3-highgpu-8g
で、対応するローカル SSD の数は16
です。
VPC とサブネットを作成する
ノードに追加する仮想 NIC ごとに、プロジェクト内に個別の VPC ネットワークを作成します。各 VPC には、内部ネットワーク トラフィックを許可するサブネットとファイアウォール ルールが必要です。帯域幅を最大にするため、4 つの新しいネットワークを作成することをおすすめします。
プロジェクト内のデフォルトの VPC サブネットワークを更新して、Pod と Service のセカンダリ IP アドレス範囲を追加します。
gcloud compute networks subnets update DEFAULT_NETWORK \ --region=REGION \ --add-secondary-ranges="CLUSTER_NAME-pods=POD_IP_ADDRESS_RANGE,CLUSTER_NAME-services=SERVICE_IP_ADDRESS_RANGE"
次のように置き換えます。
DEFAULT_NETWORK
: プロジェクトのデフォルト サブネットの名前。REGION
: デフォルト サブネットのリージョン。CLUSTER_NAME
: GKE クラスタの名前。POD_IP_ADDRESS_RANGE
: クラスタ内の Pod が使用する IP アドレス範囲(CIDR 表記)。例:10.64.0.0/19
SERVICE_IP_ADDRESS_RANGE
: クラスタ内の Service が使用する IP アドレス範囲(CIDR 表記)。Pod の範囲とは異なる必要があります。例:10.65.0.0/19
プロジェクトに GPUDirect-TCPX の VPC ネットワークを作成し、それぞれにサブネットとファイアウォール ルールを設定します。
for N in $(seq 1 4); do gcloud compute networks create PROJECT_ID-net-$N \ --subnet-mode=custom \ --mtu=8244 gcloud compute networks subnets create PROJECT_ID-sub-$N \ --network=PROJECT_ID-net-$N \ --region=REGION \ --range=SUBNET_RANGE gcloud compute firewall-rules create PROJECT_ID-internal-$N \ --network=PROJECT_ID-net-$N \ --action=ALLOW \ --rules=tcp:0-65535,udp:0-65535,icmp \ --source-ranges=SOURCE_RANGE done
次のように置き換えます。
PROJECT_ID
: Google Cloud プロジェクト ID。REGION
: 各サブネットの Compute Engine リージョン。SUBNET_RANGE
: 各サブネットの IP アドレス範囲(CIDR 表記)。この例のコマンドは 4 つのサブネットに対して繰り返し使用します。このため、変数を使用して各サブネットの IP アドレスを変更します。たとえば、最初のサブネットで192.168.1.0/24
を使用し、2 番目のサブネットで192.168.2.0/24
を使用するように192.168.$N.0/24
を指定します。SOURCE_RANGE
: 上り(内向き)トラフィックを許可するファイアウォール ルールの送信元 IP アドレス範囲(CIDR 表記)。例:192.168.0.0/16
ネットワークが作成されたことを確認します。
gcloud compute networks list
GKE 環境を作成する
マルチネットワーキング(プレビュー)を使用する新しい GKE クラスタを作成し、H100 GPU と 4 つの追加 NIC が接続された A3 マシンを使用する GPU ノードプールを作成します。マルチネットワーキングを使用するように既存のクラスタを更新することはできません。
クラスタを作成します。
gcloud container clusters create CLUSTER_NAME \ --location=LOCATION \ --cluster-version=VERSION \ --enable-dataplane-v2 --enable-ip-alias \ --enable-multi-networking \ --no-enable-autoupgrade \ --cluster-secondary-range-name=CLUSTER_NAME-pods \ --services-secondary-range-name=CLUSTER_NAME-services
次のように置き換えます。
CLUSTER_NAME
: 新しいクラスタの名前LOCATION
: クラスタの Compute Engine のリージョンVERSION
: クラスタの GKE バージョン。要件セクションで説明されているサポート対象バージョンである必要があります。
また、このコマンドでは、前のセクションで作成したクラスタの Pod と Service のセカンダリ IP アドレスを明示的に指定します。
作成した VPC ネットワークとサブネットワークに対応する Network リソースと GKENetworkParamSet リソースをクラスタに作成します。
kubectl apply -f - <<EOF apiVersion: networking.gke.io/v1 kind: Network metadata: name: vpc1 spec: parametersRef: group: networking.gke.io kind: GKENetworkParamSet name: vpc1 type: Device --- apiVersion: networking.gke.io/v1 kind: Network metadata: name: vpc2 spec: parametersRef: group: networking.gke.io kind: GKENetworkParamSet name: vpc2 type: Device --- apiVersion: networking.gke.io/v1 kind: Network metadata: name: vpc3 spec: parametersRef: group: networking.gke.io kind: GKENetworkParamSet name: vpc3 type: Device --- apiVersion: networking.gke.io/v1 kind: Network metadata: name: vpc4 spec: parametersRef: group: networking.gke.io kind: GKENetworkParamSet name: vpc4 type: Device --- apiVersion: networking.gke.io/v1 kind: GKENetworkParamSet metadata: name: vpc1 spec: vpc: PROJECT_ID-net-1 vpcSubnet: PROJECT_ID-sub-1 deviceMode: NetDevice --- apiVersion: networking.gke.io/v1 kind: GKENetworkParamSet metadata: name: vpc2 spec: vpc: PROJECT_ID-net-2 vpcSubnet: PROJECT_ID-sub-2 deviceMode: NetDevice --- apiVersion: networking.gke.io/v1 kind: GKENetworkParamSet metadata: name: vpc3 spec: vpc: PROJECT_ID-net-3 vpcSubnet: PROJECT_ID-sub-3 deviceMode: NetDevice --- apiVersion: networking.gke.io/v1 kind: GKENetworkParamSet metadata: name: vpc4 spec: vpc: PROJECT_ID-net-4 vpcSubnet: PROJECT_ID-sub-4 deviceMode: NetDevice EOF
これらのリソースは、パススルー モードで GPU トラフィックの NIC を構成するように GKE に指示します。このトラフィックには、eBPF を使用した組み込みネットワーキング プログラミングは適用されません。
H100 GPU 用のノードプールを作成します。
gcloud container node-pools create NODE_POOL_NAME \ --cluster=CLUSTER_NAME \ --location=LOCATION \ --machine-type=a3-highgpu-8g \ --accelerator=type=nvidia-h100-80gb,count=8,gpu-driver-version=LATEST \ --additional-node-network=network=PROJECT_ID-net-1,subnetwork=PROJECT_ID-sub-1 \ --additional-node-network=network=PROJECT_ID-net-2,subnetwork=PROJECT_ID-sub-2 \ --additional-node-network=network=PROJECT_ID-net-3,subnetwork=PROJECT_ID-sub-3 \ --additional-node-network=network=PROJECT_ID-net-4,subnetwork=PROJECT_ID-sub-4 \ --enable-gvnic \ --no-enable-autoupgrade \ [--ephemeral-storage-local-ssd=count=16]
NODE_POOL_NAME
は、ノードプールの名前に置き換えます。このコマンドが失敗した場合、プロジェクトに十分な H100 GPU 割り当てがない可能性があります。割り当てがあることを確認してから、コマンドを再試行してください。
クラスタ内のノードのリストを取得します。
kubectl get nodes
各 GPU ノードに 8 つの GPU があることを確認します。
kubectl describe node NODE_NAME
出力は次のようになります。
Capacity: ... nvidia.com/gpu: 8 Allocatable: ... nvidia.com/gpu: 8
GPUDirect-TCPX をインストールして NCCL を構成する
このセクションでは、DaemonSet を使用して GPUDirect-TCPX バイナリと特定の NCCL をインストールする方法について説明します。
DaemonSet マニフェストを確認します。
この DaemonSet は次の処理を行います。
- NCCL ライブラリと GPUDirect-TCPX バイナリをノードにインストールします。
- ライブラリとバイナリを VM の
/home/kubernetes/bin/nvidia/lib64
ディレクトリに保存します。デフォルトでは、このディレクトリは NCCL と GPUDirect-TCPX を使用する必要のある GPU コンテナの/usr/local/nvidia/lib64
パスにマウントされます。
DaemonSet をデプロイします。
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/master/gpudirect-tcpx/nccl-tcpx-installer.yaml
NCCL プラグインの実行が開始するまで 2 分ほどかかります。
DaemonSet Pod のステータスを確認します。
kubectl get pods -n=kube-system -l=name=nccl-tcpx-installer
出力は次のようになります。
nccl-tcpx-installer-6c2pv 1/1 Running 0 2m11s nccl-tcpx-installer-qgg82 1/1 Running 0 2m11s
テスト ワークロードをデプロイする
このセクションでは、サンプル ワークロードをデプロイし、NCCL と GPUDirect-TCPX が期待どおりに動作することを確認します。このワークロードには、Pod が GPUDirect-TCPX を使用できるようにするサービスを実行する tcpx-daemon というサイドカー コンテナが含まれています。このサイドカー コンテナは、GPUDirect-TCPX を使用する独自の環境の Pod に追加する必要があります。マニフェストに追加する必須フィールドのスニペットについては、このドキュメントのマニフェストに GPUDirect-TCPX を追加するをご覧ください。
- GitHub の
nccl-config-default.yaml
ConfigMap マニフェストを確認します。このマニフェストでは、NCCL Allgather テストを初期化し、NCCL 固有の環境変数を設定するスクリプトをデプロイします。 GitHub の
nccl-test.yaml
マニフェストを確認します。このマニフェストの内容は次のとおりです。- 2 つの Pod をデプロイします。各 Pod は、H100 GPU を備えたノードで実行されます。
- 各 Pod に
tcpx-daemon
というサイドカー コンテナをデプロイして、これらの Pod が GPUDirect-TCPX を使用できるようにします。
ConfigMap とテスト ワークロードをデプロイします。
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/master/gpudirect-tcpx/nccl-config-default.yaml kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/master/gpudirect-tcpx/nccl-test.yaml
次のコマンドを実行して、ノードの NCCL all-gather テストをトリガーします。
head_pod=$(kubectl get pods --output='custom-columns=POD:.metadata.name' --no-headers | head -n1) nodes=($(kubectl get pods --output='custom-columns=NODE:.spec.nodeName' --no-headers)) kubectl exec --stdin --tty --container=nccl-test ${head_pod} -- /configs/allgather.sh ${nodes[@]}
出力は次のようになります。
# out-of-place in-place # size count type redop root time algbw busbw #wrong time algbw busbw #wrong # (B) (elements) (us) (GB/s) (GB/s) (us) (GB/s) (GB/s) 1048576 16384 float none -1 696.8 1.50 1.41 0 729.0 1.44 1.35 0 2097152 32768 float none -1 776.4 2.70 2.53 0 726.7 2.89 2.71 0 4194304 65536 float none -1 774.3 5.42 5.08 0 805.1 5.21 4.88 0 8388608 131072 float none -1 812.1 10.33 9.68 0 817.6 10.26 9.62 0 16777216 262144 float none -1 1035.2 16.21 15.19 0 1067.8 15.71 14.73 0 33554432 524288 float none -1 1183.3 28.36 26.59 0 1211.8 27.69 25.96 0 67108864 1048576 float none -1 1593.4 42.12 39.49 0 1510.5 44.43 41.65 0 134217728 2097152 float none -1 2127.8 63.08 59.13 0 2312.7 58.03 54.41 0 268435456 4194304 float none -1 3603.0 74.50 69.85 0 3586.2 74.85 70.17 0 536870912 8388608 float none -1 7101.7 75.60 70.87 0 7060.9 76.03 71.28 0 # Out of bounds values : 0 OK # Avg bus bandwidth : 29.8293
NCCL 環境変数を使用してパフォーマンスを改善する
必要に応じて、特定の環境変数を設定して、NCCL を使用するワークロードのパフォーマンスを向上させることができます。テスト ワークロードをデプロイするでデプロイする nccl-config-default.yaml
ConfigMap では、デフォルトでいくつかの NCCL 変数を設定しています。変数の構成は、ConfigMap の run-nccl.sh
スクリプトに保存されます。
NCCL 環境変数を変更するには、変更した変数で更新した ConfigMap マニフェストをデプロイします。GitHub の nccl-config-latest.yaml
マニフェストには、更新された run-nccl.sh
スクリプトを含む推奨変数がすべて含まれています。
次のコマンドは、更新された nccl-config-latest.yaml
ConfigMap でデフォルトの変数を持つ既存の ConfigMap を更新します。
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/master/gpudirect-tcpx/nccl-config-latest.yaml
Kubernetes が ConfigMap を更新するまでに 2 分ほどかかります。
NCCL 環境変数を確認するには、次のコマンドを実行します。
head_pod=$(kubectl get pods --output='custom-columns=POD:.metadata.name' --no-headers | head -n1)
kubectl exec --stdin --tty --container=nccl-test ${head_pod} -- cat /configs/run-nccl.sh
GPUDirect-TCPX をマニフェストに追加する
このセクションでは、Pod で GPUDirect-TCPX を使用するために Kubernetes マニフェストに追加する必要がある必須フィールドについて説明します。
次のフィールドを Pod 仕様に追加します。
spec: hostNetwork: true dnsPolicy: ClusterFirstWithHostNet volumes: - name: libraries hostPath: path: /home/kubernetes/bin/nvidia/lib64 - name: tcpx-socket hostPath: path: /run/tcpx
マニフェストに次のコンテナを追加して、tcpx-daemon サービスを実行します。
- name: tcpx-daemon image: us-docker.pkg.dev/gce-ai-infra/gpudirect-tcpx/tcpgpudmarxd-dev:v2.0.9 command: - /tcpgpudmarxd/build/app/tcpgpudmarxd - --gpu_nic_preset - a3vm - --gpu_shmem_type - fd - --uds_path - /run/tcpx - --setup_param - \"--verbose 128 2 0 \" securityContext: privileged: true volumeMounts: - name: libraries mountPath: /usr/local/nvidia/lib64 - name: tcpx-socket mountPath: /run/tcpx env: - name: LD_LIBRARY_PATH value: /usr/local/nvidia/lib64
GPU をリクエストするコンテナに次のボリューム マウントを追加します。
volumeMounts: - name: tcpx-socket mountPath: /tmp - name: libraries mountPath: /usr/local/nvidia/lib64
すべての GPU コンテナに次の環境変数を追加します。
env: - name: LD_LIBRARY_PATH value: /usr/local/nvidia/lib64
必要に応じて、環境変数を追加して NCCL オプションを構成します。詳細については、このドキュメントの NCCL 環境変数を使用してパフォーマンスを改善するをご覧ください。
完成した Pod 仕様は次のようになります。
apiVersion: v1
kind: Pod
metadata:
name: example-pod
labels:
name: example-pod
spec:
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
containers:
- name: tcpx-daemon
image: us-docker.pkg.dev/gce-ai-infra/gpudirect-tcpx/tcpgpudmarxd-dev:v2.0.9
command:
- /tcpgpudmarxd/build/app/tcpgpudmarxd
- --gpu_nic_preset
- a3vm
- --gpu_shmem_type
- fd
- --uds_path
- /run/tcpx
- --setup_param
- \"--verbose 128 2 0 \"
securityContext:
privileged: true
volumeMounts:
- name: libraries
mountPath: /usr/local/nvidia/lib64
- name: tcpx-socket
mountPath: /run/tcpx
env:
- name: LD_LIBRARY_PATH
value: /usr/local/nvidia/lib64
- name: nccl-test
image: us-docker.pkg.dev/gce-ai-infra/gpudirect-tcpx/nccl-plugin-gpudirecttcpx:v3.1.2
imagePullPolicy: Always
command:
- /bin/sh
- -c
- "while true; do echo hello; sleep 1; done"
env:
- name: LD_LIBRARY_PATH
value: /usr/local/nvidia/lib64
volumeMounts:
- name: tcpx-socket
mountPath: /run/tcpx
- name: libraries
mountPath: /usr/local/nvidia/lib64
resources:
limits:
nvidia.com/gpu: 8
volumes:
- name: libraries
hostPath:
path: /home/kubernetes/bin/nvidia/lib64
- name: tcpx-socket
hostPath:
path: /run/tcpx