OpenShift で GPU を使う


Red Hat OpenShift上のワークロードからGPUを利用するために必要なセットアップをご紹介します。

## 概要
1. Node Feature Discovery Operator のインストール
2. NVIDIA GPU Operator のインストール

NVIDIA GPU Operator は、Kubernetes 内のオペレーター・フレームワークを使用して、GPU のプロビジョンに必要なすべての NVIDIA ソフトウェア・コンポーネントの管理を自動化します。

Node Feature Discovery (NFD) Operator は NVIDIA GPU Operator の前提です。


## 検証環境
- Red Hat OpenShift on IBM Cloud VPC
    - バージョン: 4.12.44
    - フレーバー: gx2.32x256.2v100 (Tesla V100)
    - vGPUサポート付きワーカー・ノード: 4ノード
- Node Feature Discovery Operator: 4.12.0-202311220908
- NVIDIA GPU Operator 23.9.1


## Node Feature Discovery (NFD) Operator のインストール
https://docs.nvidia.com/datacenter/cloud-native/openshift/23.9.1/install-nfd.html

### OpenShift Web コンソールでの NFD Operator のインストール

1. OpenShift Web コンソールで、Operators → OperatorHub をクリックします。
2. `Node Feature Discovery` を検索し、`Red Hat`提供のオペレーター(Community版でない方)をクリックします。 
![nfd_operator1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/7cb208b5-e7b3-becf-f89c-d5ea8b6714f6.png)
3. `インストール` をクリックします。 
![nfd_operator2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/c0026821-8111-d8df-c030-0058baf1ad57.png)
4. `クラスターの特定の namespace` を選択し、他はデフォルトのまま `インストール` をクリックします。
![nfd_operator3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/21d2a865-e12d-d237-a528-20bf567454e9.png)
5. Node Feature Discovery Operator が正常にインストールされていることを確認します。
![nfd_operator4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/e3c891e5-9797-4224-508e-b8b93de25bd7.png)

6. Node Feature Discovery Operator podがRunningであることを確認します。
```
# oc get pods -n openshift-nfd
NAME                                     READY   STATUS    RESTARTS   AGE
nfd-controller-manager-655688fbc-28nqg   2/2     Running   0          7m56s
```

### Node Feature Discovery インスタンスの作成

1. Operators → Installed Operators ページで、`Node Feature Discovery Operator` をクリックします。
![nfd_operator4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/e20a0c95-4c48-6c1a-536a-5d592c6ffecb.png)

2. `NodeFeatureDiscovery` の `インスタンスの作成` をクリックします。![nfd_instance1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/3a5f1a6c-362e-c39f-a10d-6d33a9e6eb3e.png)
3. `作成` をクリックします。これにより、Node Feature Discovery Operatorがクラスター内でGPUを持っているノードにラベルを付けます。
![nfd_instance2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/a783bff5-a00a-72e7-4e90-0ee747b6a15a.png)
　
![nfd_instance3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/39e85277-16ff-7838-9c37-51239e2a63dd.png)


### Node Feature Discovery Operator が正しく機能していることの確認

1. OpenShift Container Platform Web コンソールで、コンピュート → Node をクリックします。
2. GPU付きのワーカー・ノードを選択し、`詳細` タブを開きます。
3. 次のラベルが付けられていることを確認します。
注：`0x10de` はNVIDIAに割り当てられたPCIベンダーIDです。
 `feature.node.kubernetes.io/pci-10de.present=true`

 コマンドでの確認例です。
```
# oc describe node | egrep 'Roles|pci-10de'
Roles:              master,worker
                    feature.node.kubernetes.io/pci-10de.present=true
Roles:              master,worker
                    feature.node.kubernetes.io/pci-10de.present=true
Roles:              master,worker
                    feature.node.kubernetes.io/pci-10de.present=true
Roles:              master,worker
                    feature.node.kubernetes.io/pci-10de.present=true
```

## NVIDIA GPU Operator のインストール

https://docs.nvidia.com/datacenter/cloud-native/openshift/23.9.1/install-gpu-ocp.html

### OpenShift Web コンソールでの NVIDIA GPU Operator のインストール

1. OpenShift Web コンソールで、Operators → OperatorHub をクリックします。
2. `NVIDIA GPU Operator` を検索し、クリックします。 
![gpu_operator1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/954414e3-dc9f-599b-446a-bdb518f5a08e.png)
3. `インストール` をクリックします。 
![gpu_operator2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/82f790fe-8346-153c-c884-ede99cd02efa.png)
4. デフォルトのまま `インストール` をクリックします。
`クラスターの特定の namespace` として推奨の `nvidia-gpu-operator` が作成されます。
![gpu_operator3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/5a7a464d-f74c-0612-5b8f-fbd590700047.png)
5. NVIDIA GPU Operator が正常にインストールされていることを確認します。
![gpu_operator4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/c24620fb-b16a-c0f5-172c-4f314ee5309e.png)


### ClusterPolicy インスタンスの作成

