Docker 用于基于 GUI 的环境?

Posted

技术标签:

【中文标题】Docker 用于基于 GUI 的环境?【英文标题】:Docker for GUI-based environments? 【发布时间】:2014-06-07 09:53:33 【问题描述】:

问题

我有一组客户端计算机,它们是企业 Web 应用程序的一部分。每台机器都运行相同的软件,这是一个连接到服务器的基于 PyQT 的 Web 客户端。这个客户端软件会定期更新,我希望有一些配置/配置工具,允许在每台机器上拥有相同的环境,因此可以轻松地将软件部署和配置到每台客户端的机器上。

问题是我尝试过使用 Chef,但要真正维护 Chef 的知识和技能需要付出很多努力(我们没有专门的 Ops 人员),而且如果某个第三方存储库,Chef 配方可能会失败is no longer available(这是一个主要的塞子)。

我想尝试 Docker 来解决这个问题,但我 still do not know 是否可以设置允许某些基于 GUI 的软件运行的图像/容器。

问题

是否可以使用 Docker 为基于 GUI 的应用程序(PyQt/QT)提供开发/生产环境?如果是,解决该问题的第一步是什么?

【问题讨论】:

没有专门的 Ops Geek (m/f)?您处于进行 devops 的完美位置;-) 通过缓存所有资源来处理第三方的东西,如果需要的话,作为本地维护的包。否则,继续重构和维护你的部署代码,你会做得更好。 @HenkLangveld,我希望我们可以使用“配置一次运行始终”的方法。我最好为应用程序编写一些代码,而不是为 Chef 编写 Ruby DSL。 如果您可以预测生产中的确切运行时环境,包括所有未来的需求,那就太好了。你也不知道,一个专门的操作极客也不知道。让它现在运行,简单。然后在应用程序和运行时需要更改时进行调整。 can you run GUI apps in a docker container?的可能重复 【参考方案1】:

目前这个问题没有答案,但它在谷歌上的排名很高。其他答案大多是正确的,但有一些警告是我通过艰难的方式学到的,我想为其他人省去麻烦。

Nasser Alshammari 给出的答案是在 Docker 容器中运行 GTK 应用程序的最简单(也是最快)的方法 - 只需将 X 服务器的套接字挂载为 Docker 卷,然后告诉 Docker 使用它。

docker run -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=unix$DISPLAY TheImage

(我还建议传递 -u <username-within-container> 标志,因为以 root 身份运行 X11 应用程序并不总是有效,通常不推荐,尤其是在共享会话时

这适用于 xterm 等应用程序以及基于 GTK 的应用程序。例如,如果您在 Firefox(基于 GTK)上尝试此操作,它将起作用(请注意,如果您已经在主机上运行 Firefox,它将在主机中打开一个新窗口,而不是打开一个新的 Firefox 实例从容器内)。

但是,您的回答专门询问了 PyQT。 It turns out that Qt does not support sharing of X sessions in this way(或者至少不支持)。

如果您尝试以这种方式运行基于 QT 的应用程序,您可能会收到如下错误:

X Error: BadAccess (attempt to access private resource denied) 10
  Extension:    140 (MIT-SHM)
  Minor opcode: 1 (X_ShmAttach)
  Resource id:  0x12d
X Error: BadShmSeg (invalid shared segment parameter) 148
  Extension:    140 (MIT-SHM)
  Minor opcode: 5 (X_ShmCreatePixmap)
  Resource id:  0xb1
X Error: BadDrawable (invalid Pixmap or Window parameter) 9
  Major opcode: 62 (X_CopyArea)
  Resource id:  0x2c0000d
X Error: BadDrawable (invalid Pixmap or Window parameter) 9
  Major opcode: 62 (X_CopyArea)
  Resource id:  0x2c0000d

我说“可能”是因为我没有用足够多的 Qt 应用程序测试这种方法来确定,或者深入研究 Qt 源代码以找出不支持的原因。 YMMV,您可能会很幸运,但如果您希望从 Docker 容器中运行基于 Qt 的应用程序,您可能必须采用“老式”方法和任一

    在容器内运行 sshd,开启 X11 转发,然后使用ssh -X(更安全)或ssh -Y(安全性较低,如果您使用完全信任容器化应用程序)。

    在容器内运行 VNC,并使用 VNC 客户端从主机连接到它。

在这两个选项之间,我会推荐第一个,但看看哪个最适合您的情况。

【讨论】:

“没有可接受的答案”!=“没有答案”。没什么大不了的,但我必须检查一下我是否还在看同一个问题。 明白,但我想专门记录 Qt 行为,因为它是 OP 问题的关键部分。如果其他人在调试时偶然发现了这个页面(就像我在当天早些时候所做的那样!),我只是想确保他们不必重复这项工作。 :) export QT_X11_NO_MITSHM=1 将修复您的 QT 错误。 如果你得到一个错误 "Gtk-WARNING : cannot open display: unix:0.0" 试试这个:xhost +local:docker hub.docker.com/r/meertec/firefox export QT_GRAPHICSSYSTEM=native 还将修复 X 错误:BadAccess(尝试访问私有资源被拒绝)10 错误【参考方案2】:

