LoginSignup
20
18

More than 3 years have passed since last update.

DockerのRootlessモードでNVIDIAのGPUを使用する

Posted at

3行まとめ

  • RootlessモードでもGPUは使用できる。
  • RootlessモードでGPUを使用するためにはnvidia-container-runtimeの設定を変更する必要がある。
  • Rootlessモードと通常モードを共存する方法はまだ未解決。

1. はじめに

 機械学習分野では、Docker/Kubernetes上でNVIDIAのGPU(以下、単に「GPU」)を使うということがよく行われます。
複数人で共有するGPUマシンのセキュリティをより高めるため、RootlessモードのDockerでGPUが使用できるかどうか調査してみました。
結果から言えば、簡単な設定変更を行うだけで使用できました。(少なくともPyTorchから認識できました)

2. 環境

 今回、調査に使用した環境は以下の通りです。

  • OS: Ubuntu 19.10(Eoan Ermine)
  • GPU: GeForce GTX1070 8GB x4台(ただし1台のみ電源オン状態)
  • NVIDIAドライバ: 440.82
  • 通常モードのDocker: 19.03.8
  • RootlessモードのDocker: 19.03.8

 より詳細な環境の情報は以下の通りです。

yuya$ cat /etc/os-release
NAME="Ubuntu"
VERSION="19.10 (Eoan Ermine)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 19.10"
VERSION_ID="19.10"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=eoan
UBUNTU_CODENAME=eoan

yuya$ uname -a
Linux ml-1 5.3.0-51-generic #44-Ubuntu SMP Wed Apr 22 21:09:44 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

yuya$ dpkg -l | grep nvidia
ii  libnvidia-cfg1-440:amd64             440.82-0ubuntu0~0.19.10.1              amd64        NVIDIA binary OpenGL/GLX configuration library
ii  libnvidia-compute-440:amd64          440.82-0ubuntu0~0.19.10.1              amd64        NVIDIA libcompute package
ii  libnvidia-container-tools            1.0.7-1                                amd64        NVIDIA container runtime library (command-line tools)
ii  libnvidia-container1:amd64           1.0.7-1                                amd64        NVIDIA container runtime library
ii  nvidia-compute-utils-440             440.82-0ubuntu0~0.19.10.1              amd64        NVIDIA compute utilities
ii  nvidia-container-runtime             3.1.4-1                                amd64        NVIDIA container runtime
ii  nvidia-container-toolkit             1.0.5-1                                amd64        NVIDIA container runtime hook
ii  nvidia-dkms-440                      440.82-0ubuntu0~0.19.10.1              amd64        NVIDIA DKMS package
ii  nvidia-docker2                       2.2.2-1                                all          nvidia-docker CLI wrapper
ii  nvidia-headless-440                  440.82-0ubuntu0~0.19.10.1              amd64        NVIDIA headless metapackage
ii  nvidia-headless-no-dkms-440          440.82-0ubuntu0~0.19.10.1              amd64        NVIDIA headless metapackage - no DKMS
ii  nvidia-kernel-common-440             440.82-0ubuntu0~0.19.10.1              amd64        Shared files used with the kernel module
ii  nvidia-kernel-source-440             440.82-0ubuntu0~0.19.10.1              amd64        NVIDIA kernel source package
ii  nvidia-modprobe                      418.56-1                               amd64        utility to load NVIDIA kernel modules and create device nodes
ii  nvidia-utils-440                     440.82-0ubuntu0~0.19.10.1              amd64        NVIDIA driver support binaries

yuya$ nvidia-smi
Fri May  8 15:31:23 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.82       Driver Version: 440.82       CUDA Version: 10.2     |
|-------------------------------+----------------------+----------------------+
| 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 1070    Off  | 00000000:01:00.0 Off |                  N/A |
|  0%   36C    P8     7W / 195W |      0MiB /  8119MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
...

