GCP上でGPUコンテナを構築してみる。

## はじめに
GPUコンテナの作成を試したかったのだが、そのためにGPUを買う選択肢はなかったので、クラウド上でGPUインスタンスを作成して、そこでGPUコンテナを構築してみた。
以外に時間を要したので、自分用のメモとして手順やコマンドをまとめておく。

## 事前準備
・Google Cloudのアカウントを作成してGCPコンソールの画面に入れる状態にしておく。
・アップグレードする。（無料トライアルの状態だと、GPUの割当申請ができない）

## 環境
【ホストOS】
　・Ubuntu 20.04 LTS（GCP上）
　・Nvidia-driver 460.
　・docker 19.03.14
　・nvidia-docker2 2.5.0


## GPUコンテナの作成手順

１．GPUインスタンスの作成
２．ホストの設定
３．GPUコンテナの作成


## １．GPUインスタンスの作成

### GPUの割当申請をする
GPUを搭載したVMインスタンスを作成する場合、初回のみ割り当て（クオータ）申請が必要。
まずはGCPのコンソールから`IAMと管理 ＞ 割り当て`を選択する。、
申請は2つする必要があり、【全体における割り当て数】と、【各GPUのリージョン毎の割り当て数】の申請が必要。

**【全体における割り当て数】**
フィルタにGPUsと入れて、下図のサービスを選択する。

![Qiita-no024_img04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/20375c8e-d8f1-6d2e-0cc1-514ff8a66b7a.jpeg)

グローバルにチェックを入れて、『割り当て編集』をクリック。上限と理由を記入して次へ進む。

![Qiita-no024_img05.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/8f201135-0bd4-5e76-3027-73dbd5578ad0.jpeg)

次の画面で、【名前】、【メールアドレス】、【電話番号】を入力してリクエストを送信する。
5分程で承認が下りるため、次はGPUインスタンスを作成する。


**【各GPUのリージョン毎の割り当て数】**

適当にフィルタをかけて、今回は`NVIDIA T4`を選ぶ。
　※利用料金の詳細はこちらを参考に ⇒ https://cloud.google.com/compute/gpus-pricing?hl=ja

![Qiita-no024_img01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/98409379-bbc1-9bfa-bf4f-906353955004.jpeg)

![Qiita-no024_img02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/8be3b603-58f6-9ac2-1322-dfd0d1f2de76.jpeg)



割り当てはリージョン単位になるため、GPUインスタンスを立てる予定のリージョンを選択し、次にGPU数の上限を指定する。
ここで指定した数値は上限値なので、この時点で課金が発生することはない。今回はGPUコンテナの構築が目的のため１個。

![Qiita-no024_img03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/63e4c3b3-1c7d-8f66-3ef3-2cfafe216b68.jpeg)




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

GCPのコンソールから`Compute Engine ＞ VMインスタンス`を選択。
[作成] をクリックし、以下のスペックで作成。

　＜右側は今回の設定値＞
　●リージョン：us-central1（アイオワ）
　●ゾーン　　：us-central1-a

　●マシン構成
　　　マシンファミリー：GPU
　　　シリーズ　　　　：N1
　　　マシンタイプ　　：n1-standard-1（1vCPU、3.75GBメモリ）
　　※試しに申請したリージョン以外を選択すると、GPUのタグは出てこない。
　
　●GPUのタイプ
　　　GPUのタイプ：NVIDIA Tesla T4
　　　GPUの数　　：1
　
　●ブートディスク
　　　OS　　　　　　：Ubuntu
　　　バージョン　　：Ubuntu 20.04 LTS
　　　ディスクの種類：標準の永続ディスク
　　　サイズ　　　　：20GB

　●ファイアウォール
　　　HTTPトラフィックを許可
　　　HTTPSトラフィックを許可

起動に数分かかった。。。


**サーバー環境の確認**

```shell:OSの確認
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04.1 LTS"
```

```shell:GPU（NVIDIA製）の確認
$ lspci -vv | grep -i nvidia
00:04.0 3D controller: NVIDIA Corporation TU104GL [Tesla T4] (rev a1)
        Subsystem: NVIDIA Corporation TU104GL [Tesla T4]
        Kernel modules: nvidiafb
```


## ２．ホストの設定

**nouveauグラフィックスドライバの無効化**
　linuxにデフォルトで入っているnouveauグラフィックスドライバというのを無効化する必要があるらしい。

```shell:
$ lsmod | grep -i nouveau
```
　※今回のVM環境は入っていなかったため、特に何も返ってこなかった。

**パッケージ管理ツールのアップデート**

```shell:
$ sudo apt update
$ sudo apt upgrade
```

### Nvidiaドライバーのインストール
　NVIDIAのDriverバージョンは、こちらのサイトより確認できる。https://www.nvidia.co.jp/Download/index.aspx?lang=jp　　

**リポジトリを追加してアップデート**

```shell:
$ sudo add-apt-repository ppa:graphics-drivers/ppa
$ sudo apt update
```

