GPGPU
GPU
docker
nvidia-docker
nvidia-docker2

nvidia-dockerのbuild時にGPU、関連ライブラリを有効にする

2行まとめ

  • nvidia-dockerバージョン2.0系ではdocker build時にもGPU、関連ライブラリを使うことができる。
  • そのためには、Dockerデーモンの設定を変更し、デフォルトランタイムをnvidiaに切り替える必要がある。

概要

nvidia-dockerのバージョン2.0系では、Dockerの「ランタイム」という仕組みを用いてGPUデバイスや関連ライブラリのマウントを行っています。(バージョン1.0系ではnvidia-dockerというラッパコマンドが存在しました)
通常、ランタイムはその名の通り、docker run時に指定します。そのためdocker build時には有効にならず、ビルド時にGPUや関連ライブラリを必要とするソフトウェアをDockerイメージ化する場合に困ることになります。

そんな中、nvidia-dockerの公式Wiki「Advanced topics」に「デフォルトランタイムを変更するとGPUにアクセスできるよ」との記述を見つけたので実験してみました。

以下、引用です。

Default runtime

The default runtime used by the Docker® Engine is runc, our runtime can become the default one by configuring the docker daemon with --default-runtime=nvidia. Doing so will remove the need to add the --runtime=nvidia argument to docker run. It is also the only way to have GPU access during docker build.

環境

評価を行った環境は、以下の通りです。

yuya@host$ uname -a
Linux xxx 4.4.0-83-generic #106-Ubuntu SMP Mon Jun 26 17:54:43 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

yuya@host$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.3 LTS"

yuya@host$ docker version
Client:
 Version:       17.12.0-ce
 API version:   1.35
 Go version:    go1.9.2
 Git commit:    c97c6d6
 Built: Wed Dec 27 20:11:19 2017
 OS/Arch:       linux/amd64

Server:
 Engine:
  Version:      17.12.0-ce
  API version:  1.35 (minimum version 1.12)
  Go version:   go1.9.2
  Git commit:   c97c6d6
  Built:        Wed Dec 27 20:09:53 2017
  OS/Arch:      linux/amd64
  Experimental: false

yuya@host$ dpkg -l | grep nvidia-docker
ii  nvidia-docker2    2.0.2+docker17.12.0-1    all    nvidia-docker CLI wrapper

デフォルトランタイムがruncの場合(変更前)

デフォルトランタイムはdocker infoコマンドで確認することができます。変更前のデフォルトランタイムはruncです。

yuya@host$ docker info 2> /dev/null | grep -i runtime
Runtimes: nvidia runc
Default Runtime: runc

yuya@host$ sudo cat /etc/docker/daemon.json
{
    "runtimes": {
        "nvidia": {
            "path": "/usr/bin/nvidia-container-runtime",
            "runtimeArgs": []
        }
    }
}

デフォルトランタイムがruncの場合でも、docker runコマンドに--runtime nvidiaオプションを指定することでnvidiaランタイムを使用することができます。実行例を以下に示します。GPUが認識されていること、関連ライブラリにアクセスできることが確認できます。

yuya@host$ docker pull nvidia/cuda:latest
latest: Pulling from nvidia/cuda
Digest: sha256:74570aef804e30486eb74b284fd3091d14ca7144736c44fb48c13e5e6afb963f
Status: Image is up to date for nvidia/cuda:latest

yuya@host$ docker run --interactive --tty --rm --runtime nvidia nvidia/cuda:latest nvidia-smi
Mon Apr 16 11:02:32 2018
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 387.34                 Driver Version: 387.34                    |
|-------------------------------+----------------------+----------------------+
| 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 108...  Off  | 00000000:03:00.0  On |                  N/A |
|  0%   34C    P8    11W / 280W |     61MiB / 11169MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
+-----------------------------------------------------------------------------+

yuya@host$ docker run --interactive --tty --rm --runtime nvidia nvidia/cuda:latest ls -l /usr/lib/x86_64-linux-gnu/libcuda.so
lrwxrwxrwx 1 root root 17 Apr 16 11:12 /usr/lib/x86_64-linux-gnu/libcuda.so -> libcuda.so.387.34

なお、ランタイムを指定しない場合(デフォルトのruncを使う場合)、nvidia-smilibcuda.soも参照できません。

yuya@host$ docker run --interactive --tty --rm nvidia/cuda:latest nvidia-smi
docker: Error response from daemon: OCI runtime create failed: container_linux.go:296: starting container process caused "exec: \"nvidia-smi\": executable file not found in $PATH": unknown.

yuya@host$ docker run --interactive --tty --rm nvidia/cuda:latest ls -l /usr/lib/x86_64-linux-gnu/libcuda.so
ls: cannot access '/usr/lib/x86_64-linux-gnu/libcuda.so': No such file or directory

また、docker build時にも同様に、nvidia-smilibcuda.soを参照できません。

