NVIDIA MPS を使用して GPU を複数のワークロードと共有する


このページでは、CUDA Multi-Process Service(MPS)を使用して、Google Kubernetes Engine(GKE)ノードで複数のワークロードが単一の NVIDIA GPU ハードウェア アクセラレータを共有できるようにする方法について説明します。

概要

NVIDIA MPS は、ノードに接続された単一の物理 NVIDIA GPU ハードウェアを複数のコンテナで共有できる GPU 共有ソリューションです。

NVIDIA MPS は、CUDA 上の NVIDIA の Multi-Process Service に依存しています。NVIDIA MPS は、CUDA API のバイナリ互換の代替実装です。これは、1 つの GPU デバイスで協調型マルチプロセス CUDA アプリケーションを同時に実行できるように設計されています。

NVIDIA MPS を使用すると、物理 GPU の最大共有コンテナ数を指定できます。この値は、次の特性に基づいて、各コンテナが取得する物理 GPU の量を決定します。

NVIDIA MPS でスケジュールされた GPU の詳細や、CUDA MPS を使用する必要がある場合については、GKE の GPU 共有ソリューションについてをご覧ください。

このガイドの対象者

このガイドの手順は、次のいずれかのユーザーを対象としています。

  • プラットフォーム管理者: GKE クラスタの作成と管理、インフラストラクチャとリソース要件の計画、クラスタのパフォーマンスのモニタリングを行います。
  • アプリケーション デベロッパー: GKE クラスタにワークロードを設計してデプロイします。GPU で NVIDIA MPS をリクエストする手順については、GPU で NVIDIA MPS を使用するワークロードをデプロイするをご覧ください。

要件

  • GKE バージョン: NVIDIA MPS による GPU 共有は、GKE バージョン 1.27.7-gke.1088000 以降を実行している GKE Standard クラスタで有効にできます。
  • GPU タイプ: すべての NVIDIA Tesla® GPU タイプで NVIDIA MPS を有効にできます。

始める前に

作業を始める前に、次のことを確認してください。

  • Google Kubernetes Engine API を有効にします。
  • Google Kubernetes Engine API の有効化
  • このタスクに Google Cloud CLI を使用する場合は、gcloud CLI をインストールして初期化します。すでに gcloud CLI をインストールしている場合は、gcloud components update を実行して最新のバージョンを取得します。

複数の GKE クラスタで GPU を使用した NVIDIA MPS を有効にする

プラットフォーム管理者は、GKE Standard クラスタで GPU を使用した NVIDIA MPS を有効にする必要があります。その後、アプリケーション デベロッパーは、GPU で NVIDIA MPS を使用するワークロードをデプロイできます。GKE で GPU を使用した NVIDIA MPS を有効にするには、次の操作を行います。

  1. 新しい GKE クラスタで、GPU を使用した NVIDIA MPS を有効にする
  2. NVIDIA GPU デバイス ドライバをインストールする(必要な場合)
  3. ノードで使用可能な GPU リソースを確認する

1 つの GKE クラスタで GPU を使用した NVIDIA MPS を有効にする

GKE Standard クラスタを作成するときに、GPU を使用した NVIDIA MPS を有効にできます。クラスタ内のデフォルトのノードプールでこの機能が有効になっています。クラスタで新しいノードプールを手動で作成する場合も、GPU を使用した NVIDIA MPS を有効にする必要があります。

Google Cloud CLI を使用して NVIDIA MPS を有効にしたクラスタを作成します。

gcloud container clusters create CLUSTER_NAME \
    --region=COMPUTE_REGION \
    --cluster-version=CLUSTER_VERSION \
    --machine-type=MACHINE_TYPE \
    --accelerator=type=GPU_TYPE,count=GPU_QUANTITY,gpu-sharing-strategy=mps,max-shared-clients-per-gpu=CLIENTS_PER_GPU,gpu-driver-version=DRIVER_VERSION

