我是否需要 nvidia-container-runtime,为什么?

Do I need nvidia-container-runtime, and why?

我想从容器内部访问我的 NVIDIA GPU。我可以在没有 nvidia-container-runtime 的情况下执行此操作吗?

需要自定义 Docker 运行时才能与一台设备通信似乎很奇怪。那里有整个 PCI 设备世界。为什么这个需要自己的运行时?例如,假设我同时拥有 NVIDIA 和 AMD GPU。我是否无法从一个容器内同时访问两者?

我知道 nvidia-container-runtime 让我可以通过 NVIDIA_VISIBLE_DEVICES 控制哪些 GPU 可见。但我不关心这个。我没有使用容器来隔离设备;我正在使用容器来管理 CUDA/CUDNN/TensorFlow 版本 h*ll。如果我 确实 想要隔离设备,我将永远使用相同的机制:通过控制对 /dev.

中节点的访问

简而言之,整个“自定义运行时”设计在我看来是有缺陷的。

所以,问题:

我当然无法回答与此相关的所有可能的问题。我将尝试给出一个总结。我在这里写的一些内容是基于记录的内容 here and here。我在这里的讨论也将集中在 linux 和 docker(不是 windows,不是奇点,不是 podman 等)。我也不太可能详细解决诸如“为什么其他 PCI 设备不必这样做?”之类的问题。我也不想向该领域的专家描述 docker 如何完美准确地工作。

NVIDIA GPU 驱动程序在 user space 中包含 运行 的组件,在内核 space 中也包含 运行 的其他组件。这些组件协同工作,必须协调一致。这意味着驱动程序 XYZ.AB 的内核模式组件必须仅与来自驱动程序 XYZ.AB 的 user-space 组件(而非任何其他版本)和 vice-versa.

粗略地说,docker 是一种提供隔离 user-space linux 存在的机制,运行 位于 linux 内核(所有内核 space 的东西都在这里)。 linux 内核在基础机器中(容器外),linux 用户 space 代码的 much/most 在容器内。这是允许您在 RHEL 内核上做 运行 一个 ubuntu 容器这样的 neato 事情的架构因素之一。

从 NVIDIA 驱动程序的角度来看,它的一些组件需要安装在容器内部,一些需要安装在容器外部容器。

Can I obtain access to my NVIDIA GPUs using the stock Docker (or podman) runtime?

是的,你可以,这就是 nvidia-docker 或 nvidia-container-toolkit 存在之前人们所做的。您需要在基础机器和容器中安装完全相同的驱动程序。上次我检查过,这个有效(虽然我不打算在这里提供说明。)如果你这样做,容器内的驱动程序组件与容器外的驱动程序组件匹配,并且有效。

What am I missing?

NVIDIA(可能还有其他人)想要一个更灵活的场景。上面的描述意味着如果一个容器是用任何其他驱动程序版本(而不是安装在你的基础机器上的)构建的它不能工作。这很不方便。

nvidia-docker 的最初目的是执行以下操作:在容器加载时,将存在于基础计算机中的驱动程序的 运行time 组件安装到容器中。这协调了事情,虽然它没有解决所有兼容性问题,但它解决了很多问题。通过一个简单的规则“让你的基础机器上的驱动程序更新到最新版本”,它有效地解决了可能因 driver/CUDA 运行 时间不匹配而引起的每个兼容性问题。 (CUDA 工具包,以及依赖它的任何东西,比如 CUDNN,只需要安装在容器中。)

正如您所指出的,nvidia-container-toolkit 随着时间的推移已经获得了各种其他可能有用的功能。

我不会在这里花很多时间谈论编译后的 CUDA 代码存在的兼容性策略(“向前”),以及在谈论特定驱动程序时存在的兼容性策略(“向后”)和。我也不打算提供 nvidia-container-toolkit 的使用说明,该说明已经记录在案,而且关于它的许多 questions/answers 也已经存在。

我无法回答诸如“为什么它是这样设计的?”之类的后续问题。或“这不是必需的,你为什么不这样做呢?”

回答我自己的问题:不,我们不需要 nvidia-container-runtime。

NVIDIA 共享库与驱动程序的每个小版本紧密结合。 NVIDIA 喜欢说“驱动程序在用户 space 中具有 运行 的组件”,但这当然是自相矛盾的说法。所以对于任何版本的驱动程序,都需要在容器内部访问这些共享库的相应版本。

简要说明为什么这是一个糟糕的设计:除了额外的复杂性之外,NVIDIA 共享库还依赖于系统中的其他共享库,尤其是 C 和 X11。如果 NVIDIA 库的较新版本需要来自较新的 C 或 X11 库的功能,那么 运行 使用这些较新库的系统永远无法托管较旧的容器。 (因为容器将无法 运行 较新的注入库。)在新系统上 运行 旧容器的能力是容器最重要的特性之一,至少在某些应用程序中是这样。我想我们必须希望这永远不会发生。

HPC 社区在不久前就解决了这个问题并让它发挥作用。 Here are some old instructions 用于创建便携式 Singularity GPU 容器,该容器在容器 运行 时注入所需的 NVIDIA 共享库。您可以轻松地按照类似的过程来创建便携式 OCI 或 Docker GPU 容器。

最近,Singularity 支持 --nv 标志自动注入必要的共享库。它还支持 AMD GPU 的 --rocm 标志。 (是的,AMD 选择了同样糟糕的设计。)如果您需要这两个标志,大概可以将这些标志组合起来。

the Singularity manual 中,所有这些细节都非常 well-documented。

底线:如果你问我同样的问题,试试奇点。