基于GUI的环境的Docker?

时间:2014-06-07 09:53:33

标签: qt vagrant chef docker configuration-management

问题

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

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

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

问题

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

8 个答案:

答案 0 :(得分:20)

目前这个问题没有得到解答,但在Google上排名很高。其他答案大多是正确的,但有一些警告,我已经学到了很多困难,我想拯救别人的麻烦。

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的应用程序,你可能必须采用“老式”方法而

  1. 在容器中运行sshd,打开X11转发,然后使用ssh -X(更安全)或ssh -Y连接到容器(安全性较低,仅使用 如果您完全信任容器化应用程序。)

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

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

答案 1 :(得分:9)

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

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

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

希望这有帮助!

答案 2 :(得分:4)

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

我使用Xephyr来运行嵌套的X Server。这不是必需的,但大多数Linux桌面默认不允许在它们上运行远程应用程序(here如何在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服务器。

答案 3 :(得分:1)

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

答案 4 :(得分:1)

最近我试图在docker中运行PyQt5应用程序。我学到的是你不能以root身份运行应用程序(你必须创建普通用户)。当你想在应用程序中播放音频/视频时,你必须运行docker container with group&#34; audio&#34;并安装声音设备。所以要运行我的应用程序,我使用它:

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 :(得分:1)

这是您需要执行的基本步骤,以确保一切正常,

  1. 创建并运行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

  2. 启动Docker容器

    sudo docker start wakemeup

  3. 要附加到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

  4. MIT-SHM是X服务器的扩展,它可以通过使用共享内存来加快交易速度。 Docker隔离可能会阻止它。可以强制Qt应用程序不使用扩展名。在Docker容器中,

    nano ~/.bashrc export QT_X11_NO_MITSHM=1

  5. 源.bashrc

    source ~/.bashrc

希望这会有所帮助

答案 6 :(得分:0)

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

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

在没有收到错误的情况下,我也无法在Docker容器中运行PyQt5-GUI-app,并且首先阅读了所有文章,这些文章将无法在Docker容器中运行Qt。但是我可以解决(至少对我来说)...

系统

我正在使用共享的/tmp/.X11-unix/套接字在Docker容器中运行 PyQt5-应用程序,并显示图形用户界面(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)
  • 找到<No such file or directory>.so.*<coud not be loaded>软件包,例如libxkbcommon-x11.so.0libxcb。然后重新/安装相应的软件包/库(查找与apt-file --package-only search <filename>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。

答案 7 :(得分:0)

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

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