NVIDIA A10 搭載のベアメタル GPU インスタンスに KVM を立てて、ゲスト VM に vGPU を割り当てる 



:::note warn
本記事ではVLANを利用していますが、VLANはOCVS(Oracle Cloud VMware Solution)以外での利用が許可されない可能性があります。
本構成を検討される際のVMのネットワーク構成についてはVLANではなく、VMにvNICを直接割り当ててVCNに足を出す構成をご検討ください。
:::


# 概要
OCI にはグラフィック用途から AI など幅広い用途に利用できる NVIDIA A10 が4枚搭載されたベアメタルインスタンスを利用することができます。
現状、A10 はこのベアメタルインスタンスしかなく(VM はリリース予定あり)、一つの OS 環境として4枚の GPU を有効に活用すべく、 vGPU (virtual GPU)に分割し KVM と組み合わせる構成を作成したいと思います。

通常、クラウドでこのような構成をするのは非常に手間、またはできないことがあるかと思いますが、OCI は以下の特徴により比較的簡単に実現することができます。
- ベアメタルインスタンスが利用できる → KVM による仮想環境が構築できる
- VLAN が使える → KVM の Guest VM のネットワーク構成が容易

またベアメタル上で KVM を利用する場合のメリットとして、Windows クライアントなどの BYOL が可能になる点です。BYOL についてはこの記事では追求しないので[こちら](https://docs.oracle.com/ja-jp/iaas/Content/Compute/References/licensing-options-microsoft.htm#licensing-options-microsoft)を参照してください。 

具体的に作成する環境はこちらになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/932ccd9c-239c-b15e-cb79-91b7d63cdb09.png)

ここから先は構築に関することが長々と書いてありますので、設定内容が気になる方、実際に構築されたい方は続きを見ていただければと思います。



# 前提条件
## 前提知識
- OCI のネットワーク(VCN)やコンピュートインスタンスの作成方法を理解している
- KVM などのハイパーバイザーに関する概念的な理解があること

## 必要な OCI リソース
今回の構成方法では以下の OCI リソースが利用できる必要があります。
A10 ベアメタルと VLAN(Service Limit)については Annual Flex 契約であればデフォルトで Service Limit があるはずですが、PAYG 契約では Service Limit がないので申請が必要になります。 
- A10 の BM インスタンスの Service Limit があること
- VLAN が利用できること(= VMware Solution の Service Limit があること)

## すでに作成されている前提の OCI リソース
- VCN, Subnet が作成されていること
- ベアメタルインスタンスに ssh と VNC で利用する tcp 5901 が可能なセキュリティリスト設定

## OCI リソース意外に必要なもの
vGPU を構成するには vGPU Driver とライセンスサーバが必要になります。これらは NVIDIA Enterprise 契約が必要ですが、90日間も [Free Trial](https://www.nvidia.com/en-us/data-center/resources/vgpu-evaluation/) ありますので、まずはこちらを申請するのがよいでしょう。
アカウントを申請したら vGPU ドライバ(Red Hat Enterprise Linux KVM または Linux KVM)のダウンロードしてください。ライセンスサーバについては NVIDIA が提供するサーバ、またはローカルで構築するサーバが選べるようなので、ご準備ください。
- NVIDIA Enterprise アカウント
    - NVIDIA vGPU Driver のダウンロード
    - ライセンスサーバの構築

# 構築
ここからは構築手順になります。


## Network Security Group の作成
VLAN のセキュリティ設定に必要な Network Security Group を作成します。

VCN から Network Security Groups をクリックし、【Create Network Security Group】をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/e03d1f3c-c745-d45e-af90-d29b888b2c90.png)

分かりやすい名前を任意で付ける。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/70ef3dfc-f0be-d64b-13d4-3e0b94cdd7c6.png)

Ingress として Guest VM で必要なルールを追加します。 ここでは ssh を追加しますが、VNC や Remote Desktop が必要な場合は合わせて追加をします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/a896208b-139f-d4c0-c2a3-d5d9124d1dd9.png)

