🚢

k8s クラスタからGPUを使用する方法について( gpu-operator)

2022/10/01に公開

本記事ざっくりと

k8sのgpuのためのセッティングについての項目が公式ドキュメントでは古かったので、nvidaのgpu-operatorを用いてgpuからpodを使用するためのセッティングを行いました。
この記事に記載されている方法を用いて設定すれば、k8s上でgpuを使用したタスクを実行できるようになります。

はじめに

おうちk8sをやっていて、kubeflowや機械学習タスクなどをk8sに行わせたい場合、k8sからGPUを使いたくなります。しかし、k8sからgpuを使用するためには特殊で複雑な設定が必要になります。しかし、「k8s gpu」などで出てくる公式のドキュメントは古く、ちょっと心配です(コンテナランタイムがdockerじゃないと出来ないって書いてあるし。。。)
https://kubernetes.io/ja/docs/tasks/manage-gpus/scheduling-gpus/
そこで、k8s公式の記事ではなく、nvidaから提供されている「gpu-operator」を用いて、k8sのGPU環境を作成しようと試みました。
https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/overview.html
このNvidiaが提供している gpu-operator は、 k8s から GPU などの特殊なハードウエアリソースへの接続のためのドライバなどの管理を自動化してくれるものです。この gpu-operator を k8s に入れることによって、Pod と GPU が通信できるように、いい感じに間を繋いでくれます。
本記事では、Nvidia の gpu-operator のドキュメントのインストール手順を説明しながら、私がつまづいた部分への打開策を備忘録も兼ねて書いていこうと思います。

前提条件

本記事の内容は、k8sクラスタのワーカーノードのどれか一つにGPUが一枚以上刺さっていることが前提条件です。
本記事の内容は以下の環境で行いました

  • kubernetes: v1.21.1
  • container runtime: cri-o
  • ubuntu server: 20.04.5
  • build tool: kubeadm
  • GPU: GTX980

また、我が家のk8sクラスタの構成は以下の通りです

nodename gpu
1 ubuntu01 1
2 ubuntu02 0
3 ubuntu03 0 control-plane

手順

ここからが、実際の作業手順です

Helmのインストール

gpu-operator をインストールするためにk8s用パッケージマネージャーであるHelmをマスターノードにインストールします。
マスターノードにsshし、以下コマンドでhelmをインストールしてください

$ curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 \
   && chmod 700 get_helm.sh \
   && ./get_helm.sh

gpu-operatorのインストール

先ほどインストールしたHelmを用いて、gpu-operatorをインストールします

まず、nvidiaのhelm repositoryを追加します

$ helm repo add nvidia https://helm.ngc.nvidia.com/nvidia \
   && helm repo update

その後、実際にgpu-operatorをインストールしますが、ここからは実際の環境に応じてインストール方法が異なります。
既にGPUドライバが入っているPCや、CentOSを用いているPCなどにセッティングしたい場合は、公式のインストール手順をご覧ください。
https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/getting-started.html#common-deployment-scenarios
以下に記載したコマンドは、私の環境である、GPUドライバなど何もインストールしてないubuntu serverへのインストール手順です。このコマンドを実行することで、gpu-operatorがデプロイされます。

$ helm install --wait --generate-name \
     -n gpu-operator --create-namespace \
     nvidia/gpu-operator

helmの実行が完了したら以下コマンドで、gpu-operatorの各podが正しくスケジューリングさてれいるかを確認します。もし以下のようになっていればインストールは完了です。

$ kubectl get pod -n gpu-operator
NAME                                                              READY   STATUS      RESTARTS   AGE
gpu-feature-discovery-zz9rv                                       1/1     Running     0          5h44m
gpu-operator-1664607449-node-feature-discovery-master-679b6jqgh   1/1     Running     0          5h45m
gpu-operator-1664607449-node-feature-discovery-worker-994vg       1/1     Running     0          5h45m
gpu-operator-1664607449-node-feature-discovery-worker-d7nfk       1/1     Running     0          5h45m
gpu-operator-1664607449-node-feature-discovery-worker-jrplg       1/1     Running     0          5h45m
gpu-operator-1664607449-node-feature-discovery-worker-qwx6f       1/1     Running     0          5h45m
gpu-operator-1664607449-node-feature-discovery-worker-t6msd       1/1     Running     0          5h45m
gpu-operator-84d9f557c8-drxww                                     1/1     Running     0          5h45m
nvidia-container-toolkit-daemonset-t67lj                          1/1     Running     0          5h44m
nvidia-cuda-validator-t6mgw                                       0/1     Completed   0          5h29m
nvidia-dcgm-exporter-wqm4z                                        1/1     Running     0          5h44m
nvidia-device-plugin-daemonset-nnsnr                              1/1     Running     0          5h44m
nvidia-device-plugin-validator-q4fkr                              0/1     Completed   0          5h29m
nvidia-driver-daemonset-22pc5                                     1/1     Running     0          5h44m
nvidia-operator-validator-zr22z                                   1/1     Running     0          5h43m

正しくpodが立ち上がらない場合

cri-oをコンテナランタイムとして使用している場合、helm installのみでは正しくpodが立ち上がらない問題が確認されています。具体的には以下のようになります。