yuya$ docker version
Client: Docker Engine - Community
 Version:           19.03.8
 API version:       1.40
 Go version:        go1.12.17
 Git commit:        afacb8b7f0
 Built:             Wed Mar 11 01:25:55 2020
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.8
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.17
  Git commit:       afacb8b7f0
  Built:            Wed Mar 11 01:24:26 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.2.13
  GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
 nvidia:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

yuya$ docker info
...
 Security Options:
  apparmor
  seccomp
   Profile: default
...

yuya$ cat /etc/docker/daemon.json
{
    "default-runtime": "nvidia",
    "runtimes": {
        "nvidia": {
            "path": "nvidia-container-runtime",
            "runtimeArgs": []
        }
    }
}

 nvidia-docker2パッケージをインストールし、default-runtimenvidiaに設定しているのは、Kubernetes上でGPUを使用するためです。
主題のRootlessモードには関係ありません。

 なお、記事中で使用しているyuyaユーザはdockerグループに属しており、通常モードのDockerにアクセスできます。

yuya$ id yuya
uid=1000(yuya) gid=1000(yuya) groups=1000(yuya),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),115(lxd),998(docker)

3. 通常モードでのGPUの使用

 通常モード(root権限でDockerデーモンが動作している一般的な状態)では、nvidia-container-toolkitパッケージをインストールし、--gpus allオプションを付加することで、DockerコンテナでGPUを使用することができます。
nvidia-smiの実行結果は以下の通りです。Dockerコンテナ内でGPUを認識していることが確認できます。

yuya$ docker container run --tty --rm --gpus all nvidia/cuda:10.2-base-ubuntu18.04 nvidia-smi
Fri May  8 06:54:54 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.82       Driver Version: 440.82       CUDA Version: 10.2     |
|-------------------------------+----------------------+----------------------+
| 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 1070    Off  | 00000000:01:00.0 Off |                  N/A |
|  0%   36C    P8     7W / 195W |      0MiB /  8119MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
...

4. RootlessモードでのGPUの使用

4.1. RootlessモードのDockerをセットアップする

 まずは、Rootlessモードの実行に必要なuidmapパッケージ、slirp4netnsパッケージをインストールします。

yuya$ sudo apt update && sudo apt install --yes uidmap slirp4netns

 続いて、Rootlessモードの動作確認を行うため、dockerグループに属していない新しいユーザrootlessを作成します。

yuya$ sudo adduser rootless
yuya$ id rootless
uid=1001(rootless) gid=1001(rootless) groups=1001(rootless)

 準備が整ったら、RootlessモードのDockerをインストールしたいユーザ(今回はrootlessユーザ)でログインし、RootlessモードのDockerをインストールします。
この際、su - rootlessなどユーザを切り替えるのではなく、ログインシェルが起動する状態でログインする必要があります。そうしないとユーザ毎のsystemdデーモンが起動しないので注意が必要です。念のため、systemctl --user daemon-reloadが実行できることを確認しておきましょう。

 インストール自体はcurl -fsSL https://get.docker.com/rootless | shで一発です。sudoコマンドを使用していないことに気を付けましょう。

rootless$ systemctl --user daemon-reload
rootless$ echo $?
0

rootless$ curl -fsSL https://get.docker.com/rootless | sh
# Installing stable version 19.03.8
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 60.7M  100 60.7M    0     0  2995k      0  0:00:20  0:00:20 --:--:-- 2904k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 17.8M  100 17.8M    0     0  2511k      0  0:00:07  0:00:07 --:--:-- 2559k
# starting systemd service
● docker.service - Docker Application Container Engine (Rootless)
   Loaded: loaded (/home/rootless/.config/systemd/user/docker.service; disabled; vendor preset: enabled)
   Active: active (running) since Fri 2020-05-08 15:39:07 JST; 3ms ago
     Docs: https://docs.docker.com
 Main PID: 14632 (dockerd-rootles)
   CGroup: /user.slice/user-1001.slice/user@1001.service/docker.service
           ├─14632 /bin/sh /home/rootless/bin/dockerd-rootless.sh --experimental --storage-driver=overlay2
           └─14639 [grep]

