異なるバージョンのCUDAを一つの計算機で共存したいときにこうすると便利である。ホスト側のLinuxで nvidia-smi
を実行したときと同じようにコンテナ内の nvidia-smi
が動作するようにする。LXC でコンテナを作成し実行することはすでに出来ているとする。(非特権コンテナとUbuntu 20.04に合わせて記事を少し更新した)。一般ユーザー(非rootユーザー)でコンテナを作りたい場合 ここ を参照
ホスト側でnvidia-smiを実行すると以下のように見える
# nvidia-smi
Tue Feb 4 10:52:19 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.48.02 Driver Version: 440.48.02 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 RTX 208... Off | 00000000:08:00.0 Off | N/A |
| 30% 31C P8 25W / 250W | 18MiB / 11016MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
| 1 GeForce RTX 208... Off | 00000000:09:00.0 Off | N/A |
| 29% 32C P8 20W / 250W | 1MiB / 11019MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 1262 G /usr/lib/xorg/Xorg 16MiB |
+-----------------------------------------------------------------------------+
ホスト側での作業
まず lxc-create -n コンテナ名 -t download -- -d ubuntu -r focal -a amd64
でUbuntuのコンテナを作る。もし /var/lib/lxc
がBTRFSにあるなら -B btrfs
を付けておくと後で lxc-copy -n 古いコンテナ -N 新しいコンテナ
でコンテナを複製するときに掛かる時間が劇的に短くなる。
次に lxc-execute -n コンテナ名 -- /bin/passwd
でrootに適切なパスワードを設定する。
以下の設定を追加する
lxc.mount.entry = /dev/nvidiactl dev/nvidiactl none bind,rw,create=file 0 0
lxc.mount.entry = /dev/nvidia-modeset dev/nvidia-modeset none bind,rw,create=file,optional 0 0
lxc.mount.entry = /dev/nvidia-uvm dev/nvidia-uvm none bind,rw,create=file 0 0
lxc.mount.entry = /dev/nvidia-uvm-tools dev/nvidia-uvm-tools none bind,rw,create=file 0 0
lxc.mount.entry = /dev/nvidia0 dev/nvidia0 none bind,rw,create=file 0 0
lxc.mount.entry = /dev/nvidia1 dev/nvidia1 none bind,rw,create=file,optional 0 0
# 以下は非特権コンテナなら不要、またホストLinuxがFedora 31などCGroup2を用いるディストロの場合
# cgroupをcgroup2に置き換える
lxc.cgroup.devices.allow = c 195:* rwm
lxc.cgroup.devices.allow = c 235:* rwm
最後に lxc-start -F -n コンテナ名
でコンテナを起動する。ログインプロンプトが表示されたらrootでログインする。非特権コンテナからNVIDIA GPUにアクセスするためには上記の '/dev' 以下のファイルの所有者またはグループをコンテナ内のroot(たいていの場合100000)にchown
か chgrp
で予めホスト側で変更しておく必要がある。
コンテナ内での作業
apt-get --no-install-recommends install software-properties-common
add-apt-repository ppa:graphics-drivers/ppa
# 上記2行はUbuntu Focalでは不要
apt-get --no-install-recommends install nvidia-utils-440
最後のnvidia-utils-440
はホスト側LinuxのNVIDIAドライバのバージョンと完全に同一でないとエラーになりnvidia-smi
が動作しないので注意。ここまで行いコンテナ内でnvidia-smi
を実行すると
# nvidia-smi
Tue Feb 4 02:01:33 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.48.02 Driver Version: 440.48.02 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 RTX 208... Off | 00000000:08:00.0 Off | N/A |
| 30% 31C P8 26W / 250W | 18MiB / 11016MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
| 1 GeForce RTX 208... Off | 00000000:09:00.0 Off | N/A |
| 29% 32C P8 20W / 250W | 1MiB / 11019MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
+-----------------------------------------------------------------------------+
となる。
ホストの/homeをコンテナ内で見えるようにするには
lxc.mount.entry = /home home none bind,rw 0 0
非特権コンテナの場合上記の方法では /home
以下のすべてのファイルの所有者が nobody
になってしまし、まともにアクセスできない。その不都合を解消するためには、読み書きしたいファイルのUIDが1000であるとして、コンテナの設定ファイルの中のUID/GIDの変換方法を指定している lxc.idmap
の行を例えば以下のように書き換えるとよい。
lxc.idmap = u 0 100000 1000
lxc.idmap = g 0 100000 1000
lxc.idmap = u 1000 1000 1
lxc.idmap = g 1000 1000 1
lxc.idmap = u 1001 101001 64535
lxc.idmap = g 1001 101001 64535
上記のように書き換えるとホスト側ほホームディレクトリのUID 1000, GID 1000 がコンテナ内部でもUID 1000, GID 1000に割り当てられるため、UID 1000のユーザーがそのホームディレクトリにあるファイルを操作できるようになる。
他のホストからネットワーク的に見えるようにするには
設定ファイルに以下の内容を追加する。以下の設定はlxc-start
をrootから起動しないとエラーになりできない(コンテナは非特権でも構わない)。
lxc.net.0.type = macvlan
lxc.net.0.link = enp6s0 # この名前は "ip l" で表示されるEthernetインターフェースの名前
lxc.net.0.flags = up
lxc.net.0.name = eth0