次のように置き換えます。

  • CLUSTER_NAME: 新しいクラスタの名前。
  • COMPUTE_REGION: 新しいクラスタの Compute Engine のリージョン。ゾーンクラスタの場合は、--zone=COMPUTE_ZONE を指定します。 使用する GPU タイプは、選択したゾーンで使用可能である必要があります。
  • CLUSTER_VERSION: クラスタ コントロール プレーンとノードの GKE バージョン。GKE バージョン 1.27.7-gke.1088000 以降を使用します。または、--release-channel=RELEASE_CHANNEL フラグを使用して、その GKE バージョンのリリース チャンネルを指定します。
  • MACHINE_TYPE: ノードの Compute Engine マシンタイプ。
  • GPU_TYPE: GPU タイプ。NVIDIA Tesla GPU プラットフォームnvidia-tesla-v100 など)である必要があります。
  • GPU_QUANTITY: デフォルトのノードプール内の各ノードに接続する物理 GPU の数。
  • CLIENTS_PER_GPU: 各物理 GPU を共有できるコンテナの最大数。
  • DRIVER_VERSION: インストールする NVIDIA ドライバのバージョン。次のいずれか 1 つを指定できます。
    • default: GKE バージョンのデフォルトのドライバ バージョンをインストールします。
    • latest: お使いの GKE バージョン向けの最新のドライバ バージョンをインストールします。Container-Optimized OS を使用するノードでのみ使用できます。
    • disabled: ドライバの自動インストールをスキップします。ノードプールを作成した後に、手動でドライバをインストールする必要がありますgpu-driver-version を省略すると、これがデフォルトのオプションになります。

新しいノードプールで GPU を使用した NVIDIA MPS を有効にする

GKE クラスタで新しいノードプールを手動で作成するときに、GPU を使用した NVIDIA MPS を有効にできます。Google Cloud CLI を使用して、NVIDIA MPS が有効なノードプールを作成します。

gcloud container node-pools create NODEPOOL_NAME \
    --cluster=CLUSTER_NAME \
    --machine-type=MACHINE_TYPE \
    --region=COMPUTE_REGION \
    --accelerator=type=GPU_TYPE,count=GPU_QUANTITY,gpu-sharing-strategy=mps,max-shared-clients-per-gpu=CONTAINER_PER_GPU,gpu-driver-version=DRIVER_VERSION

次のように置き換えます。

  • NODEPOOL_NAME: 新しいノードプールの名前。
  • CLUSTER_NAME: クラスタの名前。GKE バージョン 1.27.7-gke.1088000 以降を実行する必要があります。
  • COMPUTE_REGION: クラスタの Compute Engine のリージョン。ゾーンクラスタの場合は、--zone=COMPUTE_ZONE を指定します。
  • MACHINE_TYPE: ノードの Compute Engine マシンタイプ。A100 GPU の場合は、A2 マシンタイプを使用します。他のすべての GPU には、N1 マシンタイプを使用します。
  • GPU_TYPE: GPU タイプ。NVIDIA Tesla GPU プラットフォームnvidia-tesla-v100 など)である必要があります。
  • GPU_QUANTITY: ノードプール内の各ノードに接続する物理 GPU の数。
  • CONTAINER_PER_GPU: 各物理 GPU を共有できるコンテナの最大数。
  • DRIVER_VERSION: インストールする NVIDIA ドライバのバージョン。次のいずれか 1 つを指定できます。

    • default: GKE バージョンのデフォルトのドライバ バージョンをインストールします。
    • latest: お使いの GKE バージョン向けの最新のドライバ バージョンをインストールします。Container-Optimized OS を使用するノードでのみ使用できます。
    • disabled: ドライバの自動インストールをスキップします。ノードプールを作成した後に、手動でドライバをインストールする必要がありますgpu-driver-version を省略すると、これがデフォルトのオプションになります。

NVIDIA GPU デバイス ドライバをインストールする

クラスタの作成時にドライバの自動インストールを無効にすることを選択した場合、または 1.27.2-gke.1200 より前の GKE バージョンを使用している場合は、物理 GPU の NVIDIA MPS 分割を管理するために互換性のある NVIDIA ドライバを手動でインストールする必要があります。ドライバをインストールするには、ドライバを設定する GKE インストール DaemonSet をデプロイします。

手順については、NVIDIA GPU デバイス ドライバのインストールをご覧ください。

使用可能な GPU リソースを確認する

ノードの GPU の数が、NVIDIA MPS を有効にしたときに指定した数と一致するかどうか確認します。また、NVIDIA MPS 制御デーモンが実行されていることも確認します。

ノードで使用可能な GPU リソースを確認する

ノードで使用可能な GPU リソースを確認するには、次のコマンドを実行します。

kubectl describe nodes NODE_NAME

NODE_NAME は、いずれかのノードの名前に置き換えます。

出力は次のようになります。

...
Capacity:
  ...
  nvidia.com/gpu:             3
Allocatable:
  ...
  nvidia.com/gpu:             3

この出力では、次の値からノード上の GPU リソースの数が 3 であることを確認できます。

  • max-shared-clients-per-gpu の値は 3 です。
  • ノードに接続する物理 GPU の count1 です。物理 GPU の count2 の場合、割り当て可能な GPU リソースが 6 個であることが示されます(物理 GPU ごとに 3 個)。