Egress として Guest VM に必要なルールを追加します。ここでは 0.0.0.0/0 で全てアクセス可能とします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/ea948f94-3d1c-5eaf-c464-ca703aa22420.png)


## VLAN の作成
まずは、 KVM の Guest OS で利用する VLAN の作成とそこで利用する IP を作成します。

既存の VCN の Resources から VLANs を選択し、【Create VLAN】をクリックします。 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/8b8af2ca-df63-716a-f62e-ba98722ae089.png)

分かりやすい名前を付けて、CIDR を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/93cfa022-92b8-debf-74bd-4c4d136b3ade.png)

先ほど作成した Network Security Group を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/94e517b1-69d1-69f7-4cea-655a66a67a65.png)

作成するとこのようになり、VLAN ID が振られます。この VLAN 上に Guest VM で利用する IP を確保するために【Add External Access】をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/3f5e409a-99ea-acf6-6f13-1dd0b055bdf2.png)

IP のタイプとして Private IP のみの【Route Target Only】と Private IP に対して Public IP も付けられる【Public Access】から選択することができます。ここでは 【Public Access】 を選択しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/6c0d23d9-f38e-4d11-baf4-3cdbe314e9b7.png)

Public IP Address は既存の予約済み Public IP、または新規作成の二つが選択でき、ここでは新規作成を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/9008a295-9745-3579-de97-3e10d99609b5.png)

作成をすると以下の様に IP が作成されます。 IP については Guest VM で必要な数だけ作成をする必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/e12c2ebd-5d83-5117-326b-ec2473b74b1f.png)



## ベアメタルインスタンス作成
A10 のベアメタルインスタンスを作成します。 通常の VM 作成時と流れは同じですが注意が必要なところとしては、まずは Shape で BM.GPU.A10.4 (今後名前が BM.GPU.GU1.4 変わります)を選択します。Image は Oracle Linux 8 で Image Build の文字列に GPU が含まれないことを確認してください。含まれていた場合は、以下画面のように NVIDIA Driver が含まれない通常の Image を選択してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/307cd9b6-a512-11a0-790d-b77084f021a1.png)

また必要に応じて Boot volume のサイズをデフォルトのサイズを Guest VM の Disk 容量や OS イメージなどを考慮して変更してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/1f3a84d9-9d4b-4520-b0a5-47b955dbc1ce.png)


### VLAN の割り当て
インスタンスが作成されスタータスが running になったら、 【Attatched VNICs】 をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/047aacd7-beb6-c8e3-74c7-fcc9f4dbe0fb.png)

【Create VNIC】をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/dec1943b-9bc4-948b-db79-e0b9d5fccae4.png)

【Name】は任意ですが、分かりやすい名前を付けてください。
【Network】 で 【Advanced Setup: VLAN】 を選択し、先ほど作成した VLAN を選択します。
さらに 【Physical NIC】 で NIC1 を選択します。
BM インスタンスは物理 NIC を2つ持っているので、 NIC0 は Boot Volume やホスト OS に対するアクセス、NIC1 にこの VLAN を割り当てることで、Guest VM 専用と分けることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/e4b47b55-8741-cfb1-cf33-b51a5178fb50.png)


## OS 設定
ssh でインスタンスにアクセスできるようになったら以下の手順を進めていきます。
注意としてベアメタルインスタンスの特性上、作成してから ssh ログインできるまでには5分ほどかかります。

### ディスク領域の拡張
Boot Volume をデフォルトのサイズから変更した場合は、以下のコマンドでパーティションの拡張を行います。
```
sudo /usr/libexec/oci-growfs -y
```

### タイムゾーン設定
```
sudo timedatectl set-timezone Asia/Tokyo
```

### (任意)パッケージを最新にする
必須ではありません。任意で最新に上げてください。
```
sudo yum upgrade -y
```

### RHEL Kernel に切り替える
Oracle Linux は以下の Kernel が含まれており、
- Unbreakable Enterprise Kernel (UEK)
- Red Hat Compatible Kernel
デフォルトでは UEK で起動されます。
今回利用する NVIDIA Host OS Driver は 【Red Hat Enterprise Linux KVM】 なので、 Red Hat Compatible Kernel に変更します。
これとは別に 【Linux KVM】 というものもありますので、こちらであれば UEK のままでも問題ありません。

