Jetson NanoでDockerを動かす(解決編)

# はじめに

「[Jetson NanoでDockerを動かす(実践編)](https://qiita.com/yamamo-to/items/3022567ae054af495cf6)」ではDockerコンテナ内でGPUが動いているようで動いていなかった。その原因を調査し解決したのでここにまとめる。

# 問題点のおさらい

Dockerコンテナ内でTensorFlowを動かした際に、CUDAが利用可能なデバイスが見つからないと表示された。

```
failed call to cuInit: CUDA_ERROR_NO_DEVICE: no CUDA-capable device is detected
```

調べたところ、先の例ではGPUは正しく動いていなかったことが判明した。そのため調査は難航するかに思えた。

# 原因調査

## /proc原因説

最初に/procを見ていない可能性を調べた。というのもエラーログ内に`/proc/driver/nvidia/version does not exist`という表示があったためだ。当然そのようなファイルはなかったが、ホスト側にも同じように存在しなかった。ということは無くても動作するものである。

```bash:ターミナル(ホスト側)
yamamo-to@jetson-nano:~$ ls /proc/driver/
rtc
```

## サンプルプログラムによる問題点の切り分け

次にTensorFlowではなく`/usr/local/cuda-10.0/samples/`にあるサンプルをいくつか試すことにした。これらはCUDAを直接呼び出しているため問題点の切り分けに使えると考えたからだ。結果、どれも動作しなかった。ということは、前回動いたと考えていたTensorFlowはCPUで動いておりGPUでは動作していなかった可能性が高い。

```bash:Dockerコンテナ内
foo@0e51fe8e73fc:~/samples/0_Simple/simplePrintf$ ./simplePrintf 
CUDA error at ../../common/inc/helper_cuda.h:708 code=38(cudaErrorNoDevice) "cudaGetDeviceCount(&device_count)" 
```

## パーミッション

結果としてはパーミッションが原因だった。

今回用意したDockerコンテナは、ビルド時に一般ユーザfooを作成しコンテナ実行時にはそのユーザ権限でコマンドを実行する。それを止めて一時的にroot権限に変更したところあっさりとGPUを認識した。ということはパーミッションが足りていないのか?と思い調べたところ

```bash:ターミナル
crw-rw---- 1 root video 506,  1  6月 13 19:17 /dev/nvhost-as-gpu
crw-rw---- 1 root video 242,  0  6月 13 19:17 /dev/nvhost-ctrl
crw-rw---- 1 root video 506,  2  6月 13 19:17 /dev/nvhost-ctrl-gpu
crw-rw---- 1 root video 242, 26  6月 13 19:17 /dev/nvhost-ctrl-isp
crw-rw---- 1 root video 242, 30  6月 13 19:17 /dev/nvhost-ctrl-isp.1
crw-rw---- 1 root video 242, 10  6月 13 19:17 /dev/nvhost-ctrl-nvdec
crw-rw---- 1 root video 242, 34  6月 13 19:17 /dev/nvhost-ctrl-vi
crw-rw---- 1 root video 506,  6  6月 13 19:17 /dev/nvhost-ctxsw-gpu
crw-rw---- 1 root root  506,  3  6月 13 19:17 /dev/nvhost-dbg-gpu
crw-rw---- 1 root video 506,  0  6月 13 19:17 /dev/nvhost-gpu
crw-rw---- 1 root video 242, 25  6月 13 19:17 /dev/nvhost-isp
crw-rw---- 1 root video 242, 29  6月 13 19:17 /dev/nvhost-isp.1
crw-rw---- 1 root video 242, 17  6月 13 19:17 /dev/nvhost-msenc
crw-rw---- 1 root video 242,  9  6月 13 19:17 /dev/nvhost-nvdec
crw-rw---- 1 root video 242, 21  6月 13 19:17 /dev/nvhost-nvjpg
crw-rw---- 1 root root  506,  4  6月 13 19:17 /dev/nvhost-prof-gpu
crw-rw---- 1 root video 506,  7  6月 13 19:17 /dev/nvhost-sched-gpu
crw-rw---- 1 root video 242,  1  6月 13 19:17 /dev/nvhost-tsec
crw-rw---- 1 root video 242,  5  6月 13 19:17 /dev/nvhost-tsecb
crw-rw---- 1 root video 506,  5  6月 13 19:17 /dev/nvhost-tsg-gpu
crw-rw---- 1 root video 242, 33  6月 13 19:17 /dev/nvhost-vi
crw-rw---- 1 root video 242, 13  6月 13 19:17 /dev/nvhost-vic
crw-rw---- 1 root video  10, 61  6月 13 19:17 /dev/nvmap
```
所有者はrootだがグループパーミッションに「read」「write」権限がそれぞれ付与されていた。そしてグループは多くが`video`だった。Dockerコンテナではないホスト側の一般ユーザ`yamamo-to`は`video`グループに所属するのかと確認したところ、

```bash:ターミナル
$ grep video /etc/group
video:x:44:yamamo-to,gdm
```

ビンゴ！

# パーミッション修正後

Dockerコンテナをビルド時に一般ユーザ`foo`を`video`グループに所属させるように変更した。
その結果、見事にGPUを伴って動作するようになった。

![Jetson_docker_GPU_success.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252224/67ac0bdc-69b5-0e92-5043-9ff0f453a127.png)

# 最後に

無事にDockerを起動できるようになったが調査の途中で/dev/nv*のデバイスファイルを破壊してしまった。これはDocker内をroot権限で起動した際に何かの拍子でファイルが削除されてしまったためである。そのためコンテナ起動時に`--device`オプションでコンテナに渡すデバイスは調べた上で最小限にした(githubは既にそのように更新)。

ホスト環境をなるべく破壊しないためのDockerだが、Dockerに/dev以下を壊されてしまっては元も子もないので、Dockerを用いるときは十分気をつけた上で実行した方が良いと考える今日この頃である。