Nowadays installing apps inside a container is very common. It’s much easier to build your app just once for a specific runtime and not for every possible distro and distro’s version.
Back-end developers usually use docker while front-end developers use other package formats such as Flatpak or AppImage (or snap, unfortunately).
The problems with the GUI package formats are:
- They store the application’s cache on the local machine which may conflict with the same app that was installed with other package manager (apt, yum, pacman etc).
- They can run only one instance for each app.
- Make the OS more messy.
- May be a security flaw.
Docker won’t write the app’s cache on your machine, but inside the container itself so:
- It won’t conflict with the app you installed with your package manager
- It will keep your system clean (unless manually mounted, which you can fix if mounted to a directory that isn’t the default direcroty of the application’s cache).
- This is more secure.
The problem with docker is that it’s only compatible with back-end applications. This is why x11docker was made.
x11docker
x11docker is a docker compatible cli for running GUI apps with docker. It’s working perfectly (if you wrote the Dockerfile properly). The only reason not to use it is that you have to install another app, which means that you make your computer:
- Dirtier.
- Slightly performance impact on your computer.
- More complex.
See more about x11docker here.
This is why Iv’e made a research about running GUI apps using docker without installing x11docker.
GUI apps with docker on Nvidia GPUs
In the past, using Nvidia GPU inside a container was a headache, but today it’s very easy.
Pre-Requisites
- Docker (or any other docker-compatible cli for containerd).
- Up to date Nvidia driver that’s compatible with your GPU model. It’s necessary for connecting the GPU to the container from the hardware side.
Note: Ubuntu and Ubuntu based OSes instead can simply run:
ubuntu-drivers autoinstall - Package nvidia-docker2 (includes Nvdia container toolkit). See here for installation guide. This is necessary for connecting the GPU to the container from the runtime side.
The advantages of using Nvidia Container Toolkit
From above it’s look like using Nvidia Container Toolkit have the same problem of using x11docker, each of them require installing some deps on your system. What is exactly the difference?
- Nvidia Container Toolkit and nvidia-docker2 are widely used by other programs that require the use of GPU processing, such as cryptomining, AI training, encryption, decryption, Data Dcience and much more. There is high chance that it’s already installed on your system.
- x11docker can’t be updated using your main package manager, so you may forget to update it and it will stay outdated for a long time.
Now Let’s start
The base Dockerfile you will want to use is:
FROM ubuntu:20.04
ARG USERNAME=myuser
ARG USER_UID=1000
ARG USER_GID=$USER_UID
ENV NVIDIA_VISIBLE_DEVICES all
ENV NVIDIA_DRIVER_CAPABILITIES all
ENV XDG_RUNTIME_DIR /run/user/$USER_UID
ENV DEBIAN_FRONTEND=noninteractive
RUN groupadd --gid $USER_GID $USERNAME \
&& useradd --uid $USER_UID --gid $USER_GID -s /bin/bash -m $USERNAME \
&& mkdir -p /run/user/$USER_UID \
&& chown -R $USERNAME:$USERNAME $XDG_RUNTIME_DIR \
#Installing process
USER $USERNAME
WORKDIR /home/$USERNAME
- The ARGs are for creating the user. Using a non-root user is much more secure and for testing you can give it sudo permissions (just make sure to remove the permissions in production).
- The NVIDIA_VISIBLE_DEVICES ENV is for GPUs detection from the container side. See more here.
- The NVIDIA_DRIVER_CAPABILITIES ENV is for specifying the allowed GPU capatbilities for the container. See more here.
- The XDG_RUNTIME_DIR ENV is for the default XDG directory for the non-root user.
- The DEBIAN_FRONTEND ENV is to skip interactive questions while installing the deps. Apps that ‘require’ user input (such as tzdata) are very common in GUI apps’ metapackage.
To start the app you will need two steps:
- Create a silent container. Using entrypoints or CMDs in the Dockerfile with GUI apps in docker is not a good idea, because there are lots of GUI app that after the installation will get only the installer (or updater, you call it). In such case it will install the app, but will crash right after and wont get up anymore fore some reasons (even if you will start the container again).
- Start your GUI app using docker exec with the app’s specific command.
If It didn’t work, make sure to use the full path. If it didn’t too, try to connect to the container’s shell using docker exec -it containerName bash and to run the app from there.
The container creation should be something like that:
docker run -dt \
--gpus all \
--device /dev/dri \
-e DISPLAY=$DISPLAY \
-v /tmp/.X11-unix:/tmp/.X11-unix \
--name containerName \
imageName
- The dt flag is for running the container as a daemon.
- The gpus flag is for conencting all the GPUs to the container. If you want to connect specific GPU, see more here.
WARNINGS!!!
— Do Not install nvidia-container-runtime as written in the docker documention. This is a deprecated version and now it’s called nvidia-container-toolkit. The newer version is already included in nvidia-docker2.
— Make sure you won’t accidently install nvidia-docker, this version is deprecated. Make sure you install nvidia-docker2.
- The device flag is for connecting the container to the Direct Rendering Infrastructure (DRI) framework for rendering the app properly on the screen.
- The DISPLAY env is for telling the container the ‘address’ of the screen the app will render on it.
- The volume of /tmp/.X11-unix is for mounting the container rendering system to yours, so it will be connected to the same screen as your OS.
- The name flag is optional. It’s for naming the container for the docker exec later. If you won’t name it, docker will name it randomly. You can find the container name using docker ps.
At the end it should look something like that:
Minecraft example:
docker run -dt --gpus all --device /dev/dri -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix --name mc-client 1nachi:minecraft:1.0.0
Then run:
docker exec mc-client minecraft-launcher
Tor Browser example:
docker run -dt --gpus all --device /dev/dri -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix --name torbrowser 1nachi:tor:1.0.0
I broght the Tor example because it requires using the full path and won’t work using typical docker exec, jsut like that:
docker exec tor /usr/bin/torbrowser-launcher
This was tested with Minecraft and Tor Browser on Ubuntu 22.04 using wayland and Nvidia’s GeForce 920M GPU and Nvidia driver 470.141.03.
NOTICE
For X11 (or any other X Server) you may need to run
xhost +
This will give everyone access to render using your X Server (Not very secure to say the least). To limit the access to your needs look at the xhost man page or just run man xhost.
For wayland this is not necessary.
Conclusions
In this post we demonstrated how to run GUI apps without using x11docker, using more widely used tools such as the Nvidia container toolkit.