I assume that
- host system is Linux
- windowing api is X11 .
And I'll use podman but you can replicate by replacing podman with docker in every command, I just like podman and never used docker.
My System: Opensuse Tumbleweed with kde [Intel Optimus laptop]
Solution
Applications need to ask Xserver to display their GUI elements. And there's an authorization system designed for security.
This authorization system is called xauth. xauth usually stores session cookies inside /home/username/.Xauthority file(usually but not always).
check for the current cookies in use
xauth list
output will look like this,
localhost.localdomain/unix:0 MIT-MAGIC-COOKIE-1 99aaccf2d83177ddf581e2989ebbcea1
#ffff##:0 MIT-MAGIC-COOKIE-1 99aaccf2d83177ddf581e2989ebbcea1
in case the Xauthority is not located at the usual place, check which authority file is in use
xauth
output will look something like this is if standard file is not in use,
Using authority file /run/user/1000/xauth_Abcde
We need to supply these two things to our container,
- MIT-MAGIC-COOKIE-1 - for now just think of this as a protocol or identifier. This is constant for every session.
- 99aaccf2d83177ddf581e2989ebbcea1 - this 32 letter key is the session key or whatever fancy name you want to give it. Key is unique for each session.
Now to resolve issues related to display we need to do these five things,
1. Create a .Xauthority file if not present already inside container, as in our example (debian)
2. Add our session key and protocol to the .Xauthority file we created
3. Pass DISPLAY environment variable to container
4. Mount host Xserver socket(usually located at /tmp/.X11-unix) to container
5. Set network to host(required for display rendering)
These 5 steps will fix all issues related to display.
CONFIGURATION - Example Scenario
Example to run firefox with GUI via container.
TO-DO
1. create a .Xauthority file
done inside Containerfile RUN touch .Xauthority
2. add our session key and protocol to the .Xauthority file we created
both passed as environment variables
protocol set in Containerfile ENV PROTOCOL=MIT-MAGIC-COOKIE-1
session key passed as argument to podman run
--env KEY=$(xauth list | sed '2,$d'| tr -d '\n' | tail -c 32) \
(can't pass inside the Containerfile as constant because it changes session to session)
and then added to .Xauthority via CMD xauth add ${HOST}:0 $PROTOCOL $KEY
from Containerfile
3. pass DISPLAY environment variable to the container
passed as argument to podman run
--env DISPLAY \
4. mount Xserver socket(usually located at /tmp/.X11-unix) to container
passed as argument to podman run
--mount type=bind,source=/tmp/.X11-unix,target=/tmp/.X11-unix,readonly \
5. set network type to host
configured while building the image podman build --network=host --tag guitest .
Containerfile
FROM debian:latest
ARG DEBIAN_FRONTEND=noninteractive
RUN apt update && apt upgrade
RUN apt install --no-install-recommends --yes firefox-esr pipewire pipewire-alsa pipewire-pulse ffmpeg xauth
ENV PROTOCOL=MIT-MAGIC-COOKIE-1
ENV HOME /home/def
ENV USER def
RUN useradd --create-home --home-dir ${HOME} -G audio,video ${USER} && chown -R ${USER}:${USER} ${HOME}
WORKDIR ${HOME}
USER ${USER}
RUN touch .Xauthority
CMD xauth add ${HOST}:0 $PROTOCOL $KEY && firefox
Build Command
podman build --network=host --tag guitest .
Run Container using the image we built
podman run -it --rm --name guiapp \
--env DISPLAY \
--env KEY=$(xauth list | sed '2,$d'| tr -d '\n' | tail -c 32) \
--mount type=bind,source=/tmp/.X11-unix,target=/tmp/.X11-unix,readonly \
guitest
BINGO ! firefox GUI in front of your eyes.
Disclaimer audio will not work in this example, Some extra steps needed to make audio work.