MPS 制御デーモンが実行されていることを確認する

GPU デバイス プラグインは、MPS 制御デーモンのヘルスチェックを実行します。MPS 制御デーモンが正常な状態になったら、コンテナをデプロイできます。

MPS のステータスを確認するには、次のコマンドを実行します。

kubectl logs -l k8s-app=nvidia-gpu-device-plugin -n kube-system --tail=100 | grep MPS

出力は次のようになります。

I1118 08:08:41.732875       1 nvidia_gpu.go:75] device-plugin started
...
I1110 18:57:54.224832       1 manager.go:285] MPS is healthy, active thread percentage = 100.0
...

出力には、次のようなイベントが発生したことが示されます。

  • failed to start GPU device manager エラーが MPS is healthy エラーの前に表示されます。このエラーは一時的なものです。MPS is healthy メッセージが表示される場合は、制御デーモンが実行されています。
  • active thread percentage = 100.0 メッセージは、物理 GPU リソース全体が完全にアクティブなスレッドであることを意味します。

MPS を使用するワークロードをデプロイする

GPU ワークロードをデプロイするアプリケーション オペレーターは、同じ物理 GPU で MPS 共有ユニットを共有するように GKE に指示できます。次のマニフェストでは、1 つの物理 GPU をリクエストし、max-shared-clients-per-gpu=3 を設定します。物理 GPU は 3 つの MPS 共有ユニットを取得し、3 つの Pod(コンテナ)を並行して実行する nvidia/samples:nbody Job を開始します。

  1. マニフェストを gpu-mps.yaml として保存します。

      apiVersion: batch/v1
      kind: Job
      metadata:
        name: nbody-sample
      spec:
        completions: 3
        parallelism: 3
        template:
          spec:
            hostIPC: true
            nodeSelector:
              cloud.google.com/gke-gpu-sharing-strategy: mps
            containers:
              - name: nbody-sample
                image: nvidia/samples:nbody
                command: ["/tmp/nbody"]
                args: ["-benchmark", "-i=5000"]
                resources:
                  limits:
                    nvidia.com/gpu: 1
            restartPolicy: "Never"
        backoffLimit: 1
    

    このマニフェストの内容:

    • hostIPC: true により、Pod は MPS 制御デーモンと通信できます。これは必須です。ただし、hostIPC: true 構成では、コンテナがホストリソースにアクセスできるため、セキュリティ リスクが発生します。
    • ベンチマーク モードで 5,000 回の反復を実行します。
  2. 次のようにマニフェストを適用します。

    kubectl apply -f gpu-mps.yaml
    
  3. すべての Pod が実行されていることを確認します。

    kubectl get pods
    

    出力は次のようになります。

    NAME                           READY   STATUS    RESTARTS   AGE
    nbody-sample-6948ff4484-54p6q   1/1     Running   0          2m6s
    nbody-sample-6948ff4484-5qs6n   1/1     Running   0          2m6s
    nbody-sample-6948ff4484-5zpdc   1/1     Running   0          2m5s
    
  4. Pod のログを確認して、Job が完了したことを確認します。

    kubectl logs -l job-name=nbody-sample -f
    

    出力は次のようになります。

    ...
    > Compute 8.9 CUDA device: [NVIDIA L4]
    18432 bodies, total time for 5000 iterations: 9907.976 ms
    = 171.447 billion interactions per second
    = 3428.941 single-precision GFLOP/s at 20 flops per interaction
    ...
    

    GKE は 50,000 回反復処理を実行するため、ログに数分かかることがあります。

クリーンアップ

次のコマンドを実行して、Job とそのすべての Pod を削除します。

kubectl delete job --all

NVIDIA MPS で固定デバイスメモリとアクティブ スレッドを制限する

デフォルトでは、GKE で NVIDIA MPS と GPU を使用する場合、次の CUDA 環境変数が GPU ワークロードに挿入されます。

  • CUDA_MPS_ACTIVE_THREAD_PERCENTAGE: この変数は、各 MPS 共有ユニットが使用できる利用可能なスレッドの割合を示します。デフォルトでは、GPU の各 MPS 共有ユニットは 100 / MaxSharedClientsPerGPU に設定され、ストリーム マルチプロセッサの観点から GPU コンピューティングと同等のスライスを取得します。
  • CUDA_MPS_PINNED_DEVICE_MEM_LIMIT: この変数は、GPU の MPS 共有ユニットによって割り当て可能な GPU メモリの量を制限します。デフォルトでは、GPU の各 MPS 共有ユニットは total mem / MaxSharedClientsPerGPU に設定され、GPU メモリと同等のスライスを取得します。

