Ubuntu18.04: CUDA+Docker セットアップ
概要
Ubuntu 18.04 (bionic beaver) の Docker コンテナ上からホストに設置されている GPU を使用するための環境構築手順を記述する。
機械学習をはじめとする昨今の計算科学は非常に速い過渡期にあり目的によって様々なモデルを試す事のできる環境を必要としている。Fig 1 に示す NVIDIA Docker は各コンテナがホストの GPU とドライバを共用し、コンテナごとに異なる CUDA Toolkit や cuDNN、OS、プログラミング言語を利用できる構成となる。つまり機械学習のフレームワーク、ライブラリやミドルウェア、プログラミング言語を実行環境と疎結合にして環境ごとの構築/共存/問題切り分けや GPU の共有を容易にする利点がある。
この手順の具体的なゴールは Docker コンテナ上で TensorFlow を使った開発や Jupyter Notebook など CUDA を使用するアプリケーションを利用できるようにすることである。大まかな手順は以下のように示される。
- まず Ubuntu が標準で NVIDIA 製 GPU カードに使用する OSS の Nouveau ドライバを無効化し NVIDIA 製の CUDA ドライバを導入する。
- 次に Docker CE と NVIDIA Container Runtime for Docker 2.0 を導入し Docker コンテナ上の CUDA からホストの GPU を利用できるようにする。
- 最後に
dockerd
をリモートからも利用できるように構成する。
この操作によって Ubuntu のパッケージ管理で標準的に使用されているグラフィックドライバや docker.io
が削除されブートイメージが再構築される。つまり Ubuntu 18.04 の標準的な環境とは少し異なる環境となることから、システムは以後のライブラリインストールやバージョンアップに注意を払う必要がある。
Nouveau ドライバの無効化
Ubuntu の標準的なインストールでは NVIDIA GPU カード向けに nouveau と呼ばれるオープンソースのドライバが導入される。しかし nouveau がカーネルにロードされている間は NVIDIA ドライバがロードできず CUDA が使用できないため nouveau を無効化する必要がある。以下 FAQ より引用:
nouveau はカーネルで実行される。カーネルがフレームバッファコンソールを表示するために使用しているため、X が実行されていなくても nouveau を無効化することは難しい。nouveau が使用されている限りカーネルモジュールをアンロードすることができず NVIDIA カーネルモジュールのロードが妨げられる。
nouveau モジュールの無効化を行うに先立ってまずシステムで nouveau がロードされていることを確認する。
torao@cobalt:~$ lsmod | grep nouveau
nouveau 1716224 1
mxm_wmi 16384 1 nouveau
wmi 24576 2 mxm_wmi,nouveau
video 40960 1 nouveau
i2c_algo_bit 16384 1 nouveau
ttm 106496 1 nouveau
drm_kms_helper 167936 1 nouveau
drm 401408 4 nouveau,ttm,drm_kms_helper
nouveau は (やっかいなことに) Ubuntu 起動時に読み込まれるブートイメージに含まれていることから、これを無効化するにはシステムのモジュールローダー構成ディレクトリに nouveau のロードを無効化する設定ファイルを追加しブートイメージを再構築する必要がある。
torao@cobalt:~$ cat /etc/modprobe.d/disable-nouveau.conf
blacklist nouveau
options nouveau modeset=0
上記の設定ファイルを新規に作成したら update-initramfs
を使用してブートイメージを再構築する。
torao@cobalt:~$ sudo update-initramfs -u
update-initramfs: Generating /boot/initrd.img-4.15.0-23-generic
これでシステムを再起動すれば nouveau が無効化された状態で起動する。まず最初に以前より解像度の低い起動画面になったことに気づくだろう。
torao@cobalt:~$ sudo shutdown -r now
前述のコマンドを入力して何も表示されていなければ nouveau がカーネルにロードされていないことが確認できる。
torao@cobalt:~$ lsmod | grep nouveau
torao@cobalt:~$
カーネルのバージョンアップでブートイメージが更新されたときは再びこの操作を行う必要があるかもしれない (未確認)。
NVIDIA ドライバのインストール
実行環境の Ubuntu 18.04 が CUDA 対応の NVIDIA GPU を認識しているかを確認する。
torao@cobalt:~$ lspci | grep -i nvidia
01:00.0 VGA compatible controller: NVIDIA Corporation GP107 [GeForce GTX 1050 Ti] (rev a1)
01:00.1 Audio device: NVIDIA Corporation GP107GL High Definition Audio Controller (rev a1)
対応カードが設置されているにも拘らず lspci
で表示されない場合は /sbin/update-pciids
を実行して PCI ハードウェアデータベースを更新する必要がある。
ここで表示された GPU カードのモデルが CUDA GPUs に掲載されていれば CUDA を利用することができる。例えば現時点で最新の CUDA 9.x の Minimum Compute Capability は 3.0 であることから Compute Capability 6.1 の GeForce GTX 1050 Ti は CUDA 9.x を利用できる。
Ubuntu 16.04 (xenial xerus) を使用している場合は apt
を使用して公式リポジトリや PPA からインストールする方法が手軽だろう (Ubuntu 16.04 LTSに NVIDIA 製ドライバーをインストールする3つの方法など参照)。ただし 2018/07 時点では 18.04 用のリポジトリに GTX 1050 Ti で利用できる NVIDIA ドライバが存在しないため手動でインストールを行う。
最新ドライバのインストールは NVIDIA ドライバダウンロードで適切な環境を選択してダウンロードしたインストーラーを使用して行う。例えば Ubuntu 18.04 + GTX 1050 Ti の組み合わせは LINUX X64 (AMD64/EM64T) DISPLAY DRIVER が該当する。
インストール時にはカーネルインターフェースのコンパイルが実行されるため Pre-install Actions を参考にコンパイラやカーネルソースをインストールする。
torao@cobalt:~$ sudo apt-get install -y linux-headers-$(uname -r) gcc make
...
次に NVIDIA ドライバダウンロードからダウンロードしたインストーラー NVIDIA-Linux-x86_64-xxx.xx.run
を起動する。ここでは現時点での最新版 390.77
を使用している。
torao@cobalt:~$ ls
NVIDIA-Linux-x86_64-390.77.run
torao@cobalt:~$ sudo sh NVIDIA-Linux-x86_64-390.77.run
Verifying archive integrity... OK
Uncompressing NVIDIA Accelerated Graphics Driver for Linux-x86_64 390.77..............................
インストールが完了したら NVIDIA ドライバのユーティリティが使用できることを確認する。
torao@cobalt:~$ nvidia-smi
Sat Jul 21 17:22:09 2018
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 390.77 Driver Version: 390.77 |
|-------------------------------+----------------------+----------------------+
| 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 105... Off | 00000000:01:00.0 Off | N/A |
| 0% 42C P0 N/A / 75W | 0MiB / 4039MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
ここでは Docker ホストの構成を最小限にするため NVIDIA CUDA Toolkit は導入していない事に注意。
NVIDA Docker 2.0 インストール
NVIDIA Docker 2.0 は Docker CE のコンテナランタイムとして動作する。しかし Ubuntu の公式リポジトリから導入できる Docker は Ubuntu がカスタマイズした docker.io
であるため Get Docker CE for Ubuntu を参考にして Docker CE を導入する。
docker.io
や docker-engine
がインストール済みの場合はアンインストールする必要がある。また古い nvidia-docker 1.0 がインストールされている場合はすべての GPU コンテナを削除する必要がある (Removing nvidia-docker 1.0 参照)。
torao@cobalt:~$ sudo apt-get remove docker docker-engine docker.io
torao@cobalt:~$ sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
software-properties-common
torao@cobalt:~$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
OK
torao@cobalt:~$ sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
torao@cobalt:~$ sudo apt-get update
torao@cobalt:~$ sudo apt-get install docker-ce
もし、後述する nvidia-docker2
のインストール時に "The following packages have unmet dependencies: nvidia-docker2: Depends: docker-ce (= 18.06.0~ce~3-0~ubuntu) but it is not installable" というエラーが発生する場合は、システムに導入されている Docker CE のバージョンに互換性がない事を示している。表示されたバージョンを docker-ce
に明示的に指定する必要がある。
torao@cobalt:~$ sudo apt-get install docker-ce=18.06.0~ce~3-0~ubuntu
Docker CE をインストールしたら nvidia-docker2
のパッケージリポジトリを追加する。
torao@cobalt:~$ curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
OK
torao@cobalt:~$ distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
torao@cobalt:~$ curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | \
sudo tee /etc/apt/sources.list.d/nvidia-docker.list
torao@cobalt:~$ sudo apt-get update
nvidia-docker2
をインストールする。
torao@cobalt:~$ sudo apt-get install -y nvidia-docker2
dockerd
を再起動する。
torao@cobalt:~$ sudo pkill -SIGHUP dockerd
Docker コンテナから nvidia-smi
のようなユーティリティが利用できれば動作確認は完了。
torao@cobalt:~$ sudo docker run --runtime=nvidia --rm nvidia/cuda nvidia-smi
Unable to find image 'nvidia/cuda:latest' locally
latest: Pulling from nvidia/cuda
3620e2d282dc: Downloading [=================> ] 15.42MB/43.19MB
ef22f5e4b3b2: Download complete
...
Sat Jul 21 18:44:35 2018
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 390.77 Driver Version: 390.77 |
|-------------------------------+----------------------+----------------------+
| 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 105... Off | 00000000:01:00.0 Off | N/A |
| 0% 38C P0 N/A / 75W | 0MiB / 4039MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
torao@cobalt:~$ sudo docker run --runtime=nvidia --rm nvidia/cuda nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2017 NVIDIA Corporation
Built on Fri_Sep__1_21:08:03_CDT_2017
Cuda compilation tools, release 9.0, V9.0.176
Docker コンテナで CUDA 9.0 が動作し GTX 1050 Ti が認識できていることを確認した。
Docker のリモート実行
Docker コンテナの起動や停止のような操作を Windows などのリモート端末から行うことができるように構成する (この章の内容は CUDA とは関係ない)。
まず Docker の起動オプションを変更して dockerd
を再起動する。以下の構成ではポート 2376 で接続するように構成している。よりセキュアにクライアント認証を用いたい場合は Docker デーモンのソケットを守るを参照。
torao@cobalt:~$ sudo vim /lib/systemd/system/docker.service
# ExecStart=/usr/bin/dockerd -H fd://
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2376 -H fd://
torao@cobalt:~$ sudo systemctl daemon-reload
torao@cobalt:~$ sudo systemctl restart docker
torao@cobalt:~$ netstat -an | grep 2376
tcp6 0 0 :::2376 :::* LISTEN
Windows マシンから Docker ホスト (この場合 cobalt) に対して CUDA を使用するコンテナを実行する。
C:\Users\Takami Torao>docker -H tcp://cobalt:2376 run --runtime=nvidia --rm nvidia/cuda nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2017 NVIDIA Corporation
Built on Fri_Sep__1_21:08:03_CDT_2017
Cuda compilation tools, release 9.0, V9.0.176
Docker ホストで実行したときと同じ結果が得られれば成功。
なお -v
でボリュームをマウントするように Docker コンテナにリソースを指定する部分では、docker
コマンドを実行した端末ではなく Docker ホストのリソースを指定している意味になることに注意。
TensorFlow
Install TensorFlow on Ubuntu 利用可能なタグ (バージョン) はいくつかあるが利用する環境に制約がなければ latest-gpu-py3
を選択すれば良い。TensorFlow や PyTorch などのフレームワークを使用する場合は cuDNN を導入する必要がある。cuDNN の利用にはライセンス同意が必要で nvidia/cuda
Docker イメージには含まれていない。NVIDIA cuDNN の DOWNLOAD cuDNN
torao@cobalt:~$ sudo nvidia-docker run -it tensorflow/tensorflow:latest-gpu-py3 bash
問題と対処
apt から nvidia-docker2
のインストールに失敗する場合は Docker CE の該当バージョンを入れ直す。
torao@cobalt:~$ sudo apt-get install -y nvidia-docker2
Reading package lists... Done
Building dependency tree
Reading state information... Done
Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:
The following packages have unmet dependencies:
nvidia-docker2 : Depends: docker-ce (= 18.06.0~ce~3-0~ubuntu) but it is not installable or
docker-ee (= 18.06.0~ee~3-0~ubuntu) but it is not installable
E: Unable to correct problems, you have held broken packages.