This question is inspired by Can you run GUI apps in a docker container?.
The basic idea is to run apps with audio and ui (vlc, firefox, skype, ...)
I was searching for docker containers using pulseaudio but all containers I found where using pulseaudio streaming over tcp. (security sandboxing of the applications)
In my case I would prefere playing audio from an app inside the container directly to my host pulseaudio. (without ssh tunneling and bloated docker images)
Pulseaudio because my qt app is using it ;)
Docker Desktop runs on your computer and manages your local containers. Development tools like Visual Studio and VS Code offer extensions that let you work with a local Docker Desktop service. You can create containerized apps, deploy apps to containers, and debug apps running on your containers.
Running a GUI program in Docker can be a useful technique when you're evaluating a new piece of software. You can install the software in a clean container, instead of having to pollute your host with new packages. This approach also helps you avoid any incompatibilities with other packages in your environment.
Application containerization is an OS-level virtualization method used to deploy and run distributed applications without launching an entire virtual machine (VM) for each app. Multiple isolated applications or services run on a single host and access the same OS kernel.
it took me some time until i found out what is needed. (Ubuntu)
we start with the docker run command docker run -ti --rm myContainer sh -c "echo run something"
ALSA:
we need /dev/snd
and some hardware access as it looks like. when we put this together we have
docker run -ti --rm \ -v /dev/snd:/dev/snd \ --lxc-conf='lxc.cgroup.devices.allow = c 116:* rwm' \ myContainer sh -c "echo run something"`
In new docker versions without lxc flags you shoud use this:
docker run -ti --rm \ -v /dev/snd:/dev/snd \ --privileged \ myContainer sh -c "echo run something"`
PULSEAUDIO:
update: it may be enought to mount the pulseaudio socket within the container using -v option. this depends on your version and prefered access method. see other answers for the socket method.
Here we need basically /dev/shm
, /etc/machine-id
and /run/user/$uid/pulse
. But that is not all (maybe because of Ubuntu and how they did it in the past). The envirorment variable XDG_RUNTIME_DIR
has to be the same in the host system and in your docker container. You may also need /var/lib/dbus
because some apps are accessing the machine id from here (may only containing a symbolic link to the 'real' machine id). And at least you may need the hidden home folder ~/.pulse
for some temp data (i am not sure about this).
docker run -ti --rm \ -v /dev/shm:/dev/shm \ -v /etc/machine-id:/etc/machine-id \ -v /run/user/$uid/pulse:/run/user/$uid/pulse \ -v /var/lib/dbus:/var/lib/dbus \ -v ~/.pulse:/home/$dockerUsername/.pulse \ myContainer sh -c "echo run something"
In new docker versions you might need to add --privileged
.
Of course you can combine both together and use it together with xServer
ui forwarding like here: https://stackoverflow.com/a/28971413/2835523
Just to mention:
dockerfile
uid=$(id -u)
to get the user id and gid with id -g
create user script:
mkdir -p /home/$dockerUsername && \ echo "$dockerUsername:x:${uid}:${gid}:$dockerUsername,,,:/home/$dockerUsername:/bin/bash" >> /etc/passwd && \ echo "$dockerUsername:x:${uid}:" >> /etc/group && \ mkdir /etc/sudoers.d && \ echo "$dockerUsername ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$dockerUsername && \ chmod 0440 /etc/sudoers.d/$dockerUsername && \ chown ${uid}:${gid} -R /home/$dockerUsername
Inspired by the links you've posted, I was able to create the following solution. It is as lightweight as I could get it. However, I'm not sure if it is (1) secure, and (2) entirely fits your use-case (as it still uses the network).
paprefs
on your host system, e.g. using sudo apt-get install paprefs
on an Ubuntu machine.sudo apt-get install -y pulseaudio
export "PULSE_SERVER=tcp:<host IP address>:<host Pulseaudio port>"
. For example, export "PULSE_SERVER=tcp:172.16.86.13:4713"
[2]. You can find out your IP address using ifconfig
and the Pulseaudio port using pax11publish
[1].PULSE_SERVER
: If it doesn't then you have to initialize it after each container start.Suggestions to make my approach even better would be greatly appreciated, since I'm currently working on a similar problem as the OP.
References:
[1] https://github.com/jlund/docker-chrome-pulseaudio
[2] https://github.com/jlund/docker-chrome-pulseaudio/blob/master/Dockerfile
UPDATE (and probably the better solution):
This also works using a Unix socket instead of a TCP socket:
-v /run/user/$UID/pulse/native:/path/to/pulseaudio/socket
export "PULSE_SERVER=unix:/path/to/pulseaudio/socket"
The /path/to/pulseaudio/socket
can be anything, for testing purposes I used /home/user/pulse
.
Maybe it will even work with the same path as on the host (taking care of the $UID part) as the default socket, this way the ultimate solution would be -v /run/user/$UID/pulse/native:/run/user/<UID in container>/pulse
; I haven't tested this however.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With