GPU ワークロードのリソース制限を設定するには、次の NVIDIA MPS 環境変数を構成します。

  1. GitHub の cuda-mps の例を確認し、イメージをビルドします。

  2. 次のマニフェストを cuda-mem-and-sm-count.yaml として保存します。

    apiVersion: v1
    kind: Pod
    metadata:
      name: cuda-mem-and-sm-count
    spec:
      hostIPC: true
      nodeSelector:
        cloud.google.com/gke-gpu-sharing-strategy: mps
      containers:
        - name: CUDA_MPS_IMAGE
          image: gcr.io/gracegao-gke-dev/cuda-mem-and-sm-count:latest
          securityContext:
            privileged: true
          resources:
            limits:
              nvidia.com/gpu: 1
    

    CUDA_MPS_IMAGE は、cuda-mps の例でビルドしたイメージの名前に置き換えます。

    NVIDIA MPS では、Pod に hostIPC:true を設定する必要があります。hostIPC:true 構成では、コンテナがホストリソースにアクセスできるため、セキュリティ リスクが発生します。

  3. 次のようにマニフェストを適用します。

    kubectl apply -f cuda-mem-and-sm-count.yaml
    
  4. この Pod のログをチェックします。

    kubectl logs cuda-mem-and-sm-count
    

    NVIDIA Tesla® L4gpu-sharing-strategy=mpsmax-shared-clients-per-gpu=3 で使用している場合、出力は次のようになります。

    For device 0:  Free memory: 7607 M, Total memory: 22491 M
    For device 0:  multiProcessorCount: 18
    

    この例では、NVIDIA Tesla® L4 GPU の SM 数は 60 個、メモリは 24 GB です。各 MPS 共有ユニットは、おおよそ 33% のアクティブ スレッドと 8 GB のメモリを取得します。

  5. マニフェストを更新して 2 つの nvidia.com/gpu をリクエストします。

      resources:
            limits:
              nvidia.com/gpu: 2
    

    出力は次のようになります。

    For device 0:  Free memory: 15230 M, Total memory: 22491 M
    For device 0:  multiProcessorCount: 38
    
  6. マニフェストを更新して、CUDA_MPS_ACTIVE_THREAD_PERCENTAGE 変数と CUDA_MPS_PINNED_DEVICE_MEM_LIMIT 変数をオーバーライドします。

      env:
        - name: CUDA_MPS_ACTIVE_THREAD_PERCENTAGE
          value: "20"
        - name: CUDA_MPS_PINNED_DEVICE_MEM_LIMIT
          value: "0=8000M"
    

    出力は次のようになります。

    For device 0:  Free memory: 7952 M, Total memory: 22491 M
    For device 0:  multiProcessorCount: 10
    

制限事項

  • Volta 以前の GPU(K80 と P100)の MPS は、Volta 以降の GPU タイプよりも機能が制限されています
  • NVIDIA MPS を使用すると、GKE は各コンテナに固定されたデバイスメモリとアクティブ スレッドを制限します。ただし、メモリ帯域幅、エンコーダ、デコーダなどの他のリソースは、これらのリソースの上限の一部としてキャプチャされません。そのため、すべてのコンテナが同じ無制限リソースをリクエストしている場合、コンテナが他のコンテナのパフォーマンスに悪影響を与える可能性があります。
  • NVIDIA MPS には、メモリ保護とエラーの封じ込めに関する制限があります。この制限を評価して、ワークロードとの互換性を確保することをおすすめします。
  • NVIDIA MPS では、Pod に hostIPC:true を設定する必要があります。hostIPC:true 構成では、コンテナがホストリソースにアクセスできるため、セキュリティ リスクが発生します。
  • GKE は、容量割り当て中に予期しない動作が発生しないように、NVIDIA MPS の使用時に特定の GPU リクエストを拒否することがあります。詳細については、GPU 共有ソリューションのリクエストの上限をご覧ください。
  • NVIDIA MPS で 1 つの物理 GPU を共有できるコンテナの最大数は 48 です(Volta 以前の GPU は 16 のみをサポートします)。NVIDIA MPS の構成を計画する場合は、ワークロードのリソースのニーズと基盤となる物理 GPU の容量を考慮して、パフォーマンスと応答性を最適化してください。
  • NVIDIA MPS API 構成は、Google Cloud CLI または Google Cloud コンソールを使用した場合にのみサポートされます。

次のステップ