Skip to main content

A Journey into Podman: Notes on My First Adventure

For the last few days, I've been experimenting with Podman. My goal was to get a feel for the setup, create a minimal yet scalable environment for a few containers, and identify potential problems early on.

Here are my notes from this experience.

Quadlet

Quadlet allows you to define containers, networks and more using a syntax similar to systemd. This includes helpful features like drop-in overrides and templates.

The framework is tightly integrated with systemd, and Quadlet actually generates real systemd units. This means I can directly write systemd options in my Quadlet files.

One of the biggest benefits I've found is how easy Quadlet makes it to set up socket activation. This allows me to place some containers in an internal network or even without a network at all.

Hardening Defaults

Let's say I have a group of Systemd and Quadlet units, all named in the format of xyz-*. My goal is to define some secure, hardened default values for these units that can still be overridden by individual units.

For example, I want to change the default for ProtectSystem= from false to true.

Simply creating a xyz-.service.d/00-override.conf doesn't work, because an individual unit cannot override this setting. While I could create a xyz-foo.service.d/10-override.conf for each specific service, this would split the definition of xyz-foo into two separate files, which isn't ideal.

To solve this, I created a script that moves the main xyz-foo.service file to xyz-foo.service.d/10-override.conf and creates a nearly empty xyz-foo.service as a placeholder. This facilitates the process of setting and overriding defaults.

gVisor

Setting up gVisor's runsc was straightforward, and I haven't encountered any compatibility issues so far.

Unfortunately, the version of gVisor in the Debian repositories is quite old, and Debian is unable to provide prompt security updates for it. This meant I had to add the official gVisor apt repository. It's not the ideal solution, but it works.

Credentials

Systemd-Credentials is a very handy tool for managing sensitive information and can be used directly in Quadlet files.

However, I ran into an issue when using it with containers that have --userns=auto. Because Podman still runs as root, the credentials are only readable by the root user and not by the containers.

Podman offers its own solution for this called podman-secret. This feature allows you to either have Podman store the secrets or use drivers to connect to your own storage solution.

I prefer to keep all my secrets in a dedicated directory. To accommodate this, I wrote a simple script that registers a file as a Podman secret:

podman secret create \
  --driver=shell \
  --driver-opts=list="echo $1" \
  --driver-opts=lookup="cat $2" \
  --driver-opts=store=/bin/true \
  --driver-opts=delete=/bin/true \
  --replace=true \
  "$1" - <<<SECRET

For any container that needs access to secrets, I simply call this script in ExecStartPre=.

Networking

My plan is to run a few groups of containers with the following requirements:

  • Containers within the same group can communicate with each other, but containers from different groups cannot.
  • I want to avoid manually managing IP addresses for each group or container.
  • It should be easy to write firewall rules to intercept container traffic.

I explored a few options to achieve this:

  1. Plain Bridges: The simplest approach is to create a default bridge for each container group, which is the default behavior in Podman. Everything works out of the box, and I don't need to explicitly specify IP addresses. However, writing firewall rules is tricky because the IP addresses and bridge names are not predetermined. To make this work, I would need to carefully define an IP range and/or bridge name for each bridge.

  2. Single Unmanaged Bridge: Another option is to create a bridge using systemd-networkd and then, for each container group, create a Podman bridge network using the existing bridge with VLANs and/or isolation. This didn't work well. Since the bridge is unmanaged, I would need to manually set up DHCP, DNS, and the firewall. My attempts to simply set up a DHCP server on the bridge were unsuccessful. See also 12

  3. VRF: I tried creating a VRF with systemd-networkd and then creating a Podman bridge network for each container group, specifying the VRF. This was a promising and straightforward solution that met most of my requirements, except for one critical issue: DNS server doesn't work. While I was able to force aardvark-dns to use the VRF by using a wrapper script (exec ip vrf exec MY-VRF aardvark-dns "$@"), this solution felt too fragile for long-term use.

  4. Bridge + veth + macvlan: This more complex setup involves creating a bridge as in the second option, then a veth pair for each container group, and finally using that to create a Podman macvlan network. Theoretically, this should work, but it offers no significant advantages over the VRF option and is more complicated to configure. It's also worth noting that the DNS server is not supported in macvlan mode.

In the end, I decided to go with option 1. It's simple, and it works. I might switch to option 3 when the built-in DNS server supports VRF, or when I don't need a DNS server.

Final Thoughts

So far, the combination of Podman, Quadlet, and gVisor has been a positive experience. Not everything has worked perfectly, but I'm quite happy with the setup. If things continue to go well, I might be able to migrate my docker-compose setup in the near future.

Comments

Popular posts from this blog

Determine Perspective Lines With Off-page Vanishing Point

In perspective drawing, a vanishing point represents a group of parallel lines, in other words, a direction. For any point on the paper, if we want a line towards the same direction (in the 3d space), we simply draw a line through it and the vanishing point. But sometimes the vanishing point is too far away, such that it is outside the paper/canvas. In this example, we have a point P and two perspective lines L1 and L2. The vanishing point VP is naturally the intersection of L1 and L2. The task is to draw a line through P and VP, without having VP on the paper. I am aware of a few traditional solutions: 1. Use extra pieces of paper such that we can extend L1 and L2 until we see VP. 2. Draw everything in a smaller scale, such that we can see both P and VP on the paper. Draw the line and scale everything back. 3. Draw a perspective grid using the Brewer Method. #1 and #2 might be quite practical. #3 may not guarantee a solution, unless we can measure distances/p...

Qubes OS: First Impressions

A few days ago, while browsing security topics online, Qubes OS surfaced—whether via YouTube recommendations or search results, I can't recall precisely. Intrigued by its unique approach to security through compartmentalization, I delved into the documentation and watched some demos. My interest was piqued enough that I felt compelled to install it and give it a try firsthand. My overall first impression of Qubes OS is highly positive. Had I discovered it earlier, I might have reconsidered starting my hardware password manager project. Conceptually, Qubes OS is not much different from running a bunch of virtual machines simultaneously. However, its brilliance lies in the seamless desktop integration and the well-designed template system, making it far more user-friendly than a manual VM setup. I was particularly impressed by the concept of disposable VMs for temporary tasks and the clear separation of critical functions like networking (sys-net) and USB handling (sys-usb) into the...

Exploring Immutable Distros and Declarative Management

My current server setup, based on Debian Stable and Docker, has served me reliably for years. It's stable, familiar, and gets the job done. However, an intriguing article I revisited recently about Fedora CoreOS, rpm-ostree, and OSTree native containers sparked my curiosity and sent me down a rabbit hole exploring alternative approaches to system management. Could there be a better way? Core Goals & Requirements Before diving into new technologies, I wanted to define what "better" means for my use case: The base operating system must update automatically and reliably. Hosted services (applications) should be updatable either automatically or manually, depending on the service. Configuration and data files need to be easy to modify, and crucially, automatically tracked and backed up. Current Setup: Debian Stable + Docker My current infrastructure consists of several servers, all running Debian Stable. System Updates are andled automatically via unattended-upgrades. Se...