NVIDIA Docker って今どうなってるの？ (19.11版)

# 大事なお知らせ
[NVIDIA Docker リポジトリでの 2020 年 9 月の変更](https://github.com/NVIDIA/nvidia-docker/commit/88a2fda83cb3cf42221931dbd0c08aa4370d4fe5)により、この記事内容と最新の状況に割と大きな差ができてしまいました。最新の状況に合わせた改訂版を、[エヌビディアジャパンの Medium ページ](https://medium.com/nvidiajapan)に投稿しましたので、今後は是非 Medium のほうをご覧ください。

[NVIDIA Docker って今どうなってるの？ (20.09 版)](https://medium.com/nvidiajapan/nvidia-docker-%E3%81%A3%E3%81%A6%E4%BB%8A%E3%81%A9%E3%81%86%E3%81%AA%E3%81%A3%E3%81%A6%E3%82%8B%E3%81%AE-20-09-%E7%89%88-558fae883f44?sk=2798a1f044a6c8471ad93909318f508a)

以下、2020 年 8 月までの内容です。
----

※ 2020/07/09 CUDA 11 の正式リリースに伴い、CUDA のインストールコマンド例を 11.0 のものに更新しました。
※ 2020/06/13 CUDA 11 RC のリリースに伴い、CUDA 10.2 のインストールページからインストールしても CUDA 11 RCがインストールされるケースが確認されたので、10.2 を明示的に指定するように例示コマンドを更新しました
※ 2020/02/12 頂いた編集リクエストを取り込みつつ更新しました。

エヌビディアの佐々木です。

突然ですが皆さん、Docker コンテナで GPU を使うとき、(典型的には [NGC](https://ngc.nvidia.com/) のコンテナイメージを使うときとか) どういうコマンドを実行していますか？

```bash
nvidia-docker run ....
```

と打ち込んでいる方は是非この記事を最後まで読んでください。おなじみの nvidia-docker コマンド (NVIDIA Docker 2 ではシェルスクリプト) は、最新の [NVIDIA Docker](https://github.com/NVIDIA/nvidia-docker) にはもはや含まれていません。

# NVIDIA Docker の歴史

さて、ここまで普通に「[NVIDIA Docker](https://github.com/NVIDIA/nvidia-docker)」と書いてしまっていますが、GitHub リポジトリを見ればわかるとおり、このプロジェクトの名前は既に NVIDIA Docker ではありません。実はこれまでに、

- 名前が3回変わっており
- 大きなアーキテクチャ変更 (所謂「NVIDIA Docker 2」になったとき) や
- 後方互換性のない変更 (nvidia-docker(1) が消えたとか) もあり
- インストールするパッケージ名も変わっています

ちょっと表にしてみましょう。なお、ここで言う「バージョン」は、[GitHub の nvidia-docker リポジトリのリリース番号](https://github.com/NVIDIA/nvidia-docker/releases)です。

| 名称                                     | バージョン    | パッケージ名             | 説明                                                                                                                                                                                                                    |
|------------------------------------------|------------|---------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| NVIDIA Docker                            | 1.0.1 まで | .deb や .rpm ファイルを配っていた | nvidia-docker-plugin という Docker ボリューム プラグインのデーモンが動いており、nvidia-docker コマンドはこのデーモンと通信してコンテナで GPU を使うための環境を整えていた                                                                                                                                                                                。|
| Docker<br>Engine Utility for NVIDIA GPUs | 2.0.2      | nvidia-docker2            | ボリュームプラグインは使われなくなった。<br>docker run --runtime=nvidia としてエヌビディアによるカスタマイズ版の runc を指定するようになった。<br>nvidia-docker は --runtime=nvidia オプションなどを補って docker コマンドを実行するラッパースクリプトになった。<br>このカスタムランタイム (/usr/bin/nvidia-container-runtime) の役割は、コンテナ作成直後に処理を挿入できる pre-start-hook にプログラム (/usr/bin/nvidia-container-runtime-hook) を登録して、以前のバージョンのボリューム プラグイン相当の処理を行うこと。 |
| NVIDIA<br>Container Runtime for Docker   | 2.1.0      | nvidia-docker2<br>        |2.0.x 系と仕組みは同じ                                                                                                                                                                                                                                |
| NVIDIA<br>Container Toolkit              | 2.2.1      | nvidia-container-toolkit  |Docker 19.03 が GPU にネイティブ対応したことに伴い、pre-start-hook の登録にカスタムランタイムが不要になった。<br>--runtime=nvidia ではなく --gpus オプションを指定する必要がある。<br>nvidia-docker コマンド(スクリプト) が含まれなくなった。                                                                                                                                                                                                                                |

なんか、ころころ変わっててすみません…

# NVIDIA Docker のインストール方法 (最新版)

本記事執筆時点 (2019年11月) の状況を元に、NVIDIA Docker 環境の作り方をいくつかのケースで示します。
簡単に言えば、

- 過去のしがらみがなければ Docker 19.03 + nvidia-container-toolkit
- 後方互換性を維持する必要があれば Docker 19.03 + nvidia-docker2

です。

## Docker 19.03 以降の環境で前だけを見て生きる場合

まっさらな Linux 環境で、GPU にネイティブ対応した 19.03 以降の Docker と、最新の NVIDIA Docker を使い始めるケースです。
この場合、話は簡単で、[Quickstart](https://github.com/NVIDIA/nvidia-docker/tree/master#quickstart)に記載の通り、

- 最新の NVIDIA ドライバーをインストール ([cuda-drivers パッケージがオススメ](#おまけ-nvidia-ドライバーのインストール))
- Docker の最新バージョン (19.03) をインストール (例えば [Ubuntu ならこちら](https://docs.docker.com/install/linux/docker-ce/ubuntu/))
- nvidia-container-toolkit パッケージをインストール ([Quickstart を参照](https://github.com/NVIDIA/nvidia-docker/tree/master#quickstart))

これだけです。GPU コンテナを実行するには Docker 19.03 でサポートされた `--gpus` オプションを使います。GPU の指定もより柔軟になります。

```bash
# すべての GPU を使用
docker run --gpus all --rm nvidia/cuda nvidia-smi

# 2 つの GPU を使用(※ GPU ID 0 から順番に選択される)
docker run --gpus 2   --rm nvidia/cuda nvidia-smi

# GPU ID または UUID を指定して使用 (クォートが冗長に見えるけど必要)
docker run --gpus '"device=0,1"'           --rm nvidia/cuda nvidia-smi
docker run --gpus '"device=UUID-ABCDEF,1"' --rm nvidia/cuda nvidia-smi
```
なお、この場合、

- `--runtime=nvidia` オプションは使用できません。下記のようなエラーになります。

```bash
docker: Error response from daemon: Unknown runtime specified nvidia.
```

- `nvidia-docker` コマンドもありません (nvidia-container-toolkit パッケージに含まれていません)。

今後は `--gpus` オプションが標準かつ唯一の方法になって世の中が少しシンプルになるはずです。

## Docker 19.03 以降を使いつつも、以前のやり方も残したい場合

いくら最新の Docker が公式に GPU に対応したからとはいえ、`--runtime=nvidia` オプションや `nvidia-docker` コマンドが突然使えなくなってしまうのでは困るケースも多いと思います。ご安心ください、実は `--runtime=nvidia` オプションや `nvidia-docker` コマンドを提供していた nvidia-docker2 パッケージは、

> With the release of Docker 19.03, usage of nvidia-docker2 packages are deprecated since NVIDIA GPUs are now natively supported as devices in the Docker runtime.

出典: https://github.com/NVIDIA/nvidia-docker/tree/master#quickstart

と非推奨であることが明記はされているものの、最新の Docker 19.03 の環境でもまだ利用可能です。
この、「Docker 19.03 + nvidia-docker2 パッケージ」の状態では、次のように新旧全ての書き方が通用します。

```bash
docker run --gpus all nvidia/cuda:9.0-base nvidia-smi
docker run --runtime nvidia nvidia/cuda:9.0-base nvidia-smi
nvidia-docker run nvidia/cuda:9.0-base nvidia-smi
```
出典: https://github.com/NVIDIA/nvidia-docker/tree/master#upgrading-with-nvidia-docker2-deprecated

なお、以前の NVIDIA Docker 2 を既に利用している環境を、Docker 19.03 + nvidia-docker2 へアップグレードする手順は [Upgrading with nvidia-docker2 (Deprecated)](https://github.com/NVIDIA/nvidia-docker#upgrading-with-nvidia-docker2-deprecated) をご覧ください。

※ いつまで nvidia-docker2 パッケージが使えるかはわかりません。できるだけ前述の nvidia-container-toolkit パッケージだけをインストールする[標準かつ唯一の方法](#nvidia-docker-使い方-最新版)への移行をオススメします。

## Docker 19.03 にはまだアップグレードできない場合

何らかの事情で最新の Docker 19.03 にアップグレードできないケースもあると思います。その場合は、今まで通り nvidia-docker2 パッケージを使いながら移行の算段をするのがオススメです。

## NVIDIA Docker 1 なんだけど…

いまだに NVIDIA Docker 1 (`/usr/bin/nvidia-docker` がバイナリファイル) を利用されている場合は、できるだけすみやかに最新環境へ移行しましょう。 NVIDIA Docker 1 は既にメンテナンスされていませんし、 CUDA 10 以降の環境では動作しません。

# おまけ: NVIDIA ドライバーのインストール

NVIDIA Docker と直接は関係しませんが、いや、そんなことないか、ほぼ直接関係する大事なことなので書きますが、 NVIDIA ドライバーをインストールする、オススメの方法(だけど案外知られていない気がする方法) は次の通りです。NVIDIA Docker の FAQ にあるのです。

>The recommended way is to use your package manager and install the cuda-drivers package (or equivalent).
When no packages are available, you should use an official "runfile".

出典: https://github.com/NVIDIA/nvidia-docker/wiki/Frequently-Asked-Questions#how-do-i-install-the-nvidia-driver

適当訳: 「オススメの方法はご利用の環境に応じたパッケージマネージャで cuda-drivers メタパッケージ (あるいはその相当品) をインストールすることです。パッケージが利用できない場合に、公式の "runfile" を使ってください。」

cuda-drivers パッケージをインストールというのをもう少し具体的に示しますと、例えば Ubuntu 18.04 に CUDA 11.0 をインストールするのであれば、[CUDA Toolkit の Web サイト](https://developer.nvidia.com/cuda-10.2-download-archive?target_os=Linux&target_arch=x86_64&target_distro=Ubuntu&target_version=1804&target_type=deblocal)で下記のようなコマンドが提示されると思います。(Installer Type として deb (local) を選んだ場合)
※ その他の Linux ディストリビューション、CUDA バージョンに関しては [CUDA Toolkit Archive のページ](https://developer.nvidia.com/cuda-toolkit-archive)から辿ってください。

```bash
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-ubuntu1804.pin
sudo mv cuda-ubuntu1804.pin /etc/apt/preferences.d/cuda-repository-pin-600
wget http://developer.download.nvidia.com/compute/cuda/11.0.2/local_installers/cuda-repo-ubuntu1804-11-0-local_11.0.2-450.51.05-1_amd64.deb
sudo dpkg -i cuda-repo-ubuntu1804-11-0-local_11.0.2-450.51.05-1_amd64.deb
sudo apt-key add /var/cuda-repo-ubuntu1804-11-0-local/7fa2af80.pub
sudo apt-get update
sudo apt-get -y install cuda
```
この最後の `sudo apt-get -y install cuda` を

```bash
sudo apt-get -y install cuda-drivers
```

とすれば、最新のドライバだけが綺麗にインストールされます。これがオススメの方法です。

# まとめ

- Docker 19.03 の GPU ネイティブ対応により、NVIDIA Docker の使い方も少し変わりました。今後は Docker 標準の --gpus オプションを使いましょう。
- nvidia-docker2 パッケージは Docker 19.03 の登場で非推奨になりましたが今のところ有効です。新旧双方のオプションが使えるので今のうちにじわじわと移行を進めてください。
- ついでに言うと、 NVIDIA ドライバは cuda-drivers パッケージでインストールするのがオススメ。

# 関連情報

- [NVIDIA Docker](https://github.com/NVIDIA/nvidia-docker/tree/v1.0.1)
- [Docker Engine Utility for NVIDIA GPU](https://github.com/NVIDIA/nvidia-docker/tree/v2.0.3)
- [NVIDIA Container Runtime for Docker](https://github.com/NVIDIA/nvidia-docker/tree/v2.1.1)
- [NVIDIA Container Toolkit](https://github.com/NVIDIA/nvidia-docker/tree/v2.2.2)
- [How do I install the NVIDIA driver?](https://github.com/NVIDIA/nvidia-docker/wiki/Frequently-Asked-Questions#how-do-i-install-the-nvidia-driver)