After my previous post, on installing Docker, I needed to setup my first container. I choose to set-up a container for Firefox, first, as that required me to get a graphical application that also needed sound working.

Dockerfile

First thing I did was to create a simple Dockerfile which installed Firefox and set the DISPLAY environment varaibel:

FROM debian:latest
RUN apt-get update
RUN apt-get install -qq firefox-esr

RUN useradd -m -u 1000 developer
USER developer

ENV DISPLAY :0
CMD firefox --no-remote

The --no-remote is important because, although running in a container, Firefox will "see" a process already running on the same X server and simply tell it to open a new window instead of running the version of Firefox installed inside the container.

This same behaviour happens when running Firefox from a remote host with X-forwarding.

Builiding the container

Once the Dockerfile exists, this is a simple case of using docker build with the directory containing the Dockerfile (e.g. if the Dockerfile is at ~/docker/firefox/Dockerfile). The -t firefox tags the image so it can be easily referred to when comming to run it:

sudo docker build -t firefox $HOME/docker/firefox

Running it

This is based on a Stack Overflow answer:

XSOCK=/tmp/.X11-unix
XAUTH=/tmp/.docker.xauth
touch $XAUTH
xauth nlist :0 | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -
sudo docker run -ti --rm \
	-v $XSOCK:$XSOCK \
	-v $XAUTH:$XAUTH \
	-e XAUTHORITY=$XAUTH \
	-v ~/.config/pulse:/home/devloper/.config/pulse:ro \
	firefox

Getting sound

So this is all great, but navigate to YouTube and click a video and not only is there no sound, but the tab crashes completely comming up with an error message. Getting sound requires a few more tweaks.

Firstly the dockerfile needs modifying to install pulseaudio too:

FROM debian:latest
RUN apt-get update
RUN apt-get install -qq firefox-esr pulseaudio

RUN useradd -m -u 1000 developer
USER developer

ENV DISPLAY :0
CMD firefox --no-remote

Then the run script needs to expose a few more host paths to the Firefox container:

XSOCK=/tmp/.X11-unix
XAUTH=/tmp/.docker.xauth
touch $XAUTH
xauth nlist :0 | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -
sudo docker run -ti --rm \
	-v $XSOCK:$XSOCK \
	-v $XAUTH:$XAUTH \
	-e XAUTHORITY=$XAUTH \
	-v /dev/shm:/dev/shm \
	-v /etc/machine-id:/etc/machine-id:ro \
	-v /run/user/1000/pulse:/run/user/1000/pulse:ro \
	-v /var/lib/dbus:/var/lib/dbus:ro \
	-v ~/.config/pulse:/home/devloper/.config/pulse:ro \
	firefox

And now you will have sound too.

Closing thoughts

The fact that Firefox can connect to its existing instance and trigger it to open a new window when it only has X11-protocol access to the X server causes me to wonder just how isolated the container is and if behaviour of applications within will be reproducable in different circumstances (e.g. different desktop environments, different applications open at the time etc. outside the container). Network transparancy is a key feature of the X11 protocol (which is how and why X-forwarding over ssh works and is so reliable) but for application testing using Docker it seems like it could be a liability to use existing host's X server.

I'm wondering if running VNC or something like X2Go would provide better isolation for reproducable testing.