在 docker 中使用 OpenGL 和 nvidia-docker2

Posted

技术标签:

【中文标题】在 docker 中使用 OpenGL 和 nvidia-docker2【英文标题】:Using OpenGL inside docker with nvidia-docker2 【发布时间】:2019-05-16 07:07:35 【问题描述】:

我正在尝试在 Ubuntu 16.04 容器内运行 OpenGL 应用程序 (Gazebo),并且我希望能够在可用时利用 nvidia 图形加速。我正在尝试找出推荐的、官方支持(希望得到 nvidia 支持)的方法是什么。

我的要求:

    创建图像非常耗时,因此我希望为所有类型的图形(nvidia、mesa 即其他所有图像)创建一个图像,或者如果分开,它们应该“从”公共基础图像构建包含大部分内容。 nvidia 容器应该在不同的系统上工作,这些系统可能安装了不同的 nvidia 卡和驱动程序版本。 我需要使用 Ubuntu 16.04,公司需要这个,尽管这是这些要求中最不重要的,例如如果这只能在 18.04 完成,我也会感兴趣。

到目前为止我已经尝试过:

只需使用 FROM nvidia/opengl:1.0-glvnd-runtime-ubuntu16.04 为 nvidia 和其他所有内容构建单独的图像。这很好用,但需要构建两个映像,这需要两倍的时间和两倍的磁盘空间。 违反了要求 1。 首先从ubuntu:16.04 构建“普通”(mesa/intel) 映像,在那里完成所有耗时的工作,然后将其用作另一个映像的基础,其中从官方“运行文件”手动安装 NVIDIA 驱动程序”。如果驱动程序与主机上安装的驱动程序完全匹配,则此方法有效,但如果主机具有不同的(例如较旧的)版本,则此方法无效。 违反了要求 2。 什么都不做,只需使用--runtime=nvidia -e NVIDIA_VISIBLE_DEVICES=all -e NVIDIA_DRIVER_CAPABILITIES=all 运行我的常规台面启用容器。如果我这样做了,nvidia-smi 会看到该卡,但 OpenGL(例如 glxinfo)仍会尝试加载 swrast 驱动程序,这不起作用。

我在野外看到的大多数示例都使用nvidia/opengl:1.0-glvnd-runtime-ubuntu16.04 基础,而在我的一生中,我无法在该图像中找到nvidia 驱动程序的安装方式(如果有的话)。我还在某处读到,使用 nvidia 容器运行时(即我正在使用的 nvidia-docker2)您不需要安装驱动程序,但情况似乎并非如此,至少对于 OpenGL .

再说一遍,有没有办法为 nvidia 和非 nvidia 创建满足我所有要求的容器映像,或者我只是想要太多?

【问题讨论】:

不能配置Docker从宿主环境绑定mount单个文件吗?我自己从未使用过 Docker,但经常使用 lxc 或 voidlinux 容器。本质上,您可以将外部的单个文件“绑定”到容器中。 /dev 图形节点在那里很简单,所以这都是关于 OpenGL 库的(如果你想要 Vulkan,ICD)。所以我的方法是有一些辅助程序在外部确定有哪些 OpenGL / Vulkan 相关库文件,并在启动时将它们绑定到容器中。 @datenwolf 是的,我可以配置 docker 来绑定挂载单个文件,而且,nvidia-docker 已经处理好了。问题在于容器没有“看到”卡,问题在于内部有正确的驱动程序来运行 OpenGL 应用程序。 通过我提到的文件 IS 通过驱动程序。不幸的是,这些路径是特定于分布的,所以 docker 图像的分布独立性的整个想法在这里离开了舞台。但是,如果您查看ldd $(which glxinfo) | grep libGL 的输出并将那里报告的文件(确保解析符号链接!)绑定到容器中,您实际上是从外部引入了 OpenGL 驱动程序,至少对于客户端而言。对于 Vulkan,您可能需要查看 /usr/share/vulkan/icd.d 的内容 这里的要点是,Linux 中的图形驱动程序由内核部分和用户区部分组成。内核部分在所有用户空间之间共享,无论是否在容器内。用户空间部分必须匹配内核部分。并且内核驱动程序作为主机系统的一部分进行管理,因此唯一明智的方法是将主机系统的用户区部分绑定到容器中。也就是说,为什么要绑定挂载这些特定文件。 @datenwolf 是的,我知道这一点,但你基本上证实了这一点。 nvidia 容器运行时(a.k.a nvidia-docker 2.x)应该做到这一点,它确实做到了,除了显然是 OpenGL;我怀疑它主要是为 Cuda 设计的,但它确实具有可以启用的“opengl”功能。 【参考方案1】:

既然可以“窃取”别人的解决方案,为什么还要浪费时间尝试自己找出解决方案?特别是如果其他人是 NVIDIA 自己。

由于nvidia/opengl:1.0-glvnd-runtime-ubuntu16.04 似乎运作良好,但将其用作基本要求 1,我可以将文件从中复制并复制到我的图像中。

这里$from 指向我原来的、不支持nvidia 的容器映像(但我也用from=ubuntu:16.04 对其进行了测试),我只是将nvidia 的驱动程序和配置复制过来:

ARG from
FROM nvidia/opengl:1.0-glvnd-runtime-ubuntu16.04 as nvidia
FROM $from

COPY --from=nvidia /usr/local /usr/local
COPY --from=nvidia /etc/ld.so.conf.d/glvnd.conf /etc/ld.so.conf.d/glvnd.conf

ENV NVIDIA_VISIBLE_DEVICES=all NVIDIA_DRIVER_CAPABILITIES=all

有了这个,我的$from 建立在ubuntu:16.04 之上,glxinfo 返回预期的配置(NVIDIA 是 GL 供应商),我可以像在主机上一样运行 Gazebo、Blender 等。这样做的美妙之处在于,即使不使用 nvidia 运行时,生成的容器也能工作,在没有 nvidia 驱动程序的系统上,它只是优雅地回退到使用 Mesa(我猜这就是“glvnd”所做的)。

虽然我目前需要使用 Ubuntu 16.04,但我认为类似的方法不能用于其他 Ubuntu 版本。

【讨论】:

以上是关于在 docker 中使用 OpenGL 和 nvidia-docker2的主要内容,如果未能解决你的问题,请参考以下文章

private virtual函数

如何在没有 FBConfig 错误的情况下在 docker 内运行 glut 应用程序?

在 OpenGL 的正交投影中使用纹理

在 tweetinvi 中查找推文的 tweetID

在 CG 和 openGL 中使用统一的 1D 纹理参数时出错

如何在 Windows 7 中使用 OpenGL、Glut 和 Visual Studio 2008 准备 C++ 项目