grabby にて Kernel 一覧を表示して最新の Red Hat Compatible Kernel (4.18 で最新のもの)であるものの番号を確認し、それをデフォルトの番号として指定します。
```
# Kernel 一覧を確認
sudo grubby --info=ALL

# Red Hat Compatible Kernel をデフォルトに指定
sudo grubby --set-default-index=x
```

また今後 Kernel をアップグレードした際に UEK で上がってこないように以下のファイルを開き
```
sudo vi /etc/sysconfig/kernel
```
以下の様に変更して保存します。
```
# UPDATEDEFAULT specifies if kernel-install should make
# new kernels the default
UPDATEDEFAULT=yes

# DEFAULTKERNEL specifies the default kernel package type
#DEFAULTKERNEL=kernel-uek
DEFAULTKERNEL=kernel
```


### IOMMU の無効化
```
sudo vi /etc/default/grub
```

GRUB_CMDLINE_LINUX 行の最後に以下を追加する
```
intel_iommu=on
```

```
sudo grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg
```

設定を反映させるため reboot します。
```
sudo reboot
```

IOMMU が有効になっていることを確認する。
```
dmesg |egrep "IOMMU.*enabled"
[    0.000000] DMAR: IOMMU enabled
```

## KVM のセットアップ

### パッケージインストール
```
sudo dnf install -y @virt virt-manager virt-install
```

kvm のサービスを起動し、reboot 後も起動するように設定します。
```
sudo systemctl start libvirtd
sudo systemctl enable libvirtd
```

opc ユーザで kvm の操作ができるように libvirt グループに opc を追加します。
```
sudo usermod -a -G libvirt $(whoami)
```

Virt-Manager を利用するため GUI と VNC を以下を入れる
```
sudo dnf groupinstall -y "Server with GUI"
sudo dnf install -y tigervnc-server git
```

vnc でデスクトップ接続時に以下を聞かれないように設定をする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/dcac0c3c-b820-c8ee-029c-a015a875f71d.png)

```
sudo -i
cd /etc/polkit-1/localauthority/50-local.d/
vi 45-tigervnc-gnome3.pkla
```

```
[Eliminate GNOME 3 dialogs in TigerVNC]
Identity=unix-user:*
Action=org.freedesktop.color-manager.create-device;org.freedesktop.color-manager.create-profile;org.freedesktop.color-manager.delete-device;org.freedesktop.color-manager.delete-profile;org.freedesktop.color-manager.modify-device;org.freedesktop.color-manager.modify-profile;org.debian.pcsc-lite.access_pcsc;org.freedesktop.packagekit.system-sources-refresh
ResultAny=no
ResultInactive=no
ResultActive=yes
```

### GUI で起動するように変更する
GUI で起動するように設定します。
```
sudo systemctl set-default graphical.target
```

VNC のパスワードを設定します。
```
vncpasswd
```

firewalld で VNC のポートを空ける。
```
sudo firewall-cmd --permanent --zone=public --add-port=5901/tcp
sudo firewall-cmd --reload
```

## ネットワークのセットアップ
Guest VM 用に追加した VLAN にアクセスできるように I/F の作成をします。
### ブリッジの作成
```
sudo vi /etc/sysconfig/network-scripts/ifcfg-br
```

```
STP=no
TYPE=Bridge
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=none
IPV4_FAILURE_FATAL=no
NAME=br
DEVICE=br
ONBOOT=yes
AUTOCONNECT_SLAVES=yes
```

### ブリッジを構成する 物理 NIC に作成した VLAN の I/F を構成

VLAN ID が 2460 だった場合の例になります。作成された VLAN ID に置き換えて対応します。
```
sudo vi /etc/sysconfig/network-scripts/ifcfg-ens340f0.2460
```