有许多解决方案可以让 GUI 应用程序在 docker 容器中运行。例如,您可以使用 SSH 或 VNC。但是它们增加了一些开销和延迟。我发现最好的方法就是将主机中 X 服务器使用的文件作为卷传递给容器。像这样:

docker run -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=unix$DISPLAY TheImage

然后您的所有 GUI 应用程序都将从容器中运行。

希望这有帮助!

【讨论】:

如果我在 windows 或 mac 上运行 docker 会发生什么?我可以使用相同的解决方案吗?因为我不认为我可以用同样的方式绑定显示。【参考方案3】:

我设法在容器中运行 xeyes,并在容器外部运行的 X 服务器中看到“窗口”。方法如下:

我使用 Xephyr 运行嵌套的 X 服务器。这不是必需的,但大多数 linux 桌面默认不允许在其上运行远程应用程序(here's how to "fix" this on ubuntu)。

安装 Xephyr:

$ sudo apt-get install xserver-xephyr

运行 Xephyr:

$ Xephyr -ac -br -noreset -screen 800x600 -host-cursor :1

这会创建一个新的 800x600 窗口,用作 X 服务器。

找到您机器的“外部”地址。这是 X 服务器运行的地方:

$ ifconfig

docker0   Link encap:Ethernet  HWaddr 56:84:7a:fe:97:99  
          inet addr:172.17.42.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::5484:7aff:fefe:9799/64 Scope:Link
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:133395 errors:0 dropped:0 overruns:0 frame:0
          TX packets:242570 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:9566682 (9.5 MB)  TX bytes:353001178 (353.0 MB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:650493 errors:0 dropped:0 overruns:0 frame:0
          TX packets:650493 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:2506560450 (2.5 GB)  TX bytes:2506560450 (2.5 GB)

wlan0     Link encap:Ethernet  HWaddr c4:85:08:97:b6:de  
          inet addr:192.168.129.159  Bcast:192.168.129.255  Mask:255.255.255.0
          inet6 addr: fe80::c685:8ff:fe97:b6de/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:6587370 errors:0 dropped:1 overruns:0 frame:0
          TX packets:3716257 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:7405648745 (7.4 GB)  TX bytes:693693327 (693.6 MB)

不要使用 127.0.0.1!您可以使用其他任何一种。我将使用 172.17.42.1。

创建一个包含以下内容的 Dockerfile:

FROM ubuntu

RUN apt-get update
RUN apt-get install -y x11-apps

CMD ["/usr/bin/xeyes"]

构建它:

$ docker build -t xeyes .

然后运行它:

$ docker run -e DISPLAY=172.17.42.1:1.0 xeyes

请注意,我将 DISPLAY 环境变量设置为我想查看的位置。

您可以使用相同的技术将显示重定向到任何 X 服务器。

【讨论】:

【参考方案4】:

最近我尝试在 docker 中运行 PyQt5 应用程序。我了解到的是,您不能以 root 身份运行应用程序(您必须创建普通用户)。当您想在应用程序中播放音频/视频时,您必须运行带有“音频”组的 docker 容器并安装声音设备。所以要运行我的应用程序,我使用这个:

docker run -it \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    -v $(pwd)/test:/app \
    -e DISPLAY=$DISPLAY \
    -u myusername \
    --group-add audio \
    --device /dev/snd \
    fadawar/docker-pyqt5-qml-qtmultimedia python3 /app/hello.py

我花了一些时间,直到弄清楚需要添加到容器中才能在其中运行 PyQt 应用程序的包,所以我创建了一些 Dockerfiles(带有简单的演示应用程序),以便其他人更容易:

Python 3 + PyQt5:https://github.com/jozo/docker-pyqt5

Python 3 + PyQt5 + QML + QtMultimedia:https://github.com/jozo/docker-pyqt5-qml-qtmultimedia

【讨论】:

【参考方案5】:

以下是您需要遵循的基本步骤才能让一切正常运行,

    创建并运行 Docker 容器

    sudo nvidia-docker run -it -d --privileged -e DISPLAY=$DISPLAY --name wakemeeup -v -v /dev:/dev -v /tmp/.X11-unix:/tmp/.X11-unix:rw nvidia/cuda:9.1-cudnn7-devel-ubuntu16.04 bash

    启动 docker 容器

    sudo docker start wakemeup

    附加到 docker 容器

    xhost +local:root 1>/dev/null 2>&1 docker exec -u $USER -it wakemeup /bin/bash xhost -local:root 1>/dev/null 2>&1

    MIT-SHM 是 X 服务器的扩展,它通过使用共享内存实现更快的事务。 Docker 隔离可能会阻止它。可以强制 Qt 应用程序不使用该扩展。在 docker 容器内,

    nano ~/.bashrc export QT_X11_NO_MITSHM=1

    来源.bashrc

    source ~/.bashrc

希望这会有所帮助

【讨论】:

最后一个标志和以下答案为我修复了它。谢谢! ***.com/a/35040140/543720【参考方案6】:

已解决 - Docker 容器中的 PyQt5-GUI:

启用 Qt-Debug $ export QT_DEBUG_PLUGINS=1 ==> 重现错误 ==> 重新/安装调试消息中列出的 No such file or directory-library ==> 重复!

我也无法在 Docker 容器中运行 PyQt5-GUI-app 而不会收到错误,并且首先阅读了所有无法在 Docker 容器中运行 Qt 的帖子。但我可以解决它(至少对我来说)......

系统

我正在一个 Docker 容器中运行我的 PyQt5 应用程序,并使用共享的 /tmp/.X11-unix/ 套接字和用于 GUI 可视化的显示:

$ nividia-docker run --interactive --tty --env DISPLAY=$DISPLAY --volume /tmp/.X11-unix/:/tmp/.X11-unix/ <docker_iamge>

错误

初始化PyQt5.QtWidgets.QApplication 总是导致以下错误:

Type "help", "copyright", "credits" or "license" for more information.
>>> from PyQt5.QtWidgets import QApplication
>>> app = QApplication([])
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

Available platform plugins are: eglfs, linuxfb, minimal, minimalegl, offscreen, vnc, wayland-egl, wayland, wayland-xcomposite-egl, wayland-xcomposite-glx, webgl, xcb.

Aborted (core dumped)

在 PyCharm 调试模式下返回的错误:

Process finished with exit code 134 (interrupted by signal 6: SIGABRT)

解决方案

一般方法:

在 docker 容器终端中设置 Qt-debug 环境变量:
   $ export QT_DEBUG_PLUGINS=1
在 docker 终端(或 IDE)中重现错误,例如:
$ python
Python 3.6.8 |Anaconda, Inc.| (default, Dec 30 2018, 01:22:34) 
[GCC 7.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.

>>> 
KeyboardInterrupt
>>> from PyQt5.QtWidgets import QApplication, QLabel
>>> app = QApplication([])
读取打印到终端的调试消息,例如:
QFactoryLoader::QFactoryLoader() checking directory path "/conda/envs/rapids/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforms" ...
QFactoryLoader::QFactoryLoader() looking at "/conda/envs/rapids/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforms/libqeglfs.so"
Found metadata in lib /conda/envs/rapids/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforms/libqeglfs.so, metadata=

    "IID": "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.3",
    "MetaData": 
        "Keys": [
            "eglfs"
        ]
    ,
...
...
...
Got keys from plugin meta data ("xcb")
QFactoryLoader::QFactoryLoader() checking directory path "/conda/envs/rapids/bin/platforms" ...
Cannot load library /conda/envs/rapids/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforms/libqxcb.so: (libxkbcommon-x11.so.0: cannot open shared object file: No such file or directory)
QLibraryPrivate::loadPlugin failed on "/conda/envs/rapids/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforms/libqxcb.so" : "Cannot load library /conda/envs/rapids/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforms/libqxcb.so: (libxkbcommon-x11.so.0: cannot open shared object file: No such file or directory)"
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

Available platform plugins are: eglfs, linuxfb, minimal, minimalegl, offscreen, vnc, wayland-egl, wayland, wayland-xcomposite-egl, wayland-xcomposite-glx, webgl, xcb.

Aborted (core dumped)
在这里找到 &lt;No such file or directory&gt;.so.*&lt;coud not be loaded&gt;-packages,例如libxkbcommon-x11.so.0libxcb。然后重新/安装相应的包/库(找到与apt-file --package-only search &lt;filename&gt;conda/pip search ... 一起使用的包)。在我的情况下,需要以下库:
### lib no.1 ###
$ sudo conda install --name <env_name> --force-reinstall libxcb    # or pip install ...
### lib no. 2 ###
$ apt-file --package-only search libxkbcommon-x11.so.0
libxkbcommon-x11-0
$ sudo apt install libxkbcommon-x11-0 

对所有按顺序复制的调试消息重复此过程并安装 2 个库后,我现在可以在本地计算机桌面上的 Docker 容器内运行 PyQt5-apps。

【讨论】:

我在 上放什么?是docker镜像的名字吗? @just_learning 这是您的 conda 环境的唯一名称,以防您将 conda 用作安装所有 python 包的虚拟 python 环境,请参阅documentation。【参考方案7】:

您可以使用subuser 来打包您的GUI 应用程序。它还对更新应用程序有很好的支持。你可以将你的 Dockerfiles 放在一个 git repo 中,然后在每个客户端上运行 subuser update all 以在需要更改图像时重建它们。

【讨论】:

【参考方案8】:

对于 Mac Catalina,必须先安装 XQuartz,然后...

xhost 127.0.0.1
export DISPLAY=:0
ssh -Y
docker run -e DISPLAY=host.docker.internal:0 -it ros

【讨论】:

以上是关于Docker 用于基于 GUI 的环境?的主要内容,如果未能解决你的问题,请参考以下文章

认识docker

如何在 Docker 映像中打开 Ubuntu GUI

使用docker方式运行elasticsearch-head

使用docker方式运行elasticsearch-head

基于docker制作Tomcat镜像

在 Docker 中运行 Kong,Kong 在 Web 浏览器中不显示 GUI