**インストール推奨Driverを確認**

```shell:
$ sudo apt ubuntu-drivers-common
$ ubuntu-drivers devices
== /sys/devices/pci0000:00/0000:00:04.0 ==
modalias : pci:v000010DEd00001EB8sv000010DEsd000012A2bc03sc02i00
vendor   : NVIDIA Corporation
model    : TU104GL [Tesla T4]
driver   : nvidia-driver-418-server - distro non-free
driver   : nvidia-driver-460 - distro non-free recommended
driver   : nvidia-driver-440-server - distro non-free
driver   : nvidia-driver-450 - distro non-free
driver   : nvidia-driver-450-server - distro non-free
driver   : xserver-xorg-video-nouveau - distro free builtin
```


**ドライバーのインストール**

```shell:
$ sudo apt install nvidia-driver-460
```

**再起動をして問題なくインストールされたか確認**

```shell:GPU（NVIDIA製）の確認
$ lspci -vv | grep -i nvidia
00:04.0 3D controller: NVIDIA Corporation TU104GL [Tesla T4] (rev a1)
        Subsystem: NVIDIA Corporation TU104GL [Tesla T4]
        Kernel driver in use: nvidia
        Kernel modules: nvidiafb, nvidia_drm, nvidia
```

　※ドライバー情報が追加されていればOK。

```shell:nvidia-smiコマンドの動作確認
$ nvidia-smi
```


### dockerのインストール
　[【Dockerコンテナ内のUbuntuではsystemctlは使えない】](https://qiita.com/smiler5617/items/2a33d1aba0174480e9d3)の手順１を参考に。
　※dockerバージョンは`docker-ce=5:19.03.14~3-0~ubuntu-focal`とする

### nvidia-docker2をインストール
　GPUコンテナを作成・起動するために必要なパッケージをインストール。

**リポジトリを追加してアップデート**
　https://nvidia.github.io/nvidia-docker

```shell:
# GPG鍵の登録
$ curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -

# リポジトリを追加
$ distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
$ curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
 
$ sudo apt update
```

**nvidia-docker2のインストール**

```shell:インストール可能なパッケージバージョンを確認
$ apt-cache madison nvidia-docker2
```

```shell:
# 最新版のインストール（今回はこちらを実行）
$ sudo apt -y install nvidia-docker2

# バージョン指定をしてインストールする場合はこんな感じ
$ sudo apt -y install nvidia-docker2=2.0.3+docker18.09.7-3

# 古いバージョンだと事前に他のパッケージもインストールが必要となる場合がある。（以下参考）
$ sudo apt install nvidia-container-runtime-hook
$ sudo apt install nvidia-container-runtime=2.0.0+docker18.09.7-3
```

　※現在は`nvidia-docker2`をインストールすると、`nvidia-container-toolkit`も依存関係があり一緒にインストールされる。（`nvidia-container-toolkit`の方が新しいパッケージ。）
`nvidia-container-toolkit`パッケージのみをインストールした場合は、DockerがGPU にネイティブ対応したため、`--runtime=nvidia`や`nvidia-docker`コマンドは使えない。 


**dockerのデーモン設定をリロード**

```shell:
$ sudo pkill -SIGHUP dockerd
```


```shell:
$ sudo nvidia-docker version
NVIDIA Docker: 2.5.0
Client: Docker Engine - Community
 Version:           20.10.2
 API version:       1.40
 Go version:        go1.13.15
 Git commit:        2291f61
 Built:             Mon Dec 28 16:17:43 2020
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          19.03.14
・・・・
・・・・
```


## ３．GPUコンテナの作成

### GPUコンテナのイメージ取得
　　詳細はこちら　https://hub.docker.com/r/nvidia/cuda/

```shell:
$ docker image pull nvidia/cuda:11.1-base-ubuntu20.04
```



### GPUコンテナの起動確認

```shell:最新コマンド（docker19.03以降でサポートされた`--gpus`オプションを使う場合）
# 全てのGPUを使用する場合
$ docker container run --gpus all --rm nvidia/cuda nvidia-smi

# 使用するGPUを指定したい場合
$ docker container run --gpus '"device=0,1"'--rm nvidia/cuda nvidia-smi
```
　※nvidia-docker2のバージョンが新し過ぎたせいか、`devices`などのオプション(環境変数？)の設定が足りてなくて`nvidia-smi`実行ができなかった。

```shell:旧コマンド（docker19.03以前+nvidia-docker2パッケージが入っている場合）
$ docker container run --runtime=nvidia --rm nvidia/cuda:11.1-base-ubuntu20.04 nvidia-smi
# or
$ nvidia-docker run --rm nvidia/cuda:11.1-base-ubuntu20.04 nvidia-smi

# 使用するGPUを指定したい場合
$ docker container run --runtime=nvidia NVIDIA_VISIBLE_DEVICES=0,1 --rm nvidia/cuda:11.1-base-ubuntu20.04 nvidia-smi
```