Docker Advent Calendar 2016 の 11 日目です。昨日は @nekop さんの「Dockerfileの無駄なレイヤリングを排除してビルドを高速化する」でした。
GPU ですよ
最近仕事で GPU が欠かせないので、備忘を兼ねて、Azure の GPU が搭載された新しい N シリーズ で NVIDIA GPU を使う + Tips を残します。
Azure で VM 起動
Linux Data Science Virtual Machine
最近 機械学習向けのマシンイメージ が出たとのことでこれを使おうとしたのですが、残念、GPU 未対応のようです。がっつり学習に利用するというより、試行錯誤するフェーズ向けな気もしますし、私の目論見が不純でした、すみません・・。
制限
で、現状は、公式の Set up GPU drivers for N-series VMs にあるように
Linux の GPU サポートは現在、Ubuntu Server 16.04 LTS で稼働する Azure NC シリーズの仮想サーバのみです
とのことなので、該当のサーバイメージを探します。探したら、
CLI で起動
South Central US で N シリーズの VM を 1 台起動します。
以下、CLI は v1 を使います。
マシン起動時の大事な引数は以下のとおり。
キー | 値 |
---|---|
--os-type | Linux |
--location | southcentralus |
--vm-size | Standard_NC6 |
--image-urn | Canonical:UbuntuServer:16.04-LTS:16.04.201612050 |
鍵はあらかじめ用意しつつ、残りの引数はよしなに変えて実行します。
$ azure vm create -g gpus -n demo --os-type Linux \
--location southcentralus --vm-size Standard_NC6 \
--image-urn Canonical:UbuntuServer:16.04-LTS:16.04.201612050 \
--admin-username azure --ssh-publickey-file key.pub \
--vnet-name demo-vnet --vnet-subnet-name demo-subnet \
--nic-name demo-nic --public-ip-name demo-pip \
--storage-account-name demogpu20161212
仮想ネットワークの CIDR ブロックとパブリック DNS 名を対話的に決めしばらくすると、サーバが起動します。
GPU 諸々セットアップ
1. SSH ログイン
$ ssh -i key azure@<domain-name>.southcentralus.cloudapp.azure.com
ドメイン名には、先ほど VM 起動時に対話的に決めた名前が入ります。
2. GPU チェック
CUDA が使える GPU であることをチェックしてみます。
azure@demo:~$ lspci | grep -i NVIDIA
a848:00:00.0 3D controller: NVIDIA Corporation GK210GL [Tesla K80] (rev a1)
3. NVIDIA ドライバインストール
sudo apt-get update
sudo apt install -y gcc make
wget -O /tmp/NVIDIA-Linux-x86_64-375.20.run http://us.download.nvidia.com/XFree86/Linux-x86_64/375.20/NVIDIA-Linux-x86_64-375.20.run
chmod +x /tmp/NVIDIA-Linux-x86_64-375.20.run
sudo sh /tmp/NVIDIA-Linux-x86_64-375.20.run
ダイアログに従って、ライセンスに Agree
した後は OK で進めていきます。
インストールが終わったら、デバイスの状態を nvidia-smi
で確かめてみます。
azure@demo:~$ nvidia-smi
Mon Dec 12 08:36:20 2016
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 375.20 Driver Version: 375.20 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 Tesla K80 Off | A848:00:00.0 Off | 0 |
| N/A 43C P0 74W / 149W | 0MiB / 11471MiB | 96% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
見えましたね。
Docker 諸々セットアップ
ホストには最低限 GPU ドライバ
のみをインストールし、その上のアプリケーションはなんでも動かしやすいよう、Docker ベースの環境にします。
1. Docker インストール
$ curl -sSL https://get.docker.com/ | sh
$ sudo service docker start
$ sudo usermod -aG docker azure
azure ユーザでも sudo なしで docker コマンドが使えるようにいったん SSH から抜け入り直します。
2. nvidia-docker インストール
$ wget -P /tmp https://github.com/NVIDIA/nvidia-docker/releases/download/v1.0.1/nvidia-docker_1.0.1-1_amd64.deb
$ sudo dpkg -i /tmp/nvidia-docker*.deb && rm /tmp/nvidia-docker*.deb
3. 起動チェック
(初回ダウンロード時は少し時間がかかりますが)
先ほどの nvidia-smi
を Docker 経由で実行してみます。
azure@demo:~$ nvidia-docker run --rm nvidia/cuda nvidia-smi
Using default tag: latest
latest: Pulling from nvidia/cuda
04cf3f0e25b6: Pull complete
..
Digest: sha256:e8ad1b9d0c3840ba07da8b622a0ede291c0c24d4025bda0a8f488b00d34c0eee
Status: Downloaded newer image for nvidia/cuda:latest
Mon Dec 12 08:50:47 2016
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 375.20 Driver Version: 375.20 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 Tesla K80 Off | A848:00:00.0 Off | 0 |
| N/A 38C P8 33W / 149W | 121MiB / 11471MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
いいですね。コンテナの中からもホストの GPU が見えました!
Docker の起動フラグ
nvidia-docker を使うととても楽ができるものの、最後に、それがなくとも Docker から GPU を使うための方法をまとめ直します。
- --privileged
- --device
--privileged
特権モードとなるため、ホストの すべてのデバイス がそのまま見えます。
必要以上に権限を渡すことになるため、後述の --device
の方が望ましい。
azure@demo:~$ docker run -it --rm --privileged nvidia/cuda sh
root# ls -la /dev | grep nvidia
crw-rw-rw- 1 root root 245, 0 Dec 12 10:05 nvidia-uvm
crw-rw-rw- 1 root root 245, 1 Dec 12 10:05 nvidia-uvm-tools
crw-rw-rw- 1 root root 195, 0 Dec 12 10:05 nvidia0
crw-rw-rw- 1 root root 195, 255 Dec 12 10:05 nvidiactl
--device
特定のデバイスのみにアクセスを許可するには --device
を使います。:rwm
オプションによって読み込み専用などの読み書き制御も付与できます。
nvidia-docker が内部的に使っているのはこれ。実際に、nvidia-docker-plugin に HTTP リクエストで問い合わせれば docker に渡しているオプションを確認することもできます。
azure@demo:~$ curl 127.0.0.1:3476/v1.0/docker/cli
--volume-driver=nvidia-docker --volume=nvidia_driver_375.20:/usr/local/nvidia:ro --device=/dev/nvidiactl --device=/dev/nvidia-uvm --device=/dev/nvidia-uvm-tools --device=/dev/nvidia0
つまり nvidia-docker で docker をラップすると、内部的に以下の引数を docker run
に加えていることがわかります。
オプション | 値 |
---|---|
--volume-driver | nvidia-docker |
--volume | nvidia_driver_375.20:/usr/local/nvidia:ro |
--device | /dev/nvidiactl |
--device | /dev/nvidia-uvm |
--device | /dev/nvidia-uvm-tools |
--device | /dev/nvidia0 |
--device オプションを使ってみると
azure@demo:~$ docker run -it --rm --device=/dev/nvidia0 nvidia/cuda sh
root# ls -la /dev | grep nvidia
crw-rw-rw- 1 root root 195, 0 Dec 12 10:16 nvidia0
期待通り、渡した GPU だけが見えました。
おわり