はじめに
NVIDIA Ampere アーキテクチャのGPUよりMIG(Multi-Instance GPU)というGPUを分割する機能が登場しました。このMIGにより分割されたGPUをKubernetesから利用する際、GPU Instanceを作成しておく必要があります。
2021/12時点では、GPU Instanceを作成する方法としては大きく2つの方法があります。
-
Kubernetesのノードのsystemdなどからスクリプト(or コマンド)を呼び出しGPU Instanceを作成
-
NVIDIA/gpu-operatorを使いKubernetes上のPodからGPU Instanceを作成
本検証では、上記の2について動作検証を行います。
検証環境
- Kubernetes v1.22.0
- GPU: NVIDIA A100
- nvidia/k8s-device-plugin:v0.9.0
検証
本検証では、MIGのGPU Instance作成向けの便利ツールmig-partedのGitHubリポジトリで提供されているgpu-operatorのManifestを使い検証を行います。
GPU Instanceの作成
まず、MIGを設定するためには、GPUが利用されていない状態にする必要があります。
利用されていない状態とは、GPUで実行されているプロセスの有無だけでなく、/dev/nvidia{N}
のデバイスがnvidia-persistencedのデーモンプロセス以外から使われていない状態を指します。
GPUを利用するアプリケーションを実行していなくても、Kubernetes上でNVIDIA GPU向けにdcgm exporterなどをデプロイしている場合などは、/dev/nvidia{N}
のデバイスを利用していますので、これらを事前に削除する必要があります。
不安な場合は、A100を備えたノードに入り、lsofコマンドなどで確認してください。
$ sudo lsof /dev/nvidia*
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nvidia-pe 1406 root 3u CHR 195,255 0t0 576 /dev/nvidiactl
nvidia-pe 1406 root 4u CHR 195,0 0t0 579 /dev/nvidia0
nvidia-pe 1406 root 5u CHR 195,0 0t0 579 /dev/nvidia0
nvidia-pe 1406 root 6u CHR 195,0 0t0 579 /dev/nvidia0
nvidia-pe 1406 root 7u CHR 195,0 0t0 579 /dev/nvidia0
ここから、実際にGPU Instanceを作成していきます。
まず、A100を搭載したノードに入りMIGを有効化します。
$ sudo nvidia-smi -i 0 -mig 1
Enabled MIG Mode for GPU 00000000:00:05.0
All done.
次に、nvidia/k8s-device-pluginのManifest(nvidia-device-plugin.yml
)を編集します。
$ wget https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.9.0/nvidia-device-plugin.yml
編集箇所は以下です。--mig-strategy
オプションを付与しています。
--- nvidia-device-plugin.yml.org 2021-12-17 19:43:12.000000000 +0900
+++ nvidia-device-plugin.yml 2021-12-17 19:44:11.000000000 +0900
@@ -48,7 +48,7 @@
containers:
- image: nvcr.io/nvidia/k8s-device-plugin:v0.9.0
name: nvidia-device-plugin-ctr
- args: ["--fail-on-init-error=false"]
+ args: ["--fail-on-init-error=false", "--mig-strategy=mixed"]
securityContext:
allowPrivilegeEscalation: false
capabilities:
編集したManifest(nvidia-device-plugin.yml
)をデプロイします。
$ kubectl apply -f nvidia-device-plugin.yml
なお、この状態は、MIGを有効にしただけでGPU Instanceがないため、DaemonSet(nvidia-device-plugin-daemonset
)のPod起動に失敗します(意図通り)。
$ kubectl get pod -n kube-system nvidia-device-plugin-daemonset-q2f7p
NAME READY STATUS RESTARTS AGE
nvidia-device-plugin-daemonset-q2f7p 0/1 CrashLoopBackOff 3 (30s ago) 74s
$ kubectl logs nvidia-device-plugin-daemonset-q2f7p
2021/11/15 07:12:36 Loading NVML
2021/11/15 07:12:36 Starting FS watcher.
2021/11/15 07:12:36 Starting OS watcher.
2021/11/15 07:12:36 Retreiving plugins.
2021/11/15 07:12:36 Shutdown of NVML returned: <nil>
panic: At least one device with migEnabled=true was not configured correctly: No MIG devices associated with /dev/nvidia0: GPU-2bacbad4-83e9-78f1-b44f-d10a754a60b8
goroutine 1 [running]:
main.(*migStrategyMixed).GetPlugins(0x1042638, 0x5, 0xae1140, 0x1042638)
/go/src/nvidia-device-plugin/mig-strategy.go:171 +0xa41
main.start(0xc420100ec0, 0x0, 0x0)
/go/src/nvidia-device-plugin/main.go:146 +0x54c
nvidia-device-plugin/vendor/github.com/urfave/cli/v2.(*App).RunContext(0xc420268000, 0xae5a40, 0xc42002c018, 0xc42001e090, 0x3, 0x3, 0x0, 0x0)
/go/src/nvidia-device-plugin/vendor/github.com/urfave/cli/v2/app.go:315 +0x6c8
nvidia-device-plugin/vendor/github.com/urfave/cli/v2.(*App).Run(0xc420268000, 0xc42001e090, 0x3, 0x3, 0x4567e0, 0xc42018df50)
/go/src/nvidia-device-plugin/vendor/github.com/urfave/cli/v2/app.go:215 +0x61
main.main()
/go/src/nvidia-device-plugin/main.go:88 +0x751
nvidia-device-plugin-daemonset
のPodが起動しないのは意図通りのため、ここでは一旦無視します。
次に、mig-partedのgpu-operatorのサンプルのManifest(nvidia-mig-manager-example.yaml
)をダウンロードします。
$ wget https://raw.githubusercontent.com/NVIDIA/mig-parted/master/deployments/gpu-operator/nvidia-mig-manager-example.yaml
`nvidia-mig-manager-example.yaml' に保存中
...
$ cp nvidia-mig-manager-example.yaml nvidia-mig-manager.yaml
nvidia-mig-manager-example.yaml
をコピーした nvidia-mig-manager.yaml
を編集します。
編集内容は、ServiceAccount追加とデプロイするNamespaceの変更を行なっています。
環境によっては変更しなくても良いので、その場合はSkipしてください。
--- nvidia-mig-manager-example.yaml 2021-11-15 15:31:46.000000000 +0900
+++ nvidia-mig-manager.yaml 2021-11-15 16:29:42.000000000 +0900
@@ -1,9 +1,31 @@
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: gpu-operator
+ labels:
+ name: gpu-operator
+ namespace: kube-system
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: kube-system:gpu-operator
+ labels:
+ name: gpu-operator
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: cluster-admin
+subjects:
+- kind: ServiceAccount
+ name: gpu-operator
+ namespace: kube-system
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nvidia-mig-manager
- namespace: default
+ namespace: kube-system
labels:
app: nvidia-mig-manager
spec:
@@ -43,7 +71,7 @@
- name: HOST_MIG_MANAGER_STATE_FILE
value: "/etc/systemd/system/nvidia-mig-manager.service.d/override.conf"
- name: OPERATOR_NAMESPACE
- value: "gpu-operator-resources"
+ value: "kube-system"
- name: WITH_SHUTDOWN_HOST_GPU_CLIENTS
value: "true"
- name: WITH_REBOOT
@@ -79,7 +107,7 @@
kind: ConfigMap
metadata:
name: gpu-clients
- namespace: default
+ namespace: kube-system
data:
clients.yaml: |
version: v1
@@ -98,7 +126,7 @@
kind: ConfigMap
metadata:
name: mig-parted-config
- namespace: default
+ namespace: kube-system
data:
config.yaml: |
version: v1
Manifest(nvidia-mig-manager.yaml
)をデプロイし、DaemonSet(nvidia-mig-manager
)のPodが起動されていることを確認します。
$ kubectl apply -f nvidia-mig-manager.yaml
serviceaccount/gpu-operator created
clusterrolebinding.rbac.authorization.k8s.io/kube-system:gpu-operator created
daemonset.apps/nvidia-mig-manager created
configmap/gpu-clients created
configmap/mig-parted-config created
$ kubectl get pod -n kube-system |grep nvidia-mig
nvidia-mig-manager-2hccw 1/1 Running 0 80s
次に、A100を備えたノードにラベル(nvidia.com/mig.config
)を付与します。
ここで指定する値は、上記でデプロイしたconfigmap/mig-parted-config の値です。
$ MIG_CONFIGURATION=all-1g.5gb
$ kubectl label nodes ysaka-mig-w-gpu-db500b78-sg2wl nvidia.com/mig.config=$MIG_CONFIGURATION --overwrite
ノードにラベル(nvidia.com/mig.config
)が付与されると、GPU Instanceが作られます。
Pod(nvidia-mig-manager-2hccw
)のログを確認します。
$ kubectl logs nvidia-mig-manager-2hccw
...
time="2021-11-15T07:33:21Z" level=debug msg="Parsing config file..."
time="2021-11-15T07:33:21Z" level=debug msg="Selecting specific MIG config..."
time="2021-11-15T07:33:21Z" level=debug msg="Running apply-start hook"
time="2021-11-15T07:33:21Z" level=debug msg="Checking current MIG mode..."
time="2021-11-15T07:33:21Z" level=debug msg="Walking MigConfig for (devices=all)"
time="2021-11-15T07:33:21Z" level=debug msg=" GPU 0: 0x20F110DE"
time="2021-11-15T07:33:21Z" level=debug msg=" Asserting MIG mode: Enabled"
time="2021-11-15T07:33:21Z" level=debug msg=" MIG capable: true\n"
time="2021-11-15T07:33:21Z" level=debug msg=" Current MIG mode: Enabled"
time="2021-11-15T07:33:21Z" level=debug msg="Running apply-exit hook"
MIG configuration applied successfully
...
time="2021-11-15T07:33:22Z" level=info msg="Successfuly updated to MIG config: all-1g.5gb"
time="2021-11-15T07:33:22Z" level=info msg="Waiting for change to 'nvidia.com/mig.config' label"
ログにSuccessfuly updated to MIG config: all-1g.5gb
が出力され、MIGの設定に成功したことがわかります。
念のため、A100を備えたノードにkubectl execコマンドで入り、nvidia-smi
コマンドを使って、GPU Instanceが作られているかを確認します。
$ nvidia-smi
Mon Nov 15 07:35:11 2021
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 495.29.05 Driver Version: 495.29.05 CUDA Version: 11.5 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 NVIDIA A100-PCI... On | 00000000:00:05.0 Off | On |
| N/A 33C P0 36W / 250W | 24MiB / 40536MiB | N/A Default |
| | | Enabled |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| MIG devices: |
+------------------+----------------------+-----------+-----------------------+
| GPU GI CI MIG | Memory-Usage | Vol| Shared |
| ID ID Dev | BAR1-Usage | SM Unc| CE ENC DEC OFA JPG|
| | | ECC| |
|==================+======================+===========+=======================|
| 0 7 0 0 | 3MiB / 4864MiB | 14 0 | 1 0 0 0 0 |
| | 0MiB / 8191MiB | | |
+------------------+----------------------+-----------+-----------------------+
| 0 8 0 1 | 3MiB / 4864MiB | 14 0 | 1 0 0 0 0 |
| | 0MiB / 8191MiB | | |
+------------------+----------------------+-----------+-----------------------+
| 0 9 0 2 | 3MiB / 4864MiB | 14 0 | 1 0 0 0 0 |
| | 0MiB / 8191MiB | | |
+------------------+----------------------+-----------+-----------------------+
| 0 11 0 3 | 3MiB / 4864MiB | 14 0 | 1 0 0 0 0 |
| | 0MiB / 8191MiB | | |
+------------------+----------------------+-----------+-----------------------+
| 0 12 0 4 | 3MiB / 4864MiB | 14 0 | 1 0 0 0 0 |
| | 0MiB / 8191MiB | | |
+------------------+----------------------+-----------+-----------------------+
| 0 13 0 5 | 3MiB / 4864MiB | 14 0 | 1 0 0 0 0 |
| | 0MiB / 8191MiB | | |
+------------------+----------------------+-----------+-----------------------+
| 0 14 0 6 | 3MiB / 4864MiB | 14 0 | 1 0 0 0 0 |
| | 0MiB / 8191MiB | | |
+------------------+----------------------+-----------+-----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
MIG devices
の項目に作成されたGPU Instanceが並んでいます。
また、GPU Instanceが作られたことで、エラーになっていたPod(nvidia-device-plugin-daemonset-q2f7p
)がRunning
になりました。
$ kubectl get pod -n kube-system |grep nvidia
nvidia-device-plugin-daemonset-q2f7p 1/1 Running 10 (6m20s ago) 27m
nvidia-mig-manager-2hccw 1/1 Running 0 5m
kubectl describeコマンドを使いノードの利用可能なリソースとしてGPUが認識されているかを確認します。
$ kubectl describe node ysaka-mig-w-gpu-db500b78-sg2wl
...
Allocatable:
cpu: 62
ephemeral-storage: 224612683405
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 241127988Ki
nvidia.com/gpu: 0
nvidia.com/mig-1g.5gb: 7
pods: 110
...
nvidia.com/mig-1g.5gb
が7個、利用可能なリソースとして追加されました。
以上で、設定は完了です。
mig-1g.5gb
のGPUの動作確認
上記で作成したGPU Instance(mig-1g.5gb
)を使いcuda-vector-addを実行してみます。
Manifest(cuda-vector-add.yaml
)は以下です。
- cuda-vector-add.yaml
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/mig-1g.5gb: 1
Manifest(cuda-vector-add.yaml
)をデプロイし、実行を確認します。
$ kubectl apply -f cuda-vector-add.yaml
pod/cuda-vector-add created
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
cuda-vector-add 0/1 Completed 0 23s
$ 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 GPUのMIGをKubernetesで設定するgpu-operator(mig-parted)の動作検証を行いました。
MIGに関しては、MIGの有効/無効の状態は不揮発メモリに保存されるため、ノードがRebootされても設定は残りますが、GPU Instanceの設定はRebootなどノードが再起動されると削除されてしまいます。そのため、GPU Instanceを設定し運用するためには「いつ」「誰が」「どのタイミング」で設定するのかが重要になってきます。
もし、決まった構成のみでGPU Instanceをインフラ管理者から提供する場合は、systemdで設定するのが安全かつシンプルな方法な方法のひとつです。一方、今回検証したgpu-operatorで設定する方法は、ノードに入らずkubectlコマンドを使いKubernetesの操作で設定できる嬉しさがあります。GPUをインフラ管理者が提供し始める時点ではGPU Instanceの構成が定まらず、Kubernetesの利用者側で、GPUを利用するアプリケーションに応じてGPU Instanceの構成を柔軟に変更できるメリットがあります。
ただし、幾つか注意点があります。
- GPUを利用していない状態にする必要があります。kubectl drain コマンドなどでノードからPodをevictする場合は、DaemonSetのPodも対象となるよう
--ignore-daemonsets=true
などの指定を行ってください。- 上記でノードがGPUを利用していない環境を作り出すのが不安な場合は、ノードをkubectl drainやcordonなどでスケジューリング対象から外したのち、ノードをRebootしGPUを利用していない状態を担保するのも手です。
- gpu-operatorではノードのラベルしかチェックしておらず、ノード自身のイベントを拾いRecocilation Loopで処理などは行っていません。そのため、ノードが障害などで再起動された場合は、GPU Instanceの設定が消去し、MIGが有効化された状態となります(動作検証で示したようにDaemonSet(
nvidia-device-plugin-daemonse
)のPodもRunningにならない状態になります)。このような状態に陥りGPUが利用不可とならないようにアラートなど含めて運用を作り上げる必要があります。
上記のように幾つか注意点があるものの、組織によっては、Kubernetesの操作でより柔軟なGPU Instanceの運用を行いたい場合や、ノードへ入る権限を持ち合わせていない場合などgpu-operatorを使う場合も出てくると推察します。このような場合に備えて、本方法も手段の一つとして知っておくと、自身の組織に適した構成や運用を作れるのではないでしょうか。