Podman #4 - Networking - Layer 2 Dragons
Finally, networking. I’ve been doing it for over 20 years, so let’s set some boundaries and enforce a few paradigms.
podman network create test
Yes, this creates a network just like in Docker. But I don’t want my containers talking to each other, and I definitely don’t want them talking to the internet.
The documentation I used to figure this out is here (again), but there are two key concepts that stood out: internal
and isolate
. And they can be combined!
Internal
Internal=true
This restricts external access for the network. In other words, containers won’t have a default gateway and can’t connect to the internet. This even improves startup time for some containers, like OpenSearch.
Isolate
Options=isolate=true
This option blocks traffic between networks that have it enabled. Networks with isolate=true
can’t talk to each other, but they can talk to networks without isolation.
Strict Isolation
It turns out:
--opt=isolate=strict
…is also a thing. I stumbled across it on Reddit or GitHub (not well documented). With strict
, the network can’t talk to anything unless that other network also has isolation enabled. Unlike true
, it won’t communicate with “normal” networks.
Perfect. This means if we combine internal
and isolate
, we can build a network where nothing leaks out. That will be the default setup from here on.
Examples
podman network create --internal internalNet
podman network create --opt=isolate=true isoTrueNet
podman network create --opt=isolate=strict isoStrictNet
podman network create --internal --opt=isolate=true intIsoTrueNet
podman network create --internal --opt=isolate=strict intIsoStrictNet
Now let’s run some containers and see if they can ping each other:
podman run --rm -it --network=isoStrictNet alpine sh
podman run --rm -it --network=intIsoTrueNet alpine sh
And yes — it behaves exactly as described.
Rootless Quadlet
Since we’re not using the CLI to deploy services, we need to define this network in a rootless Quadlet file:
nano ~/.config/containers/systemd/intisostrictnet.network
[Unit]
Description=Isolated internal network
[Network]
Driver=bridge
Internal=true
Options=isolate=strict
[Install]
WantedBy=default.target
Then generate the systemd file:
systemctl --user daemon-reload
You can check if it was created with:
ls /run/user/$UID/systemd/generator/
If it isn’t there, troubleshoot with:
/usr/lib/systemd/user-generators/podman-user-generator -dryrun
If all looks good, start the service:
systemctl --user start intisostrictnet-network.service
Now podman network ls
will show your shiny new network.
We can put a container on it to verify that we have no network connectivity:
podman run --rm -it --network=systemd-intisostrictnet alpine sh
That’s it for Podman #4 – Networking.
https://docs.podman.io/en/latest/markdown/podman-network-create.1.html
Podman #3 - Rootful vs Rootless Cheat Sheet
So far we’ve looked at running containers with Podman as root and as a regular user. The concepts are the same, but the commands and file locations differ. Here’s a quick cheat sheet to keep things straight.
Quadlet File Location
- Rootful:
/etc/containers/systemd/
- Rootless:
~/.config/containers/systemd/
systemctl Reload
- Rootful:
sudo systemctl daemon-reload
- Rootless:
systemctl --user daemon-reload
Service File Location
- Rootful:
/etc/containers/systemd/<name>.service
- Rootless:
/run/user/$UID/systemd/generator/<name>.service
Start the Container
- Rootful:
sudo systemctl start alpine.service
- Rootless:
systemctl --user start alpine.service
Enable at Boot
- Rootful:
sudo systemctl enable alpine.service
- Rootless:
systemctl --user enable alpine.service
(also requiressudo loginctl enable-linger $UID
)
Targets
- Rootful:
multi-user.target
- Rootless:
default.target
Generators
- Rootful:
/usr/lib/systemd/system-generators/podman-quadlet -dryrun
- Rootless:
/usr/lib/systemd/user-generators/podman-user-generator -dryrun
Summary
Rootful Podman behaves almost exactly like Docker in terms of how systemd manages services. Rootless Podman adds an extra layer of isolation (and complexity), but with the right commands and paths, it works just as smoothly. This cheat sheet should help you switch between modes without second guessing.
Podman #1 - Everyone is talking about podman
I’ve been using Docker forever, and everything was fine until the licensing changed and suddenly you couldn’t use it at work anymore. So, it’s time to pivot to Podman. Great. Everyone’s talking about it, so you figure, why not give it a try? But then you realize development is moving so fast that most of the documentation is already outdated before you even get started. Now, with the release of Debian Trixie, it’s finally time to sort this out.
In this series, I want to figure out how to use Podman as a replacement for Docker. For example, starting containers at boot using Quadlets. I work with Kubernetes quite a bit, so learning how pods work in Podman is a nice bonus. Network control and policies are also important, so we’ll take a look at those too.
Using Debian Trixie, we get a fairly recent version of Podman to work with, which makes experimenting a lot easier.
sudo apt install podman
podman --version
podman version 5.4.2
Step 1: Create a Quadlet
Let’s begin with a simple container. We’ll create a Quadlet in the default location for a root container:
nano /etc/containers/systemd/alpine.container
[Unit]
Description=Alpine test container
[Container]
Image=docker.io/library/alpine:latest
Exec=sleep infinity
[Service]
Restart=always
[Install]
WantedBy=multi-user.target
Save and close the file. At this point, nothing happens yet — no container is running.
Step 2: Reload systemd
Podman relies on systemd to manage services behind the scenes. To get systemd to notice our new Quadlet, reload it:
systemctl daemon-reload
This triggers "/usr/lib/systemd/system-generators/podman-quadlet", which generates the actual service file in "/etc/containers/systemd/".
Step 3: Troubleshoot if needed
If you run "systemctl daemon-reload" and no .service file appears in "/etc/containers/systemd/", try this command:
/usr/lib/systemd/system-generators/podman-quadlet -dryrun
It will tell you what went wrong in the Quadlet file ("/etc/containers/systemd/alpine.container" in our case).
Step 4: Start the container
If everything worked, you should see a file called alpine.service:
ls /etc/containers/systemd/
Now you can start it just like any other systemd service:
systemctl start alpine.service
And just like that, the container is up and running.
Step 5: Startup on boot
You might notice that the container already comes back after a reboot, even without manually enabling the service. That’s because Podman includes a helper service:
podman-restart.service
On boot, this service regenerates the systemd unit files in the documented locations and automatically starts them if the policy is set in your Quadlet. In other words, as long as you’ve configured "Restart=" or similar policies, Podman takes care of the boot startup for you.
https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html