yuya@host$ cat Dockerfile
FROM nvidia/cuda:latest
RUN ls -l /usr/lib/x86_64-linux-gnu/libcuda.so || true
RUN nvidia-smi

yuya@host$ docker build --no-cache --tag ${USER}/runtime_runc .
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM nvidia/cuda:latest
 ---> 9b8a74e9dc76
Step 2/3 : RUN ls -l /usr/lib/x86_64-linux-gnu/libcuda.so || true
 ---> Running in 6f9187fc3fab
ls: cannot access '/usr/lib/x86_64-linux-gnu/libcuda.so': No such file or directory
Removing intermediate container 6f9187fc3fab
 ---> c0b7ad290600
Step 3/3 : RUN nvidia-smi
 ---> Running in cb7a837d9096
/bin/sh: 1: nvidia-smi: not found
The command '/bin/sh -c nvidia-smi' returned a non-zero code: 127

デフォルトランタイムがnvidiaの場合(変更後)

次に、デフォルトランタイムがnvidiaの場合を見てみます。まずは、Dockerデーモンの設定ファイル/etc/docker/daemon.jsonを変更し、設定を反映するためにDockerデーモンを再起動します。docker infoコマンドの結果から、デフォルトランタイムがnvidiaに切り替わっていることが確認できます。

yuya@host$ sudo cp /etc/docker/daemon.json /etc/docker/daemon.json.20180416
yuya@host$ sudo vi /etc/docker/daemon.json
yuya@host$ sudo cat /etc/docker/daemon.json
{
    "default-runtime": "nvidia",
    "runtimes": {
        "nvidia": {
            "path": "/usr/bin/nvidia-container-runtime",
            "runtimeArgs": []
        }
    }
}

yuya@host$ sudo diff -U 2 /etc/docker/daemon.json.20180416 /etc/docker/daemon.json
--- /etc/docker/daemon.json.20180416    2018-04-16 19:10:59.018030162 +0900
+++ /etc/docker/daemon.json     2018-04-16 19:11:50.002551905 +0900
@@ -1,3 +1,4 @@
 {
+    "default-runtime": "nvidia",
     "runtimes": {
         "nvidia": {

yuya@host$ sudo systemctl restart docker
yuya@host$ docker info 2> /dev/null | grep -i runtime
Runtimes: nvidia runc
Default Runtime: nvidia

デフォルトランタイムがnvidiaに切り替わったため、docker run時に--runtime nvidiaを指定しなくてもnvidiaランタイムが使用されます。実行例を以下に示します。

yuya@host$ docker run --interactive --tty --rm nvidia/cuda:latest nvidia-smi
Wed Apr 18 02:21:18 2018
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 387.34                 Driver Version: 387.34                    |
|-------------------------------+----------------------+----------------------+
| 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 108...  Off  | 00000000:03:00.0  On |                  N/A |
|  0%   34C    P8    10W / 280W |     61MiB / 11169MiB |      1%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
+-----------------------------------------------------------------------------+

yuya@host$ docker run --interactive --tty --rm nvidia/cuda:latest ls -l /usr/lib/x86_64-linux-gnu/libcuda.so
lrwxrwxrwx 1 root root 17 Apr 18 02:21 /usr/lib/x86_64-linux-gnu/libcuda.so -> libcuda.so.387.34

デフォルトランタイムはdocker build時にも使用されます。そのため、デフォルトランタイムがruncの時には参照できなかったnvidia-smilibcuda.soが参照できています。実行例を以下に示します。

yuya@host$ cat Dockerfile
FROM nvidia/cuda:latest
RUN ls -l /usr/lib/x86_64-linux-gnu/libcuda.so || true
RUN nvidia-smi

yuya@host$ docker build --no-cache --tag ${USER}/runtime_nvidia .
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM nvidia/cuda:latest
 ---> 9b8a74e9dc76
Step 2/3 : RUN ls -l /usr/lib/x86_64-linux-gnu/libcuda.so || true
 ---> Running in 6be189daae11
lrwxrwxrwx 1 root root 17 Apr 18 02:40 /usr/lib/x86_64-linux-gnu/libcuda.so -> libcuda.so.387.34
Removing intermediate container 6be189daae11
 ---> e1b2e960906a
Step 3/3 : RUN nvidia-smi
 ---> Running in d140ec1d9142
Wed Apr 18 02:40:19 2018
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 387.34                 Driver Version: 387.34                    |
|-------------------------------+----------------------+----------------------+
| 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 108...  Off  | 00000000:03:00.0  On |                  N/A |
|  0%   34C    P8    11W / 280W |     61MiB / 11169MiB |      1%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
+-----------------------------------------------------------------------------+
Removing intermediate container d140ec1d9142
 ---> 260bc963500d
Successfully built 260bc963500d
Successfully tagged yuya/runtime_nvidia:latest

これでdocker build時にGPUや関連ライブラリを使うソフトウェアをDockerイメージ化できますね!

参考