0. Introduction
Sometimes it could be useful to run some multimedia applications inside a container. Personally, I stick with LXC and there are plenty of information about how to pass-through X11, PulseAudio and even Nvidia GPU in the Net. However, there are a few information about how to do that in a Docker container. This small post is merely a reminder for myself but also I hope that it could be useful for someone else. For a ready to use solution one can refer to this GitHub repo.
1. A bit of theory
1.0 PulseAudio
According to the pulseaudio(1), the PulseAudio client libraries check for a set of environment variables, such as $PULSE_SOURCE
, $PULSE_SERVER
, etc, and these environment variables change the behaviour of the clients. One particular environment variable is interested to us, this is $PULSE_SERVER
. The variable contains a string which denotes a list of server addresses, where each entry is separated by a whitespace, which are tried in turn. A server address may contain a prefix with an optional address type specifier, such as unix:
, tcp:
, etc. For more information please refer to pulseaudio(1)
. If PulseAudio is running per-user, as in my case, then we can bind-mount the PulseAudio AF_UNIX socket file inside our Docker container. The only issue here is that we need the same UID/GID in the Docker container as in the host system to meet access control rules. After that we can set, in the ~/.bashrc
e.g, and use $PULSE_SERVER
inside the Docker container, or create a ~/.config/pulse/client.conf
configuration file, it is a matter of choice.
1.1 X11
Xorg supports different connection types: TCP, UNIX-domain socket, etc. In this post we will stick with UNIX-domain socket as it is the most common case. Basically, we need to bind-mount the socket into the Docker container. Xserver(1) states that the UNIX-domain socket file for the $DISPLAY :0
can be found in /tmp/.X11-unix/X0
. X11 has its own display access control. For UNIX-domain socket we can use MIT-MAGIC-COOKIE-1
. When a client is using this method it sends a 128-bit “cookie” during connection establishment. The client’s copy of the cookie is stored in ~/.Xauthority
file. We can use the same cookie, as in the host, in the Docker container. To register the cookie we will use xauth(1) utility.
1.2 GPU
For Intel it is quite straightforward to pass-through a GPU into the Docker container. As far as I understand the essential part which should be exposed to the container is Direct Rendering Manager (DRM). To do that we need to simply bind-mount /dev/dri
into the container.
WARNING: one should remember about security implications as part of the host system is exposed to the container.
2. A bit of practice
Let’s start by creating the Docker file. For example, here I will use Arch btw Linux as an example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
FROM archlinux AS x11-test
# Install necessary packages
RUN pacman -Sy
RUN pacman -S --noconfirm xorg-xauth firefox pulseaudio
# Create a group and a user with the same UID/GID as in the host for
# PulseAudio to ease its setup. For example UID=1000, GID=1001
RUN groupadd -g 1001 foobar
RUN useradd -m -u 1000 -g foobar -G audio,video,lp,users foobar
# Define environment variables for X11 and PulseAudio
ENV DISPLAY=:0
ENV PULSE_SERVER=unix:/tmp/pulse/native
# Define an argument. This needs to be passed in --build-arg
ARG cookie
# Switch to the user and make necessary directories
USER 1000:1001
RUN mkdir /tmp/.X11-unix
RUN mkdir /tmp/pulse
# Entry script
RUN : > ~/run.sh
RUN chmod +x ~/run.sh
RUN echo "#!/bin/sh" >> ~/run.sh
RUN echo "xauth add :0 MIT-MAGIC-COOKIE-1 $cookie" >> ~/run.sh
RUN echo "firefox" >> ~/run.sh
# Run entry script
CMD ~/run.sh
The next step is to run the container. We will write a script for that:
1
2
3
4
5
#!/bin/sh
docker run -it -v /tmp/.X11-unix:/tmp/.X11-unix \
-v /run/user/1000/pulse/native:/tmp/pulse/native \
-v /dev/dri:/dev/dri \
x11-test