Podman: A Complete Overview

Podman
Till this moment we focused either on the low level container tools, or on very specialized ones. The truth behind such tools is that they are fantastic if you need to automate something, but they will never replace the fully featured container manager. The most fully featured and, arguably, popular Dockerless container manager these days is Podman.
Podman was created as a drop-in replacement for Docker, with the main difference being the focus on rootless containers. Same as Buildah, Podman does not require a privileged daemon - any regular user is able to run containers, and each container is scoped only to the user that runs it.
Talking about Buildah, Podman actually re-uses the source code of Buildah for image-related features - meaning, that commands like “podman pull, push and buildah” will run the same code that is behind Buildah - and it also means, that Podman and Buildah share the same storage for images.
Being a higher level utility, Podman uses either runc or crun as an underlying container runtime - but it can be used with any other OCI-compliant runtime, at least in theory.
Podman builds on top of everything we’ve discussed so far - it is compliant with OCI standards, it supports rootless containers and works nice with other tools from the container landscape. To install Podman, simply run yum install podman -y
, and proceed to the next chapter to see it in action.
Basic Podman Usage
Let’s start by building a new container image with Podman. We will re-use the same Containerfile and build it by running podman build -f Containerfile -t dockerless-curl:latest
. Just to remind, Podman has most of the Buildah source code compiled into it, meaning that podman build
is identical to running buildah build
command.
If we compare the output of podman images
and buildah images
commands, we won’t see any difference - both of the tools rely on the same storage for container images.
To run the container, we are going to use podman run
command, which works exactly the same as docker run
- it accepts the same arguments, up till the point that you can alias docker
to podman
and everything will work just fine.
podman run -it localhost/dockerless-curl curl https://mkdev.me
We can set some environment variables as well:
podman run -it -e HI=mkdev localhost/dockerless-curl env
Podman CLI was intentionally modelled after the Docker CLI, to simplify the transition process. There is a separate package named podman-docker, that sets up different aliases and symlinks, allowing you to use docker commands, which in fact will be executed by podman.
Let’s run another container with a terminal inside:
podman run -it -e HI=mkdev localhost/dockerless-curl sh
If we check whoami
, we will see that we are root inside the container. I can do some root-level things, like installing packages.
But outside the container, container process is running under the user who started it. We can verify this by finding container id via podman ps and then inspect this container id with podman inspect and afterwards checking this process id in the process table. This is due to the Linux user namespaces - the user id 0 in the container is mapped to the user id that started the container, for example.
Besides user namespaces, Podman also uses network namespaces, as well as cgroups v2 and a number of other relatively new and advanced Linux features to achieve rootless containers. As a result, almost all the features of Podman do not require privileged access.
The consequence of Podman relying so much on the advanced Linux features is that you can not use Podman on other operating systems - containers need to run inside some Linux VM.
Podman can be a drop in replacement for Docker, but it’s not just a copy of Docker. In the next chapter, we will talk about some of the more advanced and unique features of Podman.
Podman Advanced
While Podman can be a drop in replacement for Docker on Linux machines, it is not merely a clone of Docker. Let’s look at some of the unique Podman features.
The first feature is already hidden in the name: similar to Kubernetes, Podman has pods. Pod is a group of multiple containers, that share the same network namespace and are deployed together. Lets give them a try.
First, we create a new pod:
podman pod create --name dockerless
We can see the running pods by running podman pod ps
command. This new pod has only one container inside, the so called “infra” container. Just like inside the Kubernetes pods, the job of this infra container is to keep the pod alive, together will all the required namespaces. This infra container is even using the Kubernetes pod image.
The status of the pod is Created, because there are no useful containers in it. We can add a new container to this pod by running the podman run
command and passing the pod name:
podman run --label io.containers.autoupdate=image --pod dockerless -d docker.io/kshirinkin/dockerless-curl:latest sleep infinite
Ignore the label part for now, we will get back to it in a bit. Let’s run another one, with httpd:
podman run -e HI=mkdev -d --pod dockerless httpd
Now let’s enter the first container:
podman exec -it confident_gagarin sh
If we now try to access the port 80, we will get a response from the httpd: curl localhost:80
. Again, just like in Kubernetes pods, containers inside the pod can talk to each other over the localhost.
We can not access this httpd from outside the pod, because we did not map any ports. Ports are mapped on the whole pod, and we have to re-create the pod to do this. Creating pods by hand is not the convenient, which brings us to the next Podman feature: podman generate
command.
podman generate
can take an existing pod and generate either a systemd unit or a Kubernetes yaml for it. Let’s generate the systemd unit:
podman generate systemd dockerless --name -f --new
The result will be 3 different systemd services, for 3 different containers - keep in mind that pod is just an abstraction. What we think of a pod is an infra container that holds different namespaces, that are then shared with multiple other containers. We can see this relation in this systemd files, where 2 services depend on the pod service to start first.
You can also generate the pod yaml definition from Podman pod, and, in theory, use it inside the Kubernetes cluster. In practice, this yaml file will always be too far from what you would want for an application running on Kubernetes.
Stop all the containers in a pod with podman pod stop
command, and then remove the pod. Move the generated systemd units to a place where systemd can find them - that can be your user systemd services, it doesn’t have to be a global unit:
mv *.service /home/fodoj/.config/systemd/user
And now start the pod:
systemctl start pod-dockerless --user
If you check the podman ps
now, you will see the containers for this pod are running.
Remember that label we’ve set? This label tells Podman that this container should be auto-updated. To achieve this. I first need to log in to docker.io with my username and password. Afterwards, I am going to tag our image with docker.io/kshirinkin/dockerless-curl. And then I will push this image to the docker.io After it's pushed, I can run podman auto-update and it will find every container which has this auto-update label and it will check if there are new versions of the images that this container is based on, and if there is it will pull it and it will restart the container eventually. This is quite handy for patching containerized system services - you only need to make sure to run podman auto-update
as a systemd timer or a cron job.
Those are some of the features specific to Podman itself. There are many others, like a REST API that allows remote clients to manage containers. Many other features are similar to Docker, but with slight differences - there are, for example, healthchecks for your containers, as well as the podman machine
, that enables you to use podman on Mac and Windows.
Podman even suppororts Docker Compose files - you only need to install the Docker Compose tool, and then it will properly create containers from the same Compose file. Keep in mind, that Docker Compose is an extra python utility, that does not require the actual Docker daemon to be installed.
Podman Applications
We’ve seen how Podman can be both a drop in replacement for Docker, but also a unique tool of its own. You can use Podman as a local development tool or you could also use it to run containers on servers - it is perfectly capable to do both of these tasks. While being as powerful and feature complete as Docker, Podman has a couple of downsides, which, ironically, come from the Docker’s popularity.
The obvious one is the focus on Linux - you can still use it on other operating systems, but you need a Linux virtual machine.
The other disadvantage is when you are trying to use other tools from the containers ecosystem. Every now and then you will find a tool that is simply hardcoded to work with Docker only. Technically, it is totally capable of working with Podman, or any other OCI compliant container manager, but for historical reasons those tools would expect you to have Docker. Every time you encounter such tool makes Podman less attractive to you, and the only solution is to patch those other tools to be Dockerless.
If you have a Linux workstation, you should give Podman a try and see how long you can survive without missing Docker. Chances are, that you will rarely feel like you miss anything, and features like rootless containers and pods will only extend your container management capabilities. Now let’s talk about one more container manager.
Article Series "The Dockerless Course"
- What’s Wrong With Docker? Introduction to the Dockerless Course
- What Is a Container? Open Container Initiative Explained
- Where Container Images Are Stored: Introduction to Skopeo
- The Standards Behind the Modern Container Images
- Container Bundle Deep Dive
- runc, crun & Container Standards Wrap Up
- Buildah: A Complete Overview
- Container Managers and ContainerD
- Podman: A Complete Overview