LXC Container(Ubuntu 16.04) in Proxmox VE 4.4 でCUDAな環境を構築

# 概要
それなりのスペックを有したXeonでGTX1080 2枚載せなワークステーション(死語)に触れる機会を得たので、良い感じに皆で活用すべくProxmox VEを入れてみた。
その上で**Ubuntu 16.04なLXC Containerを動作させて、そこでCUDAを動かそうとした**。しかしながら思いの外つまずいたのでメモっておく。


# 前提
Proxmox VE 4.4は予めインストールされていることとする。
なお余談だがFakeRAID(Intel RST)なドライブ上にProxmox VEをインストールしたかったので、Debianを入れてからProxmox VEに仕立て上げた。
[Install Proxmox VE on Debian Jessie - Proxmox VE](https://pve.proxmox.com/wiki/Install_Proxmox_VE_on_Debian_Jessie)


# 参考文献
基本的には参考文献をなぞった。
[Journey to Deep Learning: Nvidia GPU passthrough to LXC Container](https://medium.com/@MARatsimbazafy/journey-to-deep-learning-nvidia-gpu-passthrough-to-lxc-container-97d0bc474957)

[Setting up CUDA in Linux containers - SQream](http://sqream.com/setting-cuda-linux-containers-2/)



# ホストマシンへのNVIDIAドライバインストール
ドライバのバージョンは `381.22` を入れることにした。
注意点として、**ホストマシンに入れたドライバのバージョンとコンテナ上に入れたドライバのバージョンは完全一致** させておく必要がある。


```
wget http://jp.download.nvidia.com/XFree86/Linux-x86_64/381.22/NVIDIA-Linux-x86_64-381.22.run
sudo chmod a+x NVIDIA-Linux-x86_64-381.22.run
sudo ./NVIDIA-Linux-x86_64-381.22.run
```

適当にポチポチすればインストールできる。

## 余談: 最新ドライバのチェック方法
公式サイトを見に行くとちゃんとまとまっている。
[NVIDIAドライバダウンロード](http://www.nvidia.co.jp/Download/Find.aspx?lang=jp)
![image](https://qiita-image-store.s3.amazonaws.com/0/133666/dee64a36-3f91-b513-f138-c4ac770999ab.png)


## 余談: アンインストール方法
aptで入れたわけじゃないので `sudo apt remove --purge nvidia*` 等で削除はできない。以下のようにして削除する。

```
sudo ./NVIDIA-Linux-x86_64-381.22.run --uninstall
```


# ホストマシンの設定
この状態だとCUDAのドライバがカーネルにロードされないらしい。
なので以下のようにファイルをかきかきしておく。

`/etc/modules-load.d/modules.conf`

```
# /etc/modules: kernel modules to load at boot time.

# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with “#” are ignored.
nvidia
nvidia_uvm
```

`/etc/udev/rules.d/70-nvidia.rules`

```
# Create /nvidia0, /dev/nvidia1 … and /nvidiactl when nvidia module is loaded
KERNEL=="nvidia", RUN+="/bin/bash -c '/usr/bin/nvidia-smi -L && /bin/chmod 666 /dev/nvidia*'"
# Create the CUDA node when nvidia_uvm CUDA module is loaded
KERNEL=="nvidia_uvm", RUN+="/bin/bash -c '/usr/bin/nvidia-modprobe -c0 -u && /bin/chmod 0666 /dev/nvidia-uvm*'"
```

設定変更後は以下コマンドを実行

```
update-initramfs -u
reboot
```

## ドライバ動作チェック
```
nvidia-smi
```

![image](https://qiita-image-store.s3.amazonaws.com/0/133666/a706789e-bb1e-c207-d9c1-c02b964e4d23.png)



## デバイスのcgroupをチェック
```
sudo nvidia-smi -L && /bin/chmod 666 /dev/nvidia*
sudo nvidia-modprobe -c0 -u && /bin/chmod 0666 /dev/nvidia-uvm*
ls /dev/nvidia* -l
```

![image](https://qiita-image-store.s3.amazonaws.com/0/133666/a539733b-fc16-4010-e838-60a030c0353f.png)
```

`195`と`244`というのをメモっておく。


# コンテナ作成
## Templateのダウンロード
local -> Content -> Templates
![image](https://qiita-image-store.s3.amazonaws.com/0/133666/51a025ad-a1c0-68c0-ed0e-5be75297f162.png)

ubuntu-16.04-standard
![image](https://qiita-image-store.s3.amazonaws.com/0/133666/d187c922-e426-72e6-24fe-037966c344dd.png)


## Create LXC
適当に作成。
![image](https://qiita-image-store.s3.amazonaws.com/0/133666/3c89bc4b-e078-c5ba-73b2-5586dfaa79bb.png)
![image](https://qiita-image-store.s3.amazonaws.com/0/133666/053a0cbc-f81a-0d74-46e3-353ccdcf325d.png)


## 設定変更
ホストマシンの以下のファイルを次のように編集。
ここで先程メモった`195`と`244`が効いてくる。

` /etc/pve/lxc/104.conf` (104はCT ID)

```
arch: amd64
cores: 44
hostname: UbuntuLXCforBD
memory: 65536
net0: name=eth0,bridge=vmbr0,gw=192.168.0.1,hwaddr=AE:1D:D8:47:0F:37,ip=192.168.0.6/24,type=veth
ostype: ubuntu
rootfs: local:104/vm-104-disk-1.raw,size=128G
swap: 12288

# 以下追記分
lxc.cgroup.devices.allow: c 195:* rwm
lxc.cgroup.devices.allow: c 244:* rwm
lxc.mount.entry: /dev/nvidia0 dev/nvidia0 none bind,optional,create=file
lxc.mount.entry: /dev/nvidia1 dev/nvidia1 none bind,optional,create=file
lxc.mount.entry: /dev/nvidiactl dev/nvidiactl none bind,optional,create=file
lxc.mount.entry: /dev/nvidia-uvm dev/nvidia-uvm none bind,optional,create=file
```

この設定追記によってコンテナ内から当該デバイスへのアクセスが可能となる。


## 起動
適当に起動。
![image](https://qiita-image-store.s3.amazonaws.com/0/133666/c6929b34-6b0a-fe56-9fd6-8bae556d3dad.png)


# コンテナへNVIDIAドライバインストール
コンテナへSSHして以下のように実行。

```
wget http://jp.download.nvidia.com/XFree86/Linux-x86_64/381.22/NVIDIA-Linux-x86_64-381.22.run
chmod a+x NVIDIA-Linux-x86_64-381.22.run
./NVIDIA-Linux-x86_64-381.22.run --no-kernel-module
```

# コンテナへCUDA Toolkitをインストール
引き続きコンテナへSSHして実行。

## 必要なライブラリをインストール
```
apt-get update
apt-get install build-essential perl-modules g++ freeglut3 freeglut3-dev libglu1-mesa libxi-dev libxmu-dev libglu1-mesa-dev
ln -s /usr/lib/x86_64-linux-gnu/libXmu.so /usr/lib/libXmu.so
ln -s /usr/lib/x86_64-linux-gnu/libXi.so /usr/lib/libXi.so
```

## runfileでインストール
公式サイトからrunfileを拾ってくる

[CUDA Toolkit Download | NVIDIA Developer](https://developer.nvidia.com/cuda-downloads)
![image](https://qiita-image-store.s3.amazonaws.com/0/133666/3b5bc6de-eff9-812a-2e24-abb53dfbb430.png)

```
wget https://developer.nvidia.com/compute/cuda/8.0/Prod2/local_installers/cuda_8.0.61_375.26_linux-run
chmod a+x cuda_8.0.61_375.26_linux-run
./cuda_8.0.61_375.26_linux-run --silent --toolkit --samples --override
```


# コンテナ上でのCUDA動作チェック
gcc-4.9じゃないとコンパイルにコケるので…

```
apt-get install gcc-4.9 g++-4.9
ln -s /usr/bin/gcc-4.9 /usr/local/cuda/bin/gcc
ln -s /usr/bin/g++-4.9 /usr/local/cuda/bin/g++
```

makeして実行

```
cd NVIDIA_CUDA-8.0_Samples/
make -j4
./bin/x86_64/linux/release/deviceQuery
```

![image](https://qiita-image-store.s3.amazonaws.com/0/133666/2f544eaf-70bd-bd82-1c87-db58e7fc36ba.png)



# 所感
NVIDIA Dockerの楽さを思い知った今日このごろ…


おしまい。