Podman For Container Management

After a look at all the random virtual machines running across a few systems on my home network, I decided its really time to start migrating from VMs to containers rather than having mulitple VMs stood up each for their own task. I've used containers for specific instances such as testing software from an official image off DockerHub, or running builds in a CI system, but generally stick to VMs for isolation and familiarity with the workflow.

Podman is a "daemonless container engine" that comes installed on Fedora workstation. Theres plenty qualified sources of information to get more details, but a typical user can look at it almost as a drop in replacement for running docker containers. Behind the scenes theres quite a differences between podman and docker, but that would quickly go beyond the scope of this post and is better left to the more qualified sources. The primary thing to keep in mind is it is daemonless, meaning there is no seperate service required to be running, and allows a user to create containers without elevated or specific privileges.

Basics

Containers

Podman has containers, which are run as a process rather than on a daemon. Containers are the running process of an image. These can be interacted with the same commands as docker such as run to run a container and exec to run a command on a running container.

Images

Images hold the same meaning in Podman as they do in Docker. Images are the compilation of layers of commands, filesystem, etc, to make up an... image. An image is the definition of a container. A container is a running image. Its layers all the way down. Again, same commands as docker such as pull, push, list.

Pods

Pods are where podman will differ for someone with a bit of familiarity with docker, but not enough to have dug into something like Kubernetes. Pods are a group of containers in a single namespace. The containers in a pod are the containers that are linked and communicating. Pods also include another container, the infra container. This container does nothing but sleep, and does so to keep the pod running even if no other containers are running. Theres an excellent bit of information from Podman.

Podman-compose

Podman-compose doesn't offer complete parity, but for most users this will probably be fine. Like docker-compose, podman-compose stands up a container(s) defined in a yaml file.

The default networking in podman-compose runs all the containers in a single pod. To see how well it works, you can give it a shot with an example straight from the docker-compose documentation using wordpress.

The docker-compose.yml file uses a mysql and wordpress image stand up a basic Wordpress installation in two containers. This is a good example for exposing an HTTP port to the wordpress container, as well as a network connection between the two for database access.

```version: '3.3'

services: db: image: mysql:5.7 volumes: - db_data:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: somewordpress MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress

wordpress: depends_on: - db image: wordpress:latest ports: - "8000:80" restart: always environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress WORDPRESS_DB_NAME: wordpress volumes: db_data: {}

### podman-compose up

Podman-compose up runs containers with the images and attributes defined in the `docker-compose.yml` file. Adding `-d` runs the containers in detached mode so the containers will detach from the command once they run successfully.

One interesting note of the output below is the translation for mounting the volumes, the volumes are in a namespaced directory in `/home/dan/.local/share/containers/storage`. The volume is in the user's home directory and not in `/var` as docker does by default. This is a good thing on a laptop/desktop/workstation where `/home` is typically a large partiton in comparison to `/var`.

```dan@host:~/Projects/example_wordpress$ podman-compose up -d
podman pod create --name=example_wordpress --share net -p 8000:80
98810f0d9df2ca8faec58d05445f7aa36e3f8a7f285b893e5829155753cea6f8
0
podman volume inspect example_wordpress_db_data || podman volume create example_wordpress_db_data
Error: no volume with name "example_wordpress_db_data" found: no such volume
podman run --name=example_wordpress_db_1 -d --pod=example_wordpress --label io.podman.compose.config-hash=123 --label io.podman.compose.project=example_wordpress --label io.podman.compose.ve
rsion=0.0.1 --label com.docker.compose.container-number=1 --label com.docker.compose.service=db -e MYSQL_ROOT_PASSWORD=somewordpress -e MYSQL_DATABASE=wordpress -e MYSQL_USER=wordpress -e MY
SQL_PASSWORD=wordpress --mount type=bind,source=/home/dan/.local/share/containers/storage/volumes/example_wordpress_db_data/_data,destination=/var/lib/mysql,bind-propagation=z --add-host db:
127.0.0.1 --add-host example_wordpress_db_1:127.0.0.1 --add-host wordpress:127.0.0.1 --add-host example_wordpress_wordpress_1:127.0.0.1 mysql:5.7
f3fa682c5a7ab8dee19888acbf714c752cf7688657c9c161a20a951894491d26
0
podman run --name=example_wordpress_wordpress_1 -d --pod=example_wordpress --label io.podman.compose.config-hash=123 --label io.podman.compose.project=example_wordpress --label io.podman.com
pose.version=0.0.1 --label com.docker.compose.container-number=1 --label com.docker.compose.service=wordpress -e WORDPRESS_DB_HOST=db:3306 -e WORDPRESS_DB_USER=wordpress -e WORDPRESS_DB_PASS
WORD=wordpress -e WORDPRESS_DB_NAME=wordpress --add-host db:127.0.0.1 --add-host example_wordpress_db_1:127.0.0.1 --add-host wordpress:127.0.0.1 --add-host example_wordpress_wordpress_1:127.
0.0.1 wordpress:latest
ae402644bb0a3c8487b6a3efcc510f4454b4faea4086f856520f6f27724c7349
0

Podman pods

Running containers are viewed with ps. Note there are two, wordpress:latest and mysql:5.7, as expected from the compose file. The output below uses the --format option to output only a few of the details to make this easier to read.