May 08 15:39:07 ml-1 dockerd-rootless.sh[14632]: + : auto
May 08 15:39:07 ml-1 dockerd-rootless.sh[14632]: + net=
May 08 15:39:07 ml-1 dockerd-rootless.sh[14632]: + mtu=
May 08 15:39:07 ml-1 dockerd-rootless.sh[14632]: + [ -z ]
May 08 15:39:07 ml-1 dockerd-rootless.sh[14632]: + which slirp4netns
May 08 15:39:07 ml-1 dockerd-rootless.sh[14632]: + slirp4netns --help
May 08 15:39:07 ml-1 dockerd-rootless.sh[14632]: + grep -- --disable-host-loopback
May 08 15:39:07 ml-1 dockerd-rootless.sh[14632]: --disable-host-loopback  prohibit connecting to 127.0.0.1:* on the host namespace
May 08 15:39:07 ml-1 dockerd-rootless.sh[14632]: + net=slirp4netns
May 08 15:39:07 ml-1 dockerd-rootless.sh[14632]: + [ -z ]
May 08 15:39:07 ml-1 dockerd-rootless.sh[14632]: + mtu=65520
May 08 15:39:07 ml-1 dockerd-rootless.sh[14632]: + [ -z slirp4netns ]
May 08 15:39:07 ml-1 dockerd-rootless.sh[14632]: + [ -z 65520 ]
May 08 15:39:07 ml-1 dockerd-rootless.sh[14632]: + [ -z ]
May 08 15:39:07 ml-1 dockerd-rootless.sh[14632]: + _DOCKERD_ROOTLESS_CHILD=1
May 08 15:39:07 ml-1 dockerd-rootless.sh[14632]: + export _DOCKERD_ROOTLESS_CHILD
May 08 15:39:07 ml-1 dockerd-rootless.sh[14632]: + exec rootlesskit --net=slirp4netns --mtu=65520 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run /home/rootless/bin/dockerd-rootless.sh --experimental --storage-driver=overlay2
Client: Docker Engine - Community
 Version:           19.03.8
 API version:       1.40
 Go version:        go1.12.17
 Git commit:        afacb8b7f0
 Built:             Wed Mar 11 01:22:56 2020
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.8
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.17
  Git commit:       afacb8b7f0
  Built:            Wed Mar 11 01:30:32 2020
  OS/Arch:          linux/amd64
  Experimental:     true
 containerd:
  Version:          v1.2.13
  GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683
# Docker binaries are installed in /home/rootless/bin
# WARN: dockerd is not in your current PATH or pointing to /home/rootless/bin/dockerd
# Make sure the following environment variables are set (or add them to ~/.bashrc):

export PATH=/home/rootless/bin:$PATH
export DOCKER_HOST=unix:///run/user/1001/docker.sock

#
# To control docker service run:
# systemctl --user (start|stop|restart) docker
#

4.2. RootlessモードのDockerの動作を確認する

 インストールが完了したら、関連する環境変数を設定し、docker infoを実行します。Security Options:rootlessが含まれていれば、Rootlessモードで動作しています。
また、適宜.bashrcなどを編集し、環境変数の設定を追加します。

rootless$ export PATH=/home/rootless/bin:$PATH
rootless$ export DOCKER_HOST=unix:///run/user/1001/docker.sock
rootless$ docker version
Client: Docker Engine - Community
 Version:           19.03.8
 API version:       1.40
 Go version:        go1.12.17
 Git commit:        afacb8b7f0
 Built:             Wed Mar 11 01:22:56 2020
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.8
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.17
  Git commit:       afacb8b7f0
  Built:            Wed Mar 11 01:30:32 2020
  OS/Arch:          linux/amd64
  Experimental:     true
 containerd:
  Version:          v1.2.13
  GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

