概要

Tue 23 Nov 2021 02:50:33 PM JST 現在、Debian 11 用には nvidia-docker 等の deb パッケージが用意されていない。これは、cgroup のアップグレードにより、nvidia container stack の rearchitecture が必要で、それに時間がかかっているらしい (https://github.com/NVIDIA/nvidia-docker/issues/1447#issuecomment-760189260)。つまり、debパッケージがただ無いだけではなく、現行のバージョンのソースをビルドしても Debian 11 では使用不可能ということ。

ワークアラウンドはあるようなので、一連のツールキットをビルドしてワークアラウンドを適用する方法をまとめる。

*2022-08-01T16:57:37+09:00 現在、サポートされたようだ。*https://github.com/NVIDIA/nvidia-docker/issues/1549#issuecomment-1030066481

更新のコマンドだけかんたんにまとめておく。

distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
   && curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add - \
   && curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list \
   && apt install libnvidia-container1 libnvidia-container-tools nvidia-container-toolkit nvidia-container-runtime nvidia-docker

必要なパッケージが 開発者の投稿 とマッチしているか確認する。

  • libnvidia-container1-1.9.0
  • libnvidia-container-tools-1.9.0
  • nvidia-container-toolkit-1.9.0
  • nvidia-container-runtime-3.9.0
  • nvidia-docker-2.10.0

再起動して終了。

おまけ: nvidia driver のアップグレード

ついでに、 nvidia driver のアップグレード方法について残しておく。

始める前に、新しい nvidia driver が自分の GPU に対応しているか確認する必要がある。これは、GPUによってことなる Computation Capability と cuda toolkit が要求する nvidia driver のバージョンからチェックする必要がある。まずは、https://developer.nvidia.com/cuda-gpus にアクセスし、自分の GPU の Computation Capability を確認する。例えば、 Geforce GTX 1060 ならば 6.1。次に、nvidia driver のバージョンがサポートする compute capability を確認する (https://docs.nvidia.com/deploy/cuda-compatibility/index.html の which GPUs are supported by the driver? の節。) 。 6.x ならば、現状最新の 515.43.04+ をサポートしているので問題ない。

確認ができたら、古い nvidia driver を除去する。古い nvidia driver をパッケージマネージャでインストールしたか nvidia が提供する実行ファイル (*.run) でインストールしたかで作業が少し変わる (https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#pre-installation-actions)。

Table 3. NVIDIA Driver Installation Compatibility Matrix

Table 3. NVIDIA Driver Installation Compatibility Matrix
  Installed Driver Version == X.Y Installed Driver Version != X.Y
RPM/Deb run RPM/Deb run
Installing Driver Version X.Y RPM/Deb No Action Uninstall Run No Action Uninstall Run
run Uninstall RPM/Deb No Action Uninstall RPM/Deb No Action

古いものが deb パッケージでインストールされていて、かつ今回も deb パッケージでインストールするならば、特にすることはない。

あとは、あたらしいリポジトリを APT に追加し、apt install コマンドを発効すればよい (https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#debian-installation)。

Installation (Tue 23 Nov 2021 02:50:33 PM JST 以前)

パッケージは用意されていないので、自分でビルドする。もしかすると debian 10 用の deb パッケージを流用できるかもしれないが、未検証。

ソースからビルドする場合は、みっつのプロジェクトを順にビルドする。

これらのリポジトリは、docker コンテナ内でビルドするようできているので、docker さえ入っていればとくに dependencies のインストールは必要ない。ただし、 debian 11 に対応するため、いくつかの変更は行う必要がある。みっつ全てに共通するのは、ビルドのために debian 11 のイメージを使うようにすること。加えて、libnvidia-container では、 (リンカのアップグレードによる仕様変更のため?) オブジェクトファイルであるダイナミックリンクライブラリの命名に失敗するので、その名前変更のためのコマンドを追加する。

libnvidia-container

libnvidia-container-toolkit のコミット a648cd2a698eb56d71150d8790d96e445f9ae351 に対して、以下のパッチを適用する。

diff --git a/mk/Dockerfile.debian b/mk/Dockerfile.debian
index ce582fb..612ea33 100644
--- a/mk/Dockerfile.debian
+++ b/mk/Dockerfile.debian
@@ -38,7 +38,7 @@ ENV WITH_SECCOMP=${WITH_SECCOMP}

 ARG REVISION
 ENV REVISION=${REVISION}
-RUN make distclean && make -j"$(nproc)"
+RUN make distclean && make -j"$(nproc)" || mv -v 'deps/src/elftoolchain-0.7.1/libelf/name libelf.so.1' deps/src/elftoolchain-0.7.1/libelf/libelf.so.1

 # Use the revision as the package version for the time being
 ENV PKG_NAME libnvidia-container
diff --git a/mk/docker.mk b/mk/docker.mk
index aef1762..f800bfa 100644
--- a/mk/docker.mk
+++ b/mk/docker.mk
@@ -28,8 +28,8 @@ MAKE_DIR     ?= $(CURDIR)/mk
 REVISION        ?= $(shell git rev-parse HEAD)

 # Supported OSs by architecture
-AMD64_TARGETS := ubuntu20.04 ubuntu18.04 ubuntu16.04 debian10 debian9
-X86_64_TARGETS := centos7 centos8 rhel7 rhel8 amazonlinux1 amazonlinux2 opensuse-leap15.1
+AMD64_TARGETS := debian11 debian10
+X86_64_TARGETS :=
 PPC64LE_TARGETS := ubuntu18.04 ubuntu16.04 centos7 centos8 rhel7 rhel8
 ARM64_TARGETS := ubuntu18.04
 AARCH64_TARGETS := centos8 rhel8 amazonlinux2

前半部分の変更が、ダイナミックライブラリの命名変更 [1]。

-RUN make distclean && make -j"$(nproc)"
+RUN make distclean && make -j"$(nproc)" || mv -v 'deps/src/elftoolchain-0.7.1/libelf/name libelf.so.1' deps/src/elftoolchain-0.7.1/libelf/libelf.so.1

後半部分で、debian11 のコンテナイメージをpullするために debian11 を追記する。ついでに、不要なアーキテクチャ用のバイナリを作らないように他の識別子は削除しておく (しなくても余分なビルドが行われるだけ)。

-AMD64_TARGETS := ubuntu20.04 ubuntu18.04 ubuntu16.04 debian10 debian9
-X86_64_TARGETS := centos7 centos8 rhel7 rhel8 amazonlinux1 amazonlinux2 opensuse-leap15.1
+AMD64_TARGETS := debian11 debian10
+X86_64_TARGETS :=

nvidia-container-toolkit

nvidia-container-tookit のコミット 92bb04f0fd42a52291c56b6e73d2383ba36f3e4e に対して、以下のパッチを適用する。これは debian 11 のコンテナイメージを使ってビルドするよう指示する。

diff --git a/docker/docker.mk b/docker/docker.mk
index 4ac9d00..35890fd 100644
--- a/docker/docker.mk
+++ b/docker/docker.mk
@@ -13,8 +13,8 @@
 # limitations under the License.

 # Supported OSs by architecture
-AMD64_TARGETS := ubuntu20.04 ubuntu18.04 ubuntu16.04 debian10 debian9
-X86_64_TARGETS := centos7 centos8 rhel7 rhel8 amazonlinux1 amazonlinux2 opensuse-leap15.1
+AMD64_TARGETS := debian11 debian10
+X86_64_TARGETS :=
 PPC64LE_TARGETS := ubuntu18.04 ubuntu16.04 centos7 centos8 rhel7 rhel8
 ARM64_TARGETS := ubuntu20.04 ubuntu18.04
 AARCH64_TARGETS := centos8 rhel8 amazonlinux2

nvidia-docker

nvidia-docker のコミット fd3233aa5f4ade28ac6bda616c2fa77a0ce89cd9 に対して、以下のパッチを適用する。これは debian 11 のコンテナイメージを使ってビルドするよう指示する。

diff --git a/docker/docker.mk b/docker/docker.mk
index 23ce01c..12f1423 100644
--- a/docker/docker.mk
+++ b/docker/docker.mk
@@ -17,8 +17,8 @@ MKDIR  ?= mkdir
 DIST_DIR ?= $(CURDIR)/dist

 # Supported OSs by architecture
-AMD64_TARGETS := ubuntu20.04 ubuntu18.04 ubuntu16.04 debian10 debian9
-X86_64_TARGETS := centos7 centos8 rhel7 rhel8 amazonlinux1 amazonlinux2 opensuse-leap15.1
+AMD64_TARGETS := debian11 debian10
+X86_64_TARGETS :=
 PPC64LE_TARGETS := ubuntu18.04 ubuntu16.04 centos7 centos8 rhel7 rhel8
 ARM64_TARGETS := ubuntu20.04 ubuntu18.04
 AARCH64_TARGETS := centos8 rhel8 amazonlinux2

ビルドとインストール

パッチを当てたら、それぞれのプロジェクトルートで、make または make debian11 を実行すれば、dist/ というディレクトリができ、その中に *.deb ファイルが生成される。これを dpkg などでインストールすればよい。

cgroup に対するワークアラウンド

cgroup を使わないようにし、GPU を指す devfs を直接叩くようにする [2]。ついでに、NVIDIA-SMI couldn’t find libnvidia-ml.so library in your systemの対応もする [3]。

$ cat /etc/nvidia-container-runtime/config.toml
disable-require = false
#swarm-resource = "DOCKER_RESOURCE_GPU"
#accept-nvidia-visible-devices-envvar-when-unprivileged = true
#accept-nvidia-visible-devices-as-volume-mounts = false

[nvidia-container-cli]
#root = "/run/nvidia/driver"
#path = "/usr/bin/nvidia-container-cli"
environment = []
debug = "/var/log/nvidia-container-toolkit.log"
#ldcache = "/etc/ld.so.cache"
load-kmods = true
no-cgroups = true # ← false to true [2]
#user = "root:video"
ldconfig = "/sbin/ldconfig" # ← "@/sbin/ldconfig" to "/sbin/ldconfig" [3]

[nvidia-container-runtime]
debug = "/var/log/nvidia-container-runtime.log"

加えて、初期状態では nvidia-uvm などのカーネルモジュールがロードされていないので、 nvidia-modprobe でロードするようにする。docker のデーモンが起動する前にロードされるように、systemd で管理する。ファイル docker.service.d/override.conf を追加する [4]。

$ cat /lib/systemd/system/docker.service.d/override.conf
[Service]
ExecStartPre=-/usr/bin/nvidia-modprobe -c 0 -u

GPUを使うコンテナを起動するときは、GPUの devfs を共有するように、docker run のオプションに以下を常に追加する [2]。

    --device /dev/nvidia0 \
    --device /dev/nvidiactl \
    --device /dev/nvidia-modeset \
    --device /dev/nvidia-uvm \
    --device /dev/nvidia-uvm-tools \

Validation

docker run --gpus all -it --rm \
    --device /dev/nvidia0:/dev/nvidia0 \
    --device /dev/nvidiactl:/dev/nvidiactl \
    --device /dev/nvidia-modeset:/dev/nvidia-modeset \
    --device /dev/nvidia-uvm:/dev/nvidia-uvm \
    --device /dev/nvidia-uvm-tools:/dev/nvidia-uvm-tools \
    pytorch/pytorch:1.9.1-cuda11.1-cudnn7-runtime python -c \
    "import torch; print(torch.cuda.is_available())"

これが True になれば OK とする。ちなみに、bullseye のパッケージレポジトリには cuda 11.2 しか無いが、 11.1 のコンテナイメージでも動く。

Reference