在Docker容器中运行Qt GUI

12

我有一个基于Qt5的C++ GUI,我希望能够从Docker容器内运行它。

当我尝试使用以下命令启动时:

docker run --rm -it my_image

这将导致错误输出。

qt.qpa.xcb: could not connect to display localhost:10.0
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, xcb.

因此,我搜索了如何做到这一点。我找到了在Docker容器中使用GUI Qt应用程序的文章,并基于此使用以下命令进行调用:

QT_GRAPHICSSYSTEM="native" docker run -it -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix my_image

这导致出现了相同的错误。

然后我发现了在Docker容器中是否可以运行GUI应用程序?
那里被接受的答案似乎只适用于某些应用程序,例如Firefox?
向下滚动,我得到了一个解决方案,告诉我在sshd_config中设置X11UseLocalhost no,然后像这样调用:

docker run -v $HOME:/hosthome:ro -e XAUTHORITY=/hosthome/.Xauthority -e DISPLAY=$(echo $DISPLAY | sed "s/^.*:/$(hostname -i):/") my_image

这会产生与上面错误略有不同的变化:

qt.qpa.xcb: could not connect to display 127.0.1.1:13.0
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, xcb.

在参考另一个答案后,我在我的Dockerfile中添加了ENV DISPLAY :0并使用以下方式调用它

xhost +
XSOCK=/tmp/.X11-unix/X0
docker run -v $XSOCK:$XSOCK my_image

这次,我的错误信息第一行是qt.qpa.xcb: could not connect to display :0

然后我尝试了另一个答案,添加了:

RUN export uid=0 gid=0 && \
    mkdir -p /home/developer && \
    echo "developer:x:${uid}:${gid}:Developer,,,:/home/developer:/bin/bash" >> /etc/passwd && \
    echo "developer:x:${uid}:" >> /etc/group && \
    mkdir /etc/sudoers.d/ && \
    echo "developer ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/developer && \
    chmod 0440 /etc/sudoers.d/developer && \
    chown ${uid}:${gid} -R /home/developer

我将以下内容添加到我的Dockerfile中,并运行了docker run -ti --rm -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix my_image,但还是遇到了相同的错误。

我也尝试了http://wiki.ros.org/docker/Tutorials/GUI中描述的几种方法,但仍然出现了相同的错误。


我哪里做错了吗?请注意,我通过SSH在远程机器上工作,并打开了X11转发(应用程序在Docker之外正常运行)。还请注意,我编写的是一个客户端-服务器应用程序,服务器部分不需要GUI元素,但大部分源代码都可以从其容器中正常运行。

我希望找到一种解决方案,无需更改系统,因为我使用Docker的原因就是为了让我的应用程序用户能够轻松地运行它。


1
你不能在Docker中“轻松地”运行GUI应用程序;你需要管理员级别的权限,并手动配置X Window系统连接设置的几个细节。对于最终用户来说,本机二进制文件将更容易使用。 - David Maze
尝试执行:xhost + - eyllanesc
@DavidMaze 你知道有什么好的替代方案吗?基本问题是,我必须将二进制文件与大量库文件一起交付。但感谢您告诉我,我会重新考虑使用二进制文件。(我以前使用过AppImage,但对于我的工作来说,它被证明非常混乱。) - Aziuth
@eyllanesc 我已经做了,就在下面的第二个框,但还是谢谢。 - Aziuth
1
xhost + 禁用 X 服务器的访问控制,因此任何人(即使是通过网络连接)都有权限访问它(并在您的屏幕上显示内容或捕获您的按键等)。 我学习时被告知永远不要做这样的事情。 - David Maze
@DavidMaze 在我阅读的一个答案中,有一条评论提到可能只需对特定用户执行xhost +si:localuser:$USER即可。我想这对我来说不相关,但在这个背景下还是想提一下。 - Aziuth
2个回答

5

您有多个错误互相遮盖。首先,确保您已安装正确的库。如果您的Docker镜像基于debian,则通常类似于以下行:

RUN apt-get update && \
    apt-get install -y libqt5gui5 && \
    rm -rf /var/lib/apt/lists/*
ENV QT_DEBUG_PLUGINS=1

请注意环境变量 QT_DEBUG_PLUGINS。这将使输出更有帮助,并引用任何缺失的库。在现在非常冗长的输出中,查找类似以下内容的信息:
无法加载库 /usr/local/lib/python3.9/site-packages/PySide2/Qt/plugins/platforms/libqxcb.so: (libxcb-icccm.so.4: 无法打开共享对象文件: 没有那个文件或目录)
粗体部分将是缺失的库文件;您可以通过发行版的软件包管理器找到它所在的软件包(例如,在debian上使用 dpkg -S libxcb-iccm.so.4)。
接下来,像这样启动Docker(可以一行完成,为了清楚起见而分开)。
docker run \
  -e "DISPLAY=$DISPLAY" \
  -v "$HOME/.Xauthority:/root/.Xauthority:ro" \
  --network host \
   YOUR_APP_HERE

请确保将/root替换为客户用户的主目录。

高级图形(例如游戏、3D建模等)可能还需要使用 -v /dev:/dev 挂载 /dev。请注意,这样将使客户用户具有对硬盘的 root 权限,因此您可能希望以更细粒度的方式复制/重新创建设备。


1

在主机系统上允许来自Docker的X连接xhost +local:root,然后启动您的容器。

docker run -it \
   -e DISPLAY=$DISPLAY \
   -v /tmp/.X11-unix:/tmp/.X11-unix \
   --name my_app \
   --rm \
   <your_image>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接