Share X server across multiple containers

I have a MultiContainer application where both containers need to display windows.

Container 1 [electron-app] starts with startx /usr/app/reflx-os :0
Container 2 [python-server] starts with python3 /usr/app/server.py and needs to display an OpenCV window.

[electron-app] displays properly. However, when [python-server] tries to open the OpenCV window it throws this error:
Gtk: cannot open display: 0

The issue is that the X server is running on the [electron-app]. So how can I get my [python-server] to use the X server from the other container?

It seems like sharing the hosts X server via unix socket is simple:

However, in this case, the host machine isn’t hosting the X server. The [electron-app] container is.

Follow-up:

I attempted some binding workarounds without success.

Attempt 1: I tried creating a shared named volume x-unix:/tmp/.X11-unix

Attempt 2: in my [electron-app] Dockerfile I ran mount --bind /tmp/.X11-unix /data/.X11-unix and in my [python-server] Dockerfile I ran mount --bind /data/.X11-unix /tmp/.X11-unix

In both cases, the X0 socket DOES show up in the [python-server] in /tmp/.X11-unix/X0 but does not seem to function as expected. I tried setting DISPLAY to everything from :0 to :0.0 to unix:0 to localhost:0 to 127.0.0.1:0, etc.

Perhaps a permissions issue?

Hi, it could be a permission issue indeed if the container can see the resource but can’t make use of it.
What do you mean with “does not seem to function as expected”? Do you see any error(s) in the logs? What is the expected behaviour and how does it behave instead?
Is it possible to have a look at the Dockerfile.templates and docker-compose.yml of your application?

@thundron https://github.com/JeffJassky/balena-share-x-across-containers

What I meant by “does not seem to function as expected” I mean it I get the same Gtk cannot open display: error no matter what.

The only X related log file I can find on [electron-app] is /var/log/Xorg.2.log which unfortunately has nothing even relevant to displays or display errors in it. I cannot find any X related log files on the [python-server]

Another possibly relevant reference: https://www.jujens.eu/posts/en/2017/Feb/15/docker-unix-socket/

Thanks for the resources as well, we’ll check it out and reach back to you.
In the meantime you could have a look at our x11-window-manager project to check if there’s something different you can fiddle with

1 Like

It seems the containers configs are mostly correct, but you’ll need to also add UDEV=1 (I think to both containers, but might be wrong) to be able to use the unix socket.
Tell us how it goes after adding it!

1 Like

Tried this. Still the same issue: Gtk-WARNING **: cannot open display: localhost:0.

Any other thoughts?

Seperate note: Binding the x-unix:/tmp/.X11-unix:rw volume persists the socket files (X0, X1, etc) across pushes of new builds. Each time the container starts X adds/increments a new display. Eventually /tmp/.X11-unix is filled with X0, X1, X2, X3… etc.

It’s not really a problem - just an annoyance. I added rm -r /tmp/.X11-unix to my start.sh file to manually remove defunct sockets.

Hi, I’ve looked through this thread and its not entirely clear to me what the intended result is, do you want your application to display the output of the python-server and electron-app side by side? Or are they displayed on different monitors?

The intent is separate (but overlaying) windows on a single display. The electron-app is a web interface for controlling camera settings. The python-server is an OpenCV window that displays the live camera preview. The intent is for the camera preview to be laying over the center of the web interface.

If I run the python server in the background of the [electron-app] the effect works as intended - but I wanted to containerize the [python-server] for the benefits of supervising, improved logging and code separation.

Also updated https://github.com/JeffJassky/balena-share-x-across-containers with latest configs.

Update: disabling access control on the main X process using the -ac flag allows the window to show up properly.

From the X manpage:

-ac disables host-based access control mechanisms. Enables access by any host, and permits any host to modify the access control list. Use with extreme caution. This option exists primarily for running test suites remotely.

Unfortunately it doesn’t look like THE solution. Though at least we’ve narrowed it down to an access/permissions issue.

Hi jassky, if it is working with ‘-ac’ but not without then it seems like a permissions issue. You can use the xhost command to inspect/update the access controls. I think you would want to do something like xhost +python-server from the electron-app container, but you might have to specific the python-server IP.

As another idea here… How about exposing the opencv output as a stream endpoint to the electron container and having your frontend display that however it likes? That would alleviate the need to expose the X server and cut this dependency between your containers.

@wrboyce I think you would want to do something like xhost +python-server from the electron-app container, but you might have to specific the python-server IP.

Wouldn’t the IP address be the same for all containers?

@robertgzr How about exposing the opencv output as a stream endpoint to the electron container and having your frontend display that however it likes?

I like the level of familiarity I would have with presenting a video stream in a web view - however, frame rate and latency performance and image quality are pretty critical. I assume streaming frames from OpenCV right into X would be faster and look better than streaming over a TCP socket or something. Though I haven’t tested thoroughly. If you happen to know of any good solutions for that I’m all ears.

Wouldn’t the IP address be the same for all containers?

Docker has an internal network it uses, on which each container has its own (unique) IP address. In reality, you would probably be okay to whitelist 172.16.0.0/20.

1 Like

I like the level of familiarity I would have with presenting a video stream in a web view - however, frame rate and latency performance and image quality are pretty critical. I assume streaming frames from OpenCV right into X would be faster and look better than streaming over a TCP socket or something. Though I haven’t tested thoroughly.

If you happen to know of any good solutions for that I’m all ears.

I’m not really an expert on this… but looking around a bit looks like this is not uncharted territory and opencv > gstreamer would be the way to go:

1 Like