rootless$ docker info
...
 Security Options:
  seccomp
   Profile: default
  rootless
...

4.3. nvidia-container-runtimeの設定を変更する

 RootlessモードのDockerでnvidia-smiを実行すると、以下の通りエラーとなります。

rootless$ docker container run --tty --rm --gpus all nvidia/cuda:10.2-base-ubuntu18.04 nvidia-smi
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "process_linux.go:449: container init caused \"process_linux.go:432: running prestart hook 0 caused \\\"error running hook: exit status 1, stdout: , stderr: nvidia-container-cli: mount error: open failed: /sys/fs/cgroup/devices/user.slice/devices.allow: permission denied\\\\n\\\"\"": unknown.

 mobyリポジトリのIssue#38729を参考に、nvidia-container-runtimeの設定を変更します。具体的にはno-cgroupsをデフォルト値のfalseからtrueに変更します。

参考: nvidia-container-runtime doesn't work with rootless mode · Issue #38729 · moby/moby

yuya$ sudo cp /etc/nvidia-container-runtime/config.toml /etc/nvidia-container-runtime/config.toml.20200508
yuya$ sudo vim /etc/nvidia-container-runtime/config.toml
yuya$ diff -U 3 /etc/nvidia-container-runtime/config.toml.20200508 /etc/nvidia-container-runtime/config.toml
--- /etc/nvidia-container-runtime/config.toml.20200508  2020-05-08 15:50:44.605107694 +0900
+++ /etc/nvidia-container-runtime/config.toml   2020-05-08 15:50:57.125141605 +0900
@@ -8,7 +8,7 @@
 #debug = "/var/log/nvidia-container-toolkit.log"
 #ldcache = "/etc/ld.so.cache"
 load-kmods = true
-#no-cgroups = false
+no-cgroups = true
 #user = "root:video"
 ldconfig = "@/sbin/ldconfig.real"

4.4. RootlessモードのDockerでGPUを使用する

 nvidia-container-runtimeの設定を変更すると、nvidia-smiが実行できるようになります。なお、Dockerデーモンの再起動は不要です。

rootless$ docker container run --tty --rm --gpus all nvidia/cuda:10.2-base-ubuntu18.04 nvidia-smi
Fri May  8 06:56:51 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.82       Driver Version: 440.82       CUDA Version: 10.2     |
|-------------------------------+----------------------+----------------------+
| 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 1070    Off  | 00000000:01:00.0 Off |                  N/A |
|  0%   36C    P8     7W / 195W |      0MiB /  8119MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
...

rootless$ docker container run --interactive --tty --rm --gpus all nvidia/cuda:10.2-base-ubuntu18.04 /bin/bash

root@docker# apt update && apt install --yes python3-pip
root@docker# pip3 install torch
root@docker# python3
Python 3.6.9 (default, Apr 18 2020, 01:56:04)
...
>>> import torch
>>> print(torch.cuda.is_available())
True
>>> torch.cuda.get_device_name(0)
'GeForce GTX 1070'

 上記の通り、Dockerコンテナ内のPyTorchからもGPUが認識できています。

5. 【未解決】通常モードとRootlessモードの共存

 /etc/nvidia-container-runtime/config.tomlno-cgroups = trueを追加し、RootlessモードのDockerでGPUを使用できるようにすると、逆に通常モードのDockerではGPUを使用できなくなってしまいます。
こちらの問題についてはまだ調査しておらず、未解決です。何か情報があれば、お知らせ頂けると嬉しいです。

yuya$ grep no-cgroups /etc/nvidia-container-runtime/config.toml
no-cgroups = true

yuya$ docker container run --tty --rm --gpus all nvidia/cuda:10.2-base-ubuntu18.04 nvidia-smi
Failed to initialize NVML: Unknown Error
20
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
18