Ubuntuでnvidia-dockerをsudoなしで実行するまで

# はじめに

Ubuntuにnvidia-dockerをインストールして，sudoなしで実行できるように設定します．
最後におまけとして，申し訳程度のセキュリティ対策を紹介します．

# 動作環境

## 動作OS

Ubuntu 14.04 or 16.04 or 18.04
今回，私はUbuntu 16.04での作業でしたが，18.04の方は同じ作業で問題ないはずです．
しかし，14.04の方は，最新のDockerが14.04に対応していないので，古いバージョンを入れなければなりません．
Docker関連のパッケージのバージョンの指定も行わなければならず，色々と面倒なので，大人しくOSのアップグレードをした方が良いかと思います．

## Nvidiaドライバ

極端に古くなければ基本的にドライバのバージョンに関係なくnvidia-docker自体は動作します．
しかし．CUDA 9.0は384.81以上，10.0は410.48以上のように，Docker imageのCUDAのバージョンによって，求めるドライバが新しくなるので，できるだけ新しいものを入れておいた方が後々楽かと思います．

## CUDA

ホストのCUDAは入れても入れなくても構いません．
DockerのCUDAとホストのCUDAは分離しているため，互いに影響はありません．

# Dockerのインストール

[Docker公式のドキュメント](https://docs.docker.com/install/linux/docker-ce/ubuntu/)に記載されているとおりに作業していきます．

## 古いDockerがあれば削除

```bash
$ sudo apt-get remove docker docker-engine docker.io containerd runc
```

## リポジトリの登録

```bash
$ sudo apt-get update
$ sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo apt-key fingerprint 0EBFCD88
$ sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
```

## インストール


```bash
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io
```

これでDockerのインストールは完了です．
次にnvidia-dockerのインストールに移ります．

# nvidia-dockerのインストール

こちらも[公式のリポジトリ](https://github.com/NVIDIA/nvidia-docker)の通りに作業をしていきます．

## 古いnvidia-dockerの削除

nvidia-dockerをインストールしたことのない人は飛ばしてください

```bash
$ sudo docker volume ls -q -f driver=nvidia-docker | xargs -r -I{} -n1 docker ps -q -a -f volume={} | xargs -r docker rm -f
$ sudo apt-get purge -y nvidia-docker
```

## リポジトリの追加

```bash
$ 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-get update
```

## インストール

```bash
$ sudo apt-get install -y nvidia-docker2
$ sudo pkill -SIGHUP dockerd
```

# テスト

```bash
$ sudo docker run --runtime=nvidia --rm nvidia/cuda:9.0-base nvidia-smi
```

以下のようにGPUの情報が表示されれば正常に動作しています．

```
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 430.26       Driver Version: 430.26                              |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX TIT...  Off  | 00000000:03:00.0 Off |                  N/A |
| 22%   37C    P8    14W / 250W |      1MiB / 12212MiB |      1%      Default |
+-------------------------------+----------------------+----------------------+
|   1  GeForce GTX TIT...  Off  | 00000000:04:00.0  On |                  N/A |
| 22%   45C    P8    16W / 250W |    640MiB / 12204MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
+-----------------------------------------------------------------------------+
```
# sudoなしでDockerを動かす

以下のコマンドでユーザをdockerユーザグループに追加し，ログインし直せばsudoなしでDockerが動作します．

```bash
sudo usermod -aG docker $USER
```


# おまけ
## privileged オプションについて
通常，コンテナを起動するとrootユーザが動作しますが，ホストに対してその権限はありません．
なので，ホストのディレクトリをマウントしても，ファイルのパーミッション
コンテナ起動時にprivilegedオプションを付けると，ホストに対してもルート権限に準ずる権限を持つことになります．

つまり，ホストのディレクトリをマウントした状態でコンテナを起動して，

```
docker run -it -v /:/host ubuntu16.04 /bin/bash
```

こんなことをしてしまうと，

```
rm -rf /host
```

マウントされたホストのディレクトリがすべて削除されてしまいます，

なので．privilegedオプションをつけて起動できないようにしていきます．

## ユーザ名前空間の有効化

これによってコンテナにホストのディレクトリをマウントしたときに，ホスト側のユーザと同等の権限でファイル操作が行えます．
同時にprivilegedが無効になります．

etc/subuid と /etc/subgid に下記を追加します．

```
dockremap:100000:65536
```

/etc/docker/daemon.json に以下を追加します．

```
"userns-remap": "default"
```

最後にDockerの再起動をして終了です．

```
sudo systemctl restart docker
```

# おわりに

ほとんど公式ドキュメントの焼き直しになってしまいましたが，以上で快適にnvidia-dockerを使うことができるかと思います．