仮想化通信

日本仮想化技術株式会社の公式エンジニアブログ

Multi-Instance GPUをDockerやMicroK8sで使ってみる

NVIDIAのGPUのH100、A100、A30にはマルチインスタンスGPU(以降MIG)という機能が実装されています。 かつては専用ソフトウェアを使って1つのGPUを複数のGPUがあるかのように見せて、対応するアプリケーションで使うことができましたが、 先に挙げたGPUであれば追加ソフトウェア導入の必要なく、複数のインスタンスでGPUが使えます。

MIGをDockerで使ってみる

環境のセットアップ

MIGをDockerで使うには、まず、OSにDocker Engineをインストールします。 Ubuntuの場合は次のページの通りです。

その後、NVIDIA DriversとNVIDIA Container Toolkitをインストールします。

現在のバージョンのNVIDIA Container Toolkitは、Dockerの他、containerdやPodmanなども対応しています。 手順に従って、NVIDIA Container ToolkitパッケージリポジトリーとGPG keyの取り込みを行った後にインストールを行い、

$ sudo apt-get update
$ sudo apt-get install -y nvidia-container-toolkit

その後次のようなコマンドを実行します。これでランタイムにNVIDIA GPUを使うための設定が行われます。

$ sudo nvidia-ctk runtime configure --runtime=docker
$ sudo systemctl restart docker

これで通常はコンテナでGPUを使えるようになります。

$ sudo docker run --rm --runtime=nvidia --gpus all nvidia/cuda:12.0.0-base-ubuntu20.04 nvidia-smi

MIGを有効化

MIGをサポートするGPUで次のように実行すると、MIGがその環境で使えるようになります。

$ sudo nvidia-smi -i 0 -mig 1
Enabled MIG Mode for GPU 00000000:C1:00.0
All done.

あとはMIGのプロファイルをもとにGPUリソースを分割します。使えるプロファイルとリソースの残りは'nvidia-smi mig -lgip'というコマンドで確認できます。 まだMIGをつくる前なので、最大7つインスタンスを切ることができるようです。今回の環境はNVIDIA A100 GPU1枚が実装された環境なのでGPU 0の情報しか出力されませんが、 複数のカードが実装されている場合はそのカード分表示されます。

+-----------------------------------------------------------------------------+
| GPU instance profiles:                                                      |
| GPU   Name             ID    Instances   Memory     P2P    SM    DEC   ENC  |
|                              Free/Total   GiB              CE    JPEG  OFA  |
|=============================================================================|
|   0  MIG 1g.10gb       19     7/7        9.50       No     14     0     0   |
|                                                             1     0     0   |
+-----------------------------------------------------------------------------+
|   0  MIG 1g.10gb+me    20     1/1        9.50       No     14     1     0   |
|                                                             1     1     1   |
+-----------------------------------------------------------------------------+
|   0  MIG 1g.20gb       15     4/4        19.50      No     14     1     0   |
|                                                             1     0     0   |
+-----------------------------------------------------------------------------+
|   0  MIG 2g.20gb       14     3/3        19.50      No     28     1     0   |
|                                                             2     0     0   |
+-----------------------------------------------------------------------------+
|   0  MIG 3g.40gb        9     2/2        39.25      No     42     2     0   |
|                                                             3     0     0   |
+-----------------------------------------------------------------------------+
|   0  MIG 4g.40gb        5     1/1        39.25      No     56     2     0   |
|                                                             4     0     0   |
+-----------------------------------------------------------------------------+
|   0  MIG 7g.80gb        0     1/1        78.75      No     98     5     0   |
|                                                             7     1     1   |
+-----------------------------------------------------------------------------+

プロファイルを使ってGPUリソースを分割していきます。プロファイルの指定方法は以下のように指定するようですが

  1. Profile ID (e.g. 9, 14, 5)
  2. Short name of the profile (e.g. 3g.20gb)
  3. Full profile name of the instance (e.g. MIG 3g.20gb)