```
VLAN=yes
TYPE=Vlan
PHYSDEV=ens340
VLAN_ID=2460
REORDER_HDR=yes
GVRP=no
MVRP=no
NAME=ens340.2460
DEVICE=ens340.2460
ONBOOT=yes
BRIDGE=br
```


## GPU Host Driver のインストール
NVIDIA APPLICATION HUB から入手したファイルを解凍します。
※ver は伏せ字にしています
```
unzip NVIDIA-GRID-RHEL-8.x-xxx.xx.xx-xxx.xx.xx-xxx.xx.zip
cd Host_Drivers ; sudo yum install -y ./NVIDIA-vGPU-rhel-8.x-xxx.xx.xx.x86_64.rpm
```

nouveau open source driver を無効にするため以下を実行します。
```
cat << EOF | sudo tee --append /etc/modprobe.d/blacklist.conf
blacklist nouveau
EOF
```

/etc/default/grub ファイルの GRUB_CMDLINE_LINUX 行に以下を追記する
```
rdblacklist=nouveau
```

GRUB 構成を Rebuild し reboot します。
```
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
sudo reboot
```

## vGPU を作成する
GPU で SR-IOV を有効にするため以下を実行する。
```
sudo /usr/lib/nvidia/sriov-manage -e ALL
```

GPU を作成するのに便利なスクリプトがあるので、 git から入手する。
```
git clone https://github.com/mprestin77/oci-vgpu-kvm.git
```

以下のコマンドにて PCI-Bus 17:00.0 に存在する A10 に A10-4Q というタイプの vGPU を 6 個作成する。 
A10 で作成できる vGPU は[こちら](https://docs.nvidia.com/grid/13.0/grid-vgpu-user-guide/index.html#vgpu-types-nvidia-a10)を参照してください。
```
cd oci-vgpu-kvm/
sudo ./create-mdev.sh A10-4Q 6

17:00.0 31:00.0 B1:00.0 CA:00.0
select PCI bus ID you want to create vGPU profile
1) 17:00.0
2) 31:00.0
3) B1:00.0
4) CA:00.0
#? 1
17:00.0
/sys/devices/pci0000:16/0000:16:02.0/0000:17:00.4 /sys/devices/pci0000:16/0000:16:02.0/0000:17:00.5 /sys/devices/pci0000:16/0000:16:02.0/0000:17:01.6 /sys/devices/pci0000:16/0000:16:02.0/0000:17:01.7 /sys/devices/pci0000:16/0000:16:02.0/0000:17:02.0 /sys/devices/pci0000:16/0000:16:02.0/0000:17:02.1 /sys/devices/pci0000:16/0000:16:02.0/0000:17:02.2 /sys/devices/pci0000:16/0000:16:02.0/0000:17:02.3 /sys/devices/pci0000:16/0000:16:02.0/0000:17:02.4 /sys/devices/pci0000:16/0000:16:02.0/0000:17:02.5 /sys/devices/pci0000:16/0000:16:02.0/0000:17:02.6 /sys/devices/pci0000:16/0000:16:02.0/0000:17:02.7 /sys/devices/pci0000:16/0000:16:02.0/0000:17:00.6 /sys/devices/pci0000:16/0000:16:02.0/0000:17:03.0 /sys/devices/pci0000:16/0000:16:02.0/0000:17:03.1 /sys/devices/pci0000:16/0000:16:02.0/0000:17:03.2 /sys/devices/pci0000:16/0000:16:02.0/0000:17:03.3 /sys/devices/pci0000:16/0000:16:02.0/0000:17:03.4 /sys/devices/pci0000:16/0000:16:02.0/0000:17:03.5 /sys/devices/pci0000:16/0000:16:02.0/0000:17:03.6 /sys/devices/pci0000:16/0000:16:02.0/0000:17:03.7 /sys/devices/pci0000:16/0000:16:02.0/0000:17:04.0 /sys/devices/pci0000:16/0000:16:02.0/0000:17:04.1 /sys/devices/pci0000:16/0000:16:02.0/0000:17:00.7 /sys/devices/pci0000:16/0000:16:02.0/0000:17:04.2 /sys/devices/pci0000:16/0000:16:02.0/0000:17:04.3 /sys/devices/pci0000:16/0000:16:02.0/0000:17:01.0 /sys/devices/pci0000:16/0000:16:02.0/0000:17:01.1 /sys/devices/pci0000:16/0000:16:02.0/0000:17:01.2 /sys/devices/pci0000:16/0000:16:02.0/0000:17:01.3 /sys/devices/pci0000:16/0000:16:02.0/0000:17:01.4 /sys/devices/pci0000:16/0000:16:02.0/0000:17:01.5
0000:17:00.4
Creating vGPU on 0000:17:00.4
2afe08ef-c083-4ab2-bd16-38b3aa8fb20e
0000:17:00.5
Creating vGPU on 0000:17:00.5
acd6fca3-1138-4617-b367-f438ae8f834f
0000:17:01.6
Creating vGPU on 0000:17:01.6
63d70e1b-ef90-4507-941c-cf0d6d73cb64
0000:17:01.7
Creating vGPU on 0000:17:01.7
9e238c47-6cdf-4bfd-abf1-bacdeb1f2bc3
0000:17:02.0
Creating vGPU on 0000:17:02.0
2008d02b-45ff-4bf5-9be9-316a97c01112
0000:17:02.1
Creating vGPU on 0000:17:02.1
8bbda593-a464-40a8-8ce1-6eb12be09463
6 devices created
```

作成された vGPU の UUID は以下のコマンドで一覧取得が可能。
```
mdevctl list
```

SR-IOV は reboot 後も有効にうなるように root ユーザの crontab に以下の様に設定をしておきます。
```
sudo crontab -e
```

```
@reboot sudo /usr/lib/nvidia/sriov-manage -e ALL
```


## KVM に Guest VM を作成する
Guest VM を作成については詳細を省きますが、以下の流れで作成します。
- OS の ISO イメージを配置する
- VM を任意のスペックで作成する
- OS をインストールする
- IP を手動で設定する
    - Gateway、 DNS、 NTP は VLAN の CIDR の最初の IP Address になる

## Guest VM に対する vGPU 関連の作業

### Guest VM に vGPU を割り当てる
Virt-Manager にて対象の VM を選択し、【Add Hardware】をクリックし、MDEV Host Device を選択すると作成した vGPU がリストされるので任意のものをクリックして Finish します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/a8e3b54d-b8af-fa5e-fbe0-b30963e7f5aa.png)

