Skip to main content

Fedora Silverblue and Docker Compose

·5 mins

I’ve been playing with Fedora Silverblue on and off for the past few months, switching between it and Fedora Workstation on my current laptop.

At first glance there isn’t much of a difference between the two, both show a GNOME desktop environment that’s almost identical. The main difference is that Fedora Silverblue is a variant of Fedora that uses an immutable base system.

The TL;DR for Silverblue is that you can’t install packages as you would in Workstation. Instead you can install applications via Flatpak, from Fedora’s repository or any other like Flathub, or you can create a Toolbox, a Fedora based container where you can install packages just like in Workstation. These containers are run using Podman in the base system.

What if I need Docker? #

In most cases, I’ve found Podman to be a drop in replacement for Docker. The only real issue I ran into was when I wanted to use Docker Compose for local development. When a company’s projects already have a workflow using Docker Compose, rewriting pieces of it to work with Podman isn’t the best option.

I researched various ways to solve this issue, but the best solution I found was to use docker-compose within a toolbox in combination with podman-remote which can talk to the host’s podman engine.

How to get Docker Compose working #

For this walkthrough there are steps that are specific to the host and the toolbox container. Steps specifically for one or the other will be labeled with “HOST:” or “TOOLBOX:” to keep things clear.

If you don’t already have a toolbox container ready you can easily create one with the following:

# using "dev" below as the container name
toolbox create dev

HOST: Start and Enable the Podman Socket #

In order for podman-remote to be able to connect to the host’s podman engine we need to start the podman socket to allow communication between the host and toolbox container.

We can do this through systemd services, starting and enabling the podman socket with the --user argument as they don’t need root access:

systemctl --user enable podman.socket
systemctl --user start podman.socket

Afterwards take note of the socket used in the output of:

systemctl --user status podman.socket

In my case the socket used is unix:///run/user/1000/podman/podman.sock

Add Docker host environment variable to .bashrc or shell configs #

docker-compose will require a DOCKER_HOST environment variable set in order for it to use the podman socket we just set. For example, this line can be added to your ~/.bashrc file if using a bash shell:

export DOCKER_HOST=unix:///run/user/1000/podman/podman.sock

TOOLBOX: Install podman/docker dependencies #

Now we’re ready to work inside our toolbox! Enter your toolbox and update existing packages if you haven’t already:

# assuming "dev" is the toolbox name
toolbox enter dev
sudo dnf update

Next we’ll want to install podman-remote and docker-compose. podman-remote is basically the same as installing podman and always assuming we want to add the --remote argument. Using podman-remote here just makes this easier. Then go to /usr/bin/ and add symlinks for podman and docker pointing to podman-remote

sudo dnf install -y podman-remote docker-compose
sudo ln -s /usr/bin/podman-remote /usr/bin/podman
sudo ln -s /usr/bin/podman-remote /usr/bin/docker

SELinux issues #

If you have Permission Denied errors when running docker-compose now, it’s likely due to SELinux. To bypass SELinux for containers add these lines to your ~/.config/containers/containers.conf file (creating it if needed):

[containers]
label = false

Optional: For best Docker compatibility #

If you were previously used to Docker, you likely have Dockerfiles that reference images with unqualified names.

For example, when using Docker you could pull the latest Ubuntu image from Docker Hub with just docker pull ubuntu:latest. When we use podman it doesn’t assume that we want to use Docker Hub so it may ask what repository we want to use when looking for the Ubuntu image. With Podman we need to use the fully qualified image name of docker.io/library/ubuntu:latest.

We can change this to be more like Docker (useful if working with scripts that assume docker usage) by creating a file at ~/.config/containers/registries.conf with the following content:

unqualified-search-registries = ["docker.io"]

Extra: Getting VS Code connected to toolbox #

If using VS Code, I’ve found getting it connected to a toolbox container to be a bit of a pain. You can use owtaylor’s Toolbox Visual Studio Code integration tool, but in the end I preferred to simply install VS Code within the toolbox container so that no extra connection is necessary.

Install VS Code inside toolbox #

In our toolbox we can simply install VS Code according to Microsoft’s existing Fedora Installation Instructions:

sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc
sudo sh -c 'echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com/yumrepos/vscode\nenabled=1\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/yum.repos.d/vscode.repo'
dnf check-update
sudo dnf install code

Create desktop entry from toolbox #

Now we can start VS Code from the command line within the toolbox just fine, but what if we want to see the application in our launcher?

We’ll first need to copy the code.desktop file from the toolbox container’s /usr/share/applications to ~/.local/share/applications. Then we’ll need to edit the new copy, prepending each Exec command with toolbox run --container dev (again assuming your toolbox name is “dev” here).

We should now have a desktop entry appearing in our launcher, though the VS Code icon is missing. To fix this, we’ll need to copy the icon file located in our toolbox at /usr/share/pixmaps/com.visualstudio.code.png to ~/.icons