12

So, I have a C++ GUI based on Qt5 which I want to run from inside a Docker container.

When I try to start it with

docker run --rm -it my_image

this results in the error output

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.

So I searched for how to do this. I found GUI Qt Application in a docker container, and based on that called it with

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

which resulted in the same error.

Then I found Can you run GUI applications in a Docker container?.
The accepted answer in there seems to be specific to certain applications such as Firefox?
Scrolling further down I got a solution that tells me to set X11UseLocalhost no in sshd_config and then call it like

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

this produces a slight variation of the error above:

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.

Following another answer, I added ENV DISPLAY :0 to my Dockerfile and called it with

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

This time, the first line of my error was qt.qpa.xcb: could not connect to display :0.

Then I tried another answer, added

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

to my Dockerfile and called docker run -ti --rm -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix my_image, again same error.

I also tried several of the ways described in http://wiki.ros.org/docker/Tutorials/GUI, same error.


Am I doing something wrong? Note that I'm working on a remote machine via SSH, with X11 forwarding turned on of course (and the application works just fine outside of Docker). Also note that what I write is a client-server-application, and the server part which needs no GUI elements but shares most of the source code works just fine from it's container.

I hope for a solution that doesn't require me to change the system as the reason I use Docker in the first place is for users of my application to get it running without much hassle.

Aziuth
  • 3,652
  • 3
  • 18
  • 36
  • 1
    You can't run GUI applications in Docker "without much hassle"; you need administrator-level permission and to manually configure several details of the X Window System connection setup. A native binary will be much easier for your end users. – David Maze Jan 09 '21 at 14:46
  • try execute: `xhost +` – eyllanesc Jan 09 '21 at 15:02
  • @DavidMaze Do you know a good alternative? The basic thing is, I'd had to deliver the binary with a ton of library files. But thanks for telling me, I'll reconsider using binaries. (I used AppImage in the past, but that one proved to be quite messy for what I do.) – Aziuth Jan 09 '21 at 20:01
  • @eyllanesc Did that already, second box from below, but thanks. – Aziuth Jan 09 '21 at 20:01
  • 1
    @eyllanesc `xhost +` disables access control for the X server, so anyone who can connect to it (even over the network) has permission to access it (and display things on your screen or capture your keystrokes or...). I learned this as one of things to _never_ do. – David Maze Jan 09 '21 at 20:04
  • @DavidMaze In one of the answers I read through a comment mentions that it might suffice to do this for a specific user with `xhost +si:localuser:$USER`. Not relevant for me, I guess, but wanted to mention it in this context. – Aziuth Jan 09 '21 at 20:07

2 Answers2

4

You have multiple errors that are covering each other. First of all, make sure you have the correct libraries installed. If your docker image is debian-based, it usually looks like a line

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

Note the environment variable QT_DEBUG_PLUGINS. This will make the output much more helpful and cite any missing libraries. In the now very verbose output, look for something like this:

Cannot load library /usr/local/lib/python3.9/site-packages/PySide2/Qt/plugins/platforms/libqxcb.so: (libxcb-icccm.so.4: cannot open shared object file: No such file or directory)

The bolded part will be the missing library file; you can find the package it's in with your distribution's package manager (e.g. dpkg -S libxcb-iccm.so.4 on debian).

Next, start docker like this (can be one line, separated for clarity):

docker run \
  -e "DISPLAY=$DISPLAY" \
  -v "$HOME/.Xauthority:/root/.Xauthority:ro" \
  --network host \
   YOUR_APP_HERE

Make sure to replace /root with the guest user's HOME directory.

Advanced graphics (e.g. games, 3D modelling etc.) may also require mounting of /dev with -v /dev:/dev. Note that this will give the guest root access to your hard disks though, so you may want to copy/recreate the devices in a more fine-grained way.

phihag
  • 278,196
  • 72
  • 453
  • 469
1

On host system allow X connection from docker xhost +local:root And start your container

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