例えば次のように実行すると、3つのMIGを作成できます。このプロファイルで3分割すると、もうこれ以上は分割できないようですね。

sudo nvidia-smi mig -cgi 2g.20gb -C

作成したMIGは次のコマンドにより全部削除できます。

$ sudo nvidia-smi mig -dci && sudo nvidia-smi mig -dgi

分割したGPUは次のような感じでデバイスを確認できますので

$ nvidia-smi -L
GPU 0: NVIDIA A100 80GB PCIe (UUID: GPU-69198b81-f419-f843-4449-eeb123f2912f)
  MIG 3g.40gb     Device  0: (UUID: MIG-ea2c8e7c-5712-570e-9416-bf0eda652588)
  MIG 3g.40gb     Device  1: (UUID: MIG-0f0e3e49-8f71-5345-8a33-7c2ef0ff6bf5)

あとはDocker runコマンド実行時にUUIDを指定するだけです。

sudo docker run --runtime=nvidia \
    -e NVIDIA_VISIBLE_DEVICES=MIG-ea2c8e7c-5712-570e-9416-bf0eda652588 \
    nvidia/cuda:12.0.0-base-ubuntu20.04 nvidia-smi

MIGをMicroK8sで使ってみる

MicroK8sでMIGを使うのは結構簡単です。まず次のようにMicroK8sをインストールします。

$ sudo snap install microk8s --classic --channel=1.26/stable
$ sudo microk8s.start
$ sudo usermod -a -G microk8s $USER
$ sudo snap alias microk8s.kubectl kubectl

そのあと、GPUアドオンや他に必要なアドオンがあればインストールしてください。

$ sudo microk8s enable gpu registry hostpath-storage

nvidia-mig-managerが導入されていれば、Kubernetes APIを介してMIGの設定ができます。

$ kubectl get pod -A -lapp=nvidia-mig-manager
NAMESPACE                NAME                       READY   STATUS    RESTARTS   AGE
gpu-operator-resources   nvidia-mig-manager-wxbh2   1/1     Running   0          20s

例えば次のように実行すると、kubectlコマンドでMIGを設定できます。

$ kubectl label nodes shachi nvidia.com/mig.config=all-3g.40gb --overwrite
node/shachi labeled

あとは次のようなマニフェストを使ってPodを作成します。nvidia.com/gpuで指定できるのはGPU数だけですが、MIGを有効化しているのでMIGの設定で分割した数が最大値になります。 本例では2分割したので、2を指定してみましょう。

$ kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: cuda-vector-add
spec:
  restartPolicy: OnFailure
  containers:
    - name: cuda-vector-add
      image: "k8s.gcr.io/cuda-vector-add:v0.1"
      resources:
        limits:
          nvidia.com/gpu: 2
EOF

実行するとPodが作成されて処理が行われます。ログを確認すると、アプリケーションがちゃんと実行されたのを確認できます。

$ kubectl logs cuda-vector-add
[Vector addition of 50000 elements]
Copy input data from the host memory to the CUDA device
CUDA kernel launch with 196 blocks of 256 threads
Copy output data from the CUDA device to the host memory
Test PASSED
Done

nvidia.com/gpu: 3にして実行すると、GPU要求を環境が満たしていないためPendingになり、次のようなイベントが記録されます。

Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  11s   default-scheduler  0/1 nodes are available: 1 Insufficient nvidia.com/gpu. preemption: 0/1 nodes are available: 1 No preemption victims found for incoming pod..

CPUとは異なりGPUにはコアがたくさんあります。メモリーについてはGPUに実装されているメモリーを均等に分割していきますので、 分割したリソースに割り当てられるメモリーはチップに載っているメモリーサイズ次第です。

アプリケーション開発などでGPUを使う場合に複数のアプリケーションでGPUが使えて便利な機能だと思います。

参考情報