NVIDIA GPU Operator を OpenShift Container Platform にインストールすると、ClusterPolicy のカスタムリソース定義が作成されます。 ClusterPolicy は GPU スタックを構成し、イメージ名とリポジトリ、ポッドの制限/認証情報などを構成します。

NVIDIA vGPUを使用する場合、ClusterPolicy の作成手順は異なります。
今回の使用した `vGPUサポート付きワーカー・ノード` は、NVIDIA vGPUを使用するのではなく、`GPU パススルー` の設定となっています。


参考) GPU パススルーについて

[GPU パススルーの有効化](https://www.ibm.com/docs/ja/mas-cd/continuous-delivery?topic=inspection-enabling-gpu-passthrough)
（別製品のドキュメントですが、わかりやすいので引用します）
> GPU パススルーの有効化
ハイパーバイザー (VSphere、Citrix KVM など) にプロビジョンされている Red Hat® OpenShift® クラスターの場合、 基礎となる GPU ハードウェアを Red Hat OpenShift クラスターに公開するには、2 つの方法があります。 1 つ目は、ハイパーバイザーに GPU 仮想化ドライバーをインストールして、物理 GPU を仮想化し、ハイパーバイザーを介して VM 間でそのリソースを共有できるようにすることです。 2 番目の方法は、GPU パススルーを有効にして、GPU リソースを特定の VM に直接割り当て、ハイパーバイザーをバイパスする方法です。



この環境では、GPUパススルーが有効化されています。

```
# oc debug node/10.248.128.9
Temporary namespace openshift-debug-6g5rj is created for debugging node...
Starting pod/102481289-debug ...
To use host binaries, run `chroot /host`
Pod IP: 10.248.128.9
If you don't see a command prompt, try pressing enter.
sh-4.4# lspci | grep NVIDIA
04:01.0 3D controller: NVIDIA Corporation GV100GL [Tesla V100 PCIe 16GB] (rev a1)
04:02.0 3D controller: NVIDIA Corporation GV100GL [Tesla V100 PCIe 16GB] (rev a1)
```

### OpenShift Web コンソールを使った ClusterPolicy インスタンスの作成

https://docs.nvidia.com/datacenter/cloud-native/openshift/23.9.1/install-gpu-ocp.html#create-the-clusterpolicy-instance-with-nvidia-vgpu


1. インストール済みのOperatorから、`NVIDIA GPU Operator` をクリックします。
![clusterpolicy1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/0b45eef7-ed85-cb39-a014-7757af0a62fd.png)
2. `ClusterPolicy` タブに移動し、`ClusterPolicyの作成` をクリックします。
![clusterpolicy2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/c2c9d592-3aac-4712-f3fa-72916d9b606b.png)

3. デフォルト設定のまま、`作成` をクリックします。
![clusterpolicy3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/c500b631-dda6-0ae2-af6b-6bbb638a361e.png)
![clusterpolicy4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/c5b31bd5-0fc5-6d6d-fe0f-f3f373f2d6f8.png)

4. 10-20分程度待ち、ステータスが `State:ready` になればインストールの成功です。
![clusterpolicy5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/dcc8101a-5d8e-f10f-e993-5a48e90a23ef.png)


各GPU付きノードで、`nvidia-driver-daemonset` をはじめとするpodが起動しています。
```
# oc get pods -o wide -n nvidia-gpu-operator
NAME                                       READY   STATUS      RESTARTS   AGE    IP              NODE            NOMINATED NODE   READINESS GATES
gpu-feature-discovery-mz4xm                1/1     Running     0          106m   172.17.7.85     10.248.128.9    <none>           <none>
gpu-feature-discovery-pv5nq                1/1     Running     0          105m   172.17.32.144   10.248.0.11     <none>           <none>
gpu-feature-discovery-w5c92                1/1     Running     0          105m   172.17.33.39    10.248.0.10     <none>           <none>
gpu-feature-discovery-zhb56                1/1     Running     0          107m   172.17.39.153   10.248.128.10   <none>           <none>
gpu-operator-5657b6df9f-vz592              1/1     Running     0          129m   172.17.33.34    10.248.0.10     <none>           <none>
nvidia-container-toolkit-daemonset-bfxsq   1/1     Running     0          106m   172.17.7.87     10.248.128.9    <none>           <none>
nvidia-container-toolkit-daemonset-ghhgf   1/1     Running     0          105m   172.17.33.4     10.248.0.10     <none>           <none>
nvidia-container-toolkit-daemonset-m75jz   1/1     Running     0          105m   172.17.32.143   10.248.0.11     <none>           <none>
nvidia-container-toolkit-daemonset-p6xhs   1/1     Running     0          107m   172.17.39.152   10.248.128.10   <none>           <none>
nvidia-cuda-validator-5bgxr                0/1     Completed   0          102m   172.17.7.88     10.248.128.9    <none>           <none>
nvidia-cuda-validator-c7km2                0/1     Completed   0          101m   172.17.32.146   10.248.0.11     <none>           <none>
nvidia-cuda-validator-xb474                0/1     Completed   0          100m   172.17.33.65    10.248.0.10     <none>           <none>
nvidia-cuda-validator-xc84g                0/1     Completed   0          102m   172.17.39.154   10.248.128.10   <none>           <none>
nvidia-dcgm-dc55f                          1/1     Running     0          105m   10.248.0.10     10.248.0.10     <none>           <none>
nvidia-dcgm-exporter-4pmlj                 1/1     Running     0          105m   10.248.0.10     10.248.0.10     <none>           <none>
nvidia-dcgm-exporter-bgm4g                 1/1     Running     0          106m   10.248.128.9    10.248.128.9    <none>           <none>
nvidia-dcgm-exporter-brh6l                 1/1     Running     0          105m   10.248.0.11     10.248.0.11     <none>           <none>
nvidia-dcgm-exporter-ll95c                 1/1     Running     0          107m   10.248.128.10   10.248.128.10   <none>           <none>
nvidia-dcgm-g227n                          1/1     Running     0          107m   10.248.128.10   10.248.128.10   <none>           <none>
nvidia-dcgm-nrmpn                          1/1     Running     0          105m   10.248.0.11     10.248.0.11     <none>           <none>
nvidia-dcgm-pdctq                          1/1     Running     0          106m   10.248.128.9    10.248.128.9    <none>           <none>
nvidia-device-plugin-daemonset-77lst       1/1     Running     0          107m   172.17.39.151   10.248.128.10   <none>           <none>
nvidia-device-plugin-daemonset-gvxbb       1/1     Running     0          106m   172.17.7.86     10.248.128.9    <none>           <none>
nvidia-device-plugin-daemonset-htcrz       1/1     Running     0          105m   172.17.33.32    10.248.0.10     <none>           <none>
nvidia-device-plugin-daemonset-rrbnf       1/1     Running     0          105m   172.17.32.145   10.248.0.11     <none>           <none>
nvidia-driver-daemonset-bqphw              1/1     Running     0          108m   172.17.7.78     10.248.128.9    <none>           <none>
nvidia-driver-daemonset-pg65l              1/1     Running     0          108m   172.17.33.38    10.248.0.10     <none>           <none>
nvidia-driver-daemonset-rhpcd              1/1     Running     0          108m   172.17.39.144   10.248.128.10   <none>           <none>
nvidia-driver-daemonset-rsj8h              1/1     Running     0          108m   172.17.32.138   10.248.0.11     <none>           <none>
nvidia-node-status-exporter-577mf          1/1     Running     0          108m   172.17.33.48    10.248.0.10     <none>           <none>
nvidia-node-status-exporter-9g92k          1/1     Running     0          108m   172.17.7.79     10.248.128.9    <none>           <none>
nvidia-node-status-exporter-dxmgs          1/1     Running     0          108m   172.17.32.137   10.248.0.11     <none>           <none>
nvidia-node-status-exporter-jtx9x          1/1     Running     0          108m   172.17.39.145   10.248.128.10   <none>           <none>
nvidia-operator-validator-2js5p            1/1     Running     0          107m   172.17.39.150   10.248.128.10   <none>           <none>
nvidia-operator-validator-4smxp            1/1     Running     0          106m   172.17.7.84     10.248.128.9    <none>           <none>
nvidia-operator-validator-9xkjz            1/1     Running     0          105m   172.17.33.12    10.248.0.10     <none>           <none>
nvidia-operator-validator-vgppw            1/1     Running     0          105m   172.17.32.142   10.248.0.11     <none>           <none>
```

`nvidia-smi` は、メモリ使用量、GPU 使用率、GPU 温度を表示します。`nvidia-driver-daemonset` pod から `nvidia-smi` コマンドを実行して、GPU の情報を表示できます。

```
# oc exec -it nvidia-driver-daemonset-bqphw -- nvidia-smi
Fri Dec 15 10:45:03 2023
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.129.03             Driver Version: 535.129.03   CUDA Version: 12.2     |
|-----------------------------------------+----------------------+----------------------+
| 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  Tesla V100-PCIE-16GB           On  | 00000000:04:01.0 Off |                    0 |
| N/A   31C    P0              27W / 250W |      0MiB / 16384MiB |      0%      Default |
|                                         |                      |                  N/A |
+-----------------------------------------+----------------------+----------------------+
|   1  Tesla V100-PCIE-16GB           On  | 00000000:04:02.0 Off |                    0 |
| N/A   31C    P0              24W / 250W |      0MiB / 16384MiB |      0%      Default |
|                                         |                      |                  N/A |
+-----------------------------------------+----------------------+----------------------+

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

### サンプル GPU アプリケーションの実行

[Running a sample GPU Application](https://docs.nvidia.com/datacenter/cloud-native/openshift/23.9.1/install-gpu-ocp.html#running-a-sample-gpu-application) を実行します。

```
# cat << EOF | oc 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
Warning: would violate PodSecurity "restricted:v1.24": allowPrivilegeEscalation != false (container "cuda-vectoradd" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "cuda-vectoradd" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "cuda-vectoradd" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "cuda-vectoradd" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")
pod/cuda-vectoradd created

# oc get pod | grep cuda
cuda-vectoradd                                                    0/1     Completed          0                50s
```
コンテナーのログを確認します。
```
# oc 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
```