$ kubectl get pod -n gpu-operator
gpu-feature-discovery-jd2jn                                       0/1     Init:0/1                0              43m
gpu-feature-discovery-vb9nk                                       0/1     Init:0/1                0              43m
nvidia-container-toolkit-daemonset-6flgq                          1/1     Running                 0              43m
nvidia-container-toolkit-daemonset-jnt62                          1/1     Running                 0              43m
nvidia-dcgm-b26rc                                                 0/1     Init:0/1                0              43m
nvidia-dcgm-exporter-8tngv                                        0/1     Init:0/1                0              43m
nvidia-dcgm-exporter-kmtg6                                        0/1     Init:0/1                0              43m
nvidia-dcgm-r8qww                                                 0/1     Init:0/1                0              43m
nvidia-device-plugin-daemonset-l4dsn                              0/1     Init:0/1                0              43m
nvidia-device-plugin-daemonset-rhz62                              0/1     Init:0/1                0              43m
nvidia-driver-daemonset-rfvvg                                     1/1     Running                 0              43m
nvidia-driver-daemonset-wlqws                                     1/1     Running                 0              43m
nvidia-operator-validator-l72z2                                   0/1     Init:CrashLoopBackOff   13 (41s ago)   43m
nvidia-operator-validator-vzh9c                                   0/1     Init:CrashLoopBackOff   13 (44s ago)   43m

https://github.com/NVIDIA/gpu-operator/issues/280
この原因は、cri-oのセッティングに問題があるみたいです(詳しい原因については理解ができませんでした。。)
この場合は、GPUが入っているnodeにsshで接続し、cri-oの設定ファイルを変更することで解決します。
具体的には、GPUが入っているPCの/etc/crio/crio.confに以下の行を追加します。

[crio.runtime]
hooks_dir=["/run/containers/oci/hooks.d"]

上の行を追加したら、sudo systemctl restart crioでcri-oをリスタートしてください。5分から10分経ち、再びkubectl get pod -n gpu-operatorで確認すれば、全てのPODが「Runnning」か「Completed」になっていると思います。
これで設定は完了です。

GPUを使用できるか確認

では、実際にGPUを使用して計算をしてみます。
以下のコマンドを叩き、GPUでベクトル演算をさせます

$ cat << EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
  name: cuda-vectoradd
spec:
  restartPolicy: OnFailure
  containers:
  - name: cuda-vectoradd
    image: "nvidia/samples:vectoradd-cuda11.2.1"
    resources:
      limits:
         nvidia.com/gpu: 1
EOF

上記manifestのspec.containers.resources.limitsでgpuを指定していることがわかります。
logを確認してみます

$ kubectl logs cuda-vectoradd
[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

実際に計算されているみたいですね。成功です!!
では次にpodの中からnvida-smiを確認してみましょう
以下コマンドで適当なpodを作成します

$ cat << EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
  name: tensorflow-gpu
spec:
  containers:
    - name: tensorflow-gpu
      image: tensorflow/tensorflow:latest-gpu
      command: ["/bin/sleep"]
      args: ["3600"]
      resources:
        limits:
          nvidia.com/gpu: 1
EOF

作れたかどうか確認

$ kubectl get pod
NAME                     READY   STATUS      RESTARTS   AGE
tensorflow-gpu           1/1     Running     0          25s

ちゃんと作れたみたいなのでshellに入り、nvidia-smiしてみようと思います。いつも思うけどtensorflowのcontainerをrunすると出てくるのかっこいいですよね。

$ kubectl exec -it tensorflow-gpu -- /bin/bash
________                               _______________
___  __/__________________________________  ____/__  /________      __
__  /  _  _ \_  __ \_  ___/  __ \_  ___/_  /_   __  /_  __ \_ | /| / /
_  /   /  __/  / / /(__  )/ /_/ /  /   _  __/   _  / / /_/ /_ |/ |/ /
/_/    \___//_/ /_//____/ \____//_/    /_/      /_/  \____/____/|__/

root@tensorflow-gpu:/# nvidia-smi
Sat Oct  1 13:19:13 2022
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 515.48.07    Driver Version: 515.48.07    CUDA Version: 11.7     |
|-------------------------------+----------------------+----------------------+
| 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 GeForce ...  On   | 00000000:01:00.0 Off |                  N/A |
| 28%   36C    P8    13W / 180W |      1MiB /  4096MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

はい。nvida-smiもちゃんと出てきていますね!

終わりに

今回の記事では、gpuドライバなどを自動管理してくれるnvida gpu-operatorをおうちk8sクラスタにデプロイしました。このクラスタで、tensorflowを用いた学習などを行う場合は、cudaのバージョンと合ったtensorflowを用いなければならなかったりと、実用にはもう一工夫必要になります。
もし、需要がありましたら、kubeflowからgpuを使用することができるnotebookの作成などの記事も作成していきたいと思います。

以上!nvidia gpu-operatorのセットアップと確認でした。
最後まで読んでいただきありがとうございます。

参考にさせていただきた記事

https://qiita.com/XJK/items/2a1f438a66edaeb10bcc

GitHubで編集を提案

Discussion