```dan@host:~/Projects/example_wordpress$ podman ps --format "table {{.ID}} {{.Image}} {{.Status}} {{.Ports}} {{.Names}}" ID Image Status Ports Names ae402644bb0a docker.io/library/wordpress:latest Up 3 minutes ago 0.0.0.0:8000->80/tcp example_wordpress_wordpress_1 f3fa682c5a7a docker.io/library/mysql:5.7 Up 3 minutes ago 0.0.0.0:8000->80/tcp example_wordpress_db_1

That `example_wordpress` is included in in the container names, which is the namespace the containers are running in, named by `podman-compose` after the directory where `podman-compose` was executed. Pods can be viewed with `podman pod list`, and more details can be viewed with the `inspect` command as demonstrated with the `example_wordpress` pod below.

The `pod list` displays there are three running containers on the `example_wordpress` pod even though only two images were defined in the `docker-compose.yml` file. Also `podman ps` displayed there were only two containers running. It also includes the `INFRA ID` column with the beginning of a SHA.

```dan@host:~/Projects/example_wordpress$ podman pod list
POD ID         NAME                STATUS    CREATED          # OF CONTAINERS   INFRA ID
98810f0d9df2   example_wordpress   Running   3 minutes ago    3                 ad6ee2217602

Running inspect provides more info about what containers are running in that pod and their IDs.

```dan@host:~/Projects/example_wordpress$ podman pod inspect example_wordpress | jq '.Containers' [ { "id": "ad6ee22176020c5cfa93e3e0bd740a5e147781e22711784ae341978ef05339a5", "state": "running" }, { "id": "ae402644bb0a3c8487b6a3efcc510f4454b4faea4086f856520f6f27724c7349", "state": "running" }, { "id": "f3fa682c5a7ab8dee19888acbf714c752cf7688657c9c161a20a951894491d26", "state": "running" } ]

As mentioned in the beginning of this post, pods have an `infra` container that sleeps to keep the pod running. This is included in the full output if above didn't filter with `jq`. The infra container is given in the `state` information and it matches the `INFRA ID` column.

```dan@host:~/Projects/example_wordpress$ podman pod inspect example_wordpress | jq '.State.infraContainerID'
"ad6ee22176020c5cfa93e3e0bd740a5e147781e22711784ae341978ef05339a5"

That container can be viewed in the container list using --filter.

```dan@host:~/Projects/example_wordpress$ podman container list -a --filter id=ad6ee22176020c5cfa93e3e0bd740a5e147781e22711784ae341978ef05339a5 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ad6ee2217602 k8s.gcr.io/pause:3.1 5 minutes ago Up 5 minutes ago 0.0.0.0:8000->80/tcp 98810f0d9df2-infra

Cool. Remember that container is running with the intention of keeping the pod alive even if no services are. That can be seen in action. Note for those unfamiliar, you can specify just the first few characters of the SHA to identify a container, rather than using the full SHA.

Lets kill our containers that aren't infra.

```dan@host:~/Projects/example_wordpress$ podman container stop ae40264
ae402644bb0a3c8487b6a3efcc510f4454b4faea4086f856520f6f27724c7349

dan@host:~/Projects/example_wordpress$ podman container stop f3fa68
f3fa682c5a7ab8dee19888acbf714c752cf7688657c9c161a20a951894491d26

And take another look to make sure they're exited.

```dan@host:~/Projects/example_wordpress$ podman-compose ps podman ps --filter label=io.podman.compose.project=example_wordpress CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ae402644bb0a docker.io/library/wordpress:latest apache2-foregroun... 5 minutes ago Exited (0) 23 seconds ago 0.0.0.0:8000->80/tcp example_wordpress_wordpress_1 f3fa682c5a7a docker.io/library/mysql:5.7 mysqld 5 minutes ago Exited (0) 4 seconds ago 0.0.0.0:8000->80/tcp example_wordpress_db_1

Now view the pod to see if it's still running. It should be (and is) thanks to the infra container.

```dan@host:~/Projects/example_wordpress$ podman pod list

POD ID         NAME                STATUS    CREATED          # OF CONTAINERS   INFRA ID
98810f0d9df2   example_wordpress   Running   5 minutes ago   3                 ad6ee2217602

And check out the containers via inspect on the pod again. Only one is running (filtered the output with jq, but it would show the container IDs as well).

```dan@host:~/Projects/example_wordpress$ podman pod inspect example_wordpress | jq '.Containers[].state' "running" "exited" "exited"

Now kill the infra container...

```dan@host:~/Projects/example_wordpress$ podman container stop ad6ee
ad6ee22176020c5cfa93e3e0bd740a5e147781e22711784ae341978ef05339a5

...and the pod is finally exited.

dan@host:~/Projects/example_wordpress$ podman pod list POD ID NAME STATUS CREATED # OF CONTAINERS INFRA ID 98810f0d9df2 example_wordpress Exited 5 minutes ago 3 ad6ee2217602

Conclusion

Fun stuff all around. Thanks to podman being installed on fresh Fedora Workstation, and not requiring elevated privleges and a daemon, it's a great way to get in digging around and using containers. Having almost the exact same functionality and parameters to docker makes it easy to transfer skill from podman to docker or the other way around.

social