Podman

Introduction

Podman is an OCI compliant container management tool that offers similar features like Docker for managing containers.

One of the best features of podman is its ability to run rootless containers. A rootless container is a concept of running and managing containers without root privileges (Normal user). From a security standpoint, rootless containers add an additional layer of security by not allowing root access even if the container gets compromised by an attacker. You can read about the benefits of rootless containers here

Note

Docker also supports rootless mode with some limitations. You can read about it in this documentation

Podman is also daemonless (unlike docker), meaning it doesn’t have a daemon and interacts directly with the runc (runs containers based on OCI specification). Toward the end of the article, I added the difference between Docker and Podman.

Also, let’s say there are two users in Linux. user-a and user-b. The containers created by user-a using podman cannot be modified by user-b and vice versa.

Another interesting and advanced feature of podman is running containers in Pods. Similar to Kubernetes pods, you can create multi-container pods locally using Podman. You can export the podman pod as a Kubernetes manifest and use a Kubernetes pod manifest to deploy and podman pod.

Docker Vs Podman

Podman

Docker

Podman is Daemonless

Docker has a daemon (containerd ). The docker CLI interacts with the daemon to manage containers.

Podman interacts with the Linux kernel directly through runc

Docker daemon owns all the child processes of running containers

Podman can deploy pods with multiple containers. The same pod manifest can be used in Kubernetes. Also, you can deploy a Kubernetes pod manifest as a Podman pod.

There is no concept of a pod in Docker

Can run rootless containers without any additional configurations. You can run containers with root or non-privileged users.

Docker rootless mode requires additional configurations.

Installation

# Update your packages
sudo apt-get update && sudo apt-get upgrade
# Install Podman
sudo apt-get install podman

From there usage is as normal

Usage

# Create Podman Machine
podman machine init
# Start Podman
podman machine start
# Verify Info
podman info

Similar to docker, most commands are the same

# Start Container
podman start
# Stop Container
podman stop
# View Processes
podman ps
# Remove Container
podman rm

Registries

We can also grab images from any repository; Github, Docker, Google, Redhat, Kubernates

From Podman Add Registry

# System-Wide configuration
nano /etc/containers/registries.conf

# User-Specific configuration
nano $HOME/.config/containers/registries.conf

# An example would be
[[registry]]
location=quay.io

# Or

[[registry]]
location="my-registry.tld"
username="username"
password="password"

This allows us to have anything accessible for us to pull..

Permissions

Podman permissions seem tricky at first, but let’s try to understand them together..

Podman utilises something called SELinux which is a kernel addon created by the NSA for high security settings, although we don’t need this additional security, it is very good to have considering containers are supposed to be secure by design.

If you read into how it works, you will slowly start to understand that podman mimics the systems permissions in a strange way, as everything inside the container needs to be run as root under podmans control, the outside permissions need to allow this

Below is a table that somewhat explains this.

From Podman Rootless Volumes

The table below shows four possible rootless/rootful operating modes of Podman

You run podman as..

With containerised process running as..

The actual UID visible on the host is…

root

root

0

root

non-root

The UID of the user running the process inside the container

non-root

root

Your UID

non-root

non-root

A non-root UID

All rootless containers must be run in the same user namespace. If they are not, some things (like sharing the network namespace from another container) would be impossible.

By using the same user namespace, your containers can share resources with each other, without needing to ask for root privileges.

It uses this user namespace to mount filesystems, or run a container which accesses more than one user ID (UID) or group ID (GID).

This mapping is fine for most situations, except when the container needs to be able to share something with the host, like a volume.

But - here’s the important thing:

When the container runs, any volumes which are shared with it, will appear inside the user namespace as owned by root/root. Because the mapping will map your UID on the host (e.g. 1000) as root (0) in the container.

Examples

We have gone through and figured out roughly how to get these permissions working nicely in the container.

The examples provided are for single run commands, but include the PUID and PGID

podman run -d \
--name=nextcloud \
-e PUID=7000 \
-e PGID=7000 \
-e TZ=Europe/London \
-p 443:443 \
-v /home/nextcloud/config:/config \
-v /home/nextcloud/data:/data \
--restart unless-stopped \
lscr.io/linuxserver/nextcloud:latest

Here the example is for nextcloud, we’ve created a user nextcloud on the server, the UID are set on the user when created.

su nextcloud
mkdir config
mkdir data

#Run the podman command here

Since the directories are created under the nextcloud user, they have control and access..

Podman then hooks onto this in a sense, leverages the users permissions then elevates to root within the container.

Referring to the table from before, this user is non-root, so podman will be root.

Command Structure

From what I have seen there are different ways to structure a run command, however they are all Similar

podman run -d \
--name=<name> \
-e PUID=<uid> \
-e PGID=<gid> \
-e <EXTRA> \
-p <port number> \
-v <volume/directory> \
--restart <option> \
<repository link>

Going through this line by line, we have the container name which should be obvious

Next we have PUID and PGID, these are what allow the container to hook onto the user and elevate root inside the container

Next we have an optional extra, this can be another environment variable like timezone or something else like gpu support

Now onto the port number, the way this works is simple. There’s 000:000. The number before the brackets is the port on our local machine the port after the brackets is what the container will use. So for web servers that’ll be :80, :8080, :443, etc.. The idea being you can run multiple services on one or several ports with simple port forwarding.

After that is the volume, we set these up so we can tell the container where to store data or configuration files, similar to how the port forwarding works We have /home/$USER/dev:/dev. So within the container it requires a dev folder, we create a directory on our host machine and link the two together. This is why setting UID permissions is important since without them, we would not be able to communicate or do anything within this volume.

Next is just the restart option, if you want to use always, unless-stopped, never As you can guess, always is just always looping, unless-stopped is to restart it if for some reason it crashes and stops, never just means if it ever stops, don’t restart it.

Common Issues

Following are some of the errors and issues I faced while doing hands-on with Podman.

Port Mapping Error

If you try to map privileged ports you might get the following error. Always use a nonprivileged port if you want to run Podman as a non-root user.

Error: error from slirp4netns while setting up port redirection: map[desc:bad request: add_hostfwd: slirp_add_hostfwd failed]

If you don’t have runc installed, you might get the following error.

Error: default OCI runtime "runc" not found: invalid argument

Image Errors

If you don’t specify the correct image name, Podman will throw the following error.

Trying to pull quay.io/busybox...
  error parsing HTTP 404 response body: invalid character '<' looking for beginning of value: "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n<title>404 Not Found</title>\n<h1>Not Found</h1>\n<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>\n"

It normally happens with quay.io because, unlike docker, for quay.io , you should specify the image name correctly.

For example, podman pull busybox, will throw the error. But, podman pull quay/busybox works without any error.

Pod Errors

If you try to add a container with ports that were not added during the pod creation, you will get the following error.

Error: invalid config provided: published or exposed ports must be defined when the pod is created: network cannot be configured when it is shared with a pod

If you try to delete a pod with running containers, you will get the following error. First, you need to stop all the containers and then delete the pod.

Error: pod 9e31de31950664702f21 has containers that are not ready to be removed: cannot remove container 3d10007e844a5aea3c7805fb0ee986b0b4c2cedd66c0996d0bff9f53ba1c0b57 as it is running - running or paused containers cannot be removed without force: container state improper

Sometimes you might deploy containers using a specific user and if you try to list the containers with a different user or with sudo, you will get the following error.

Error: no pod with name or ID webserver found: no such pod

Sources of Information

Here are my Sources

Source 1

Source 2

Source 3