また vGPU をグラフィック用途に利用する場合は、vGPU の display="off" を "on" に変更してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108605/b1436e53-4b59-403c-3848-e6acbf5d9de7.png)

### vGPU ドライバのインストール
NVIDIA より入手した zip ファイルの Guest_Drivers ディレクトリに、Linux や Windows の vGPU Driver がはいっているので、OS に合わせてインストールします。

### NVIDIA ライセンスサーバの設定
vGPU は NVIDIA のライセンスサーバを設定し、認証されることで正しく利用することができます。
認証されなくとも利用することは可能なようですが、一定時間が経過すると本来のパフォーマンスが得られないのでご注意ください。

ライセンスサーバの設定は、Winodws の場合は 【NVIDIA コントロールパネル】 の 【ライセンス】 から可能です。
Linux の場合は、以下の様にテンプレートをコピーして内容を設定してください。
```
sudo cp /etc/nvidia/nvidia-gridd.conf.template /etc/nvidia/nvidia-gridd.conf
sudo vi /etc/nvidia/nvidia-gridd.conf
```

# 参考情報
- https://blogs.oracle.com/cloud-infrastructure/post/deploy-nvidia-vgpu-graphics-virtualization-on-oci
- https://github.com/mprestin77/oci-vgpu-kvm

# 最後に
色々とボリュームのある作業を実施すると KVM で様々な VM を集約することができます。
実利用以外にの、KVM の勉強、vGPU の勉強などなど、 クラウドなら実機を準備することなく試すことが可能なのでぜひお気軽に楽しんでいただければと思います。