Beginner's Guide to Using Podman Compose

If you have looked for alternatives to Docker, Podman might have attracted your attention.

One thing that Podman does not yet have is the ability to automatically pull appropriate images and start the containers based on a compose file.

There exists a tool called podman-compose that is an alternative to docker-compose tool and it works with Podman, as you would expect. So let us see how to use this tool.

What is podman-compose?

Docker provides the functionality to specify all the necessary details like the container name, image used, restart policy, volumes, bind mounts, ports, labels, etc inside a single file. This file is usually called the docker-compose.yml file.

This functionality is missing from Podman. Hence we need to use the podman-compose tool to achieve this functionality.

The podman-compose tool does this by adhering to the Compose specification. This is the same specification that Docker adheres to, making it compatible with an existing docker-compose.yml file. (There may be some pedantic differences like enclosing values between double quotes ("), etc but those can be easily solved by looking at the errors.)

Installing the podman-compose tool

Since the podman-compose tool is a relatively new tool, your stable/LTS Linux distribition might not have it in the first party repositories. But nonetheless, let us see what your options are and how to install it.

On Ubuntu 22.10 (Kinetic Kudu) and later and Debian 12 (Bookworm) and later, you can install it using the apt package manager like so:

sudo apt install podman-compose

Users of Fedora 36 and later (the package version on Fedora 35 is 0.1.7-6.git) can use the dnf package manager to install podman-compose like so:

sudo dnf install podman-compose

OpenSUSE Tumbleweed or Leap 15 and later can install the podman-compose tool like so:

sudo zypper install podman-compose

If you are a proud Arch Linux user, you do not need my help. But below is the installation command nonetheless ;)

sudo pacman -Syu podman-compose

Verify the installation

To ensure that the podman-compose utility is either installed or its path is included in the PATH environment variable, you can check it like so:

podman-compose --version

This should also list your Podman version.

On my Fedora 36 machine, I get the following output:

$ podman-compose --version
['podman', '--version', '']
using podman version: 4.3.1
podman-composer version  1.0.3
podman --version
podman version 4.3.1
exit code: 0
Get a $10 credit for Fathom, a privacy-focused website analytics company
Someone has shared a link with you that gives you $10 credit upon sign-up.

Basics of the podman-compose tool

For the sake of keeping this tutorial short, sweet and digestable, I will not cover the structure of a compose file. But fret not! We already have a quick guide to using docker-compose.

For the sake of convenience, below is the compose file that I am using:

version: 3.7

services:


    reverse-proxy:
        image: docker.io/library/caddy:alpine
        container_name: caddy-vishwambhar
        command: caddy run --config /etc/caddy/Caddyfile
        restart: always
        ports:
            - "8080:80"
            - "8443:443"
        volumes:
            - /docker-volumes/caddy/Caddyfile:/etc/caddy/Caddyfile:Z
            - /docker-volumes/caddy/site:/srv:Z
            - /docker-volumes/caddy/caddy_data:/data:Z
            - /docker-volumes/caddy/caddy_config:/config:Z
            - /docker-volumes/caddy/ssl:/etc/ssl:Z
        labels:
            - io.containers.autoupdate=registry
            - pratham.container.category=proxy
        environment:
            - TZ=Asia/Kolkata
        depends_on:
            - gitea-web


    gitea-web:
        image: docker.io/gitea/gitea:latest
        container_name: gitea-govinda
        restart: always
        ports:
            - "8010:3000"
            - "8011:22"
        volumes:
            - /docker-volumes/gitea/web:/data:Z
            - /docker-volumes/gitea/ssh:/data/git/.ssh:Z
            - /etc/localtime:/etc/localtime:ro
        labels:
            - io.containers.autoupdate=registry
            - pratham.container.category=gitea
        environment:
            - RUN_MODE=prod
            - DISABLE_SSH=false
            - START_SSH_SERVER=true
            - SSH_PORT=22
            - SSH_LISTEN_PORT=22
            - ROOT_URL=https://git.mydomain.com
            - DOMAIN=git.mydomain.com
            - SSH_DOMAIN=git.mydomain.com
            - GITEA__database__DB_TYPE=postgres
            - GITEA__database__HOST=gitea-db:5432
            - GITEA__database__NAME=gitea
            - GITEA__database__USER=gitea
            - GITEA__database__PASSWD=/run/secrets/gitea_database_user_password
            - GITEA__service__DISABLE_REGISTRATION=true
            - TZ=Asia/Kolkata
        depends_on:
            - gitea-db
        secrets:
            - gitea_database_user_password


    gitea-db:
        image: docker.io/library/postgres:14-alpine
        container_name: gitea-chitragupta
        restart: always
        volumes:
            - /docker-volumes/gitea/database:/var/lib/postgresql/data:Z
        labels:
            - io.containers.autoupdate=registry
            - pratham.container.category=gitea
        environment:
            - POSTGRES_USER=gitea
            - POSTGRES_PASSWORD=/run/secrets/gitea_database_user_password
            - POSTGRES_DB=gitea
            - TZ=Asia/Kolkata
        secrets:
            - gitea_database_user_password


secrets:
    gitea_database_user_password:
        external: true

Let us now start with the basic commands.

Starting all containers from the compose file

Using the up command, we can create and start the services described in our compose file (docker-compose.yml).

You can simply use the up command and start all the specified containers/services that are listed in the compose file like so:

podman-compose up -d

Running the above command will perform all the necessary actions needed to start the services/containers listed in the compose file. That includes steps like the folloiwng:

  • Pull all the images that are not available locally
  • Create the containers with all the specified options (ports, volumes, secrets, networks, etc)
  • Start the containers in a specific order (defined by constraints like depends_on)

If you looked closely at the above example, you might have noticed a new option; the -d option. This option starts the container in the background, detaching it from the current shell.


Once the containers are up and running, you can verify that by running the podman ps command:

$ podman ps
CONTAINER ID  IMAGE                                COMMAND               CREATED      STATUS          PORTS                                         NAMES
d7b7f91c03aa  docker.io/library/caddy:alpine       caddy run --confi...  4 hours ago  Up 4 hours ago  0.0.0.0:8080->80/tcp, 0.0.0.0:8443->443/tcp   caddy-vishwambhar
1cfcc6efc0d0  docker.io/library/postgres:14-alpine postgres              4 hours ago  Up 4 hours ago                                                gitea-chitragupta
531be3df06d0  docker.io/gitea/gitea:latest         /bin/s6-svscan /e...  4 hours ago  Up 4 hours ago  0.0.0.0:8010->3000/tcp, 0.0.0.0:8011->22/tcp  gitea-govinda

Stop all containers from the compose file

To stop all the containers specified in the compose file, use the down command.

podman-compose down

Additionally, you can give a timeout so the containers can shut themselves down safely. This is done using either of the following options:

podman-compose down -t TIMEOUT_IN_SECONDS
podman-compose down --timeout TIMEOUT_IN_SECONDS

Please note that the down command only stops the container(s). If you want to delete containers, that will need to be done manually.

Start, stop or specific services

If you are iterating through multiple configurations like ports, volumes, environment variables, etc, you might be using the podman-compose up and the podman-compose down command repeatedly.

This will start and stop all services, respectively. Meaning, if you only have one service to start/stop, you now have to wait for all the services listed in a compose file to start and shut down. That's no good!

To solve this, we can use the start and stop commands to start or stop individual services. There is even a restart command. This does exactly what it says :)

Below is a demonstration where I start the gitea-db service, stop it and then restart it, just for you ;)

$ podman-compose start gitea-db

$ podman-compose stop gitea-db

$ podman-compose restart gitea-db

Pull all necessary images at once

Let's say that you specified 10 different services in your compose file. What if waiting once is okay to you, but not when you want to start the contiainers--for whatever reason?

If that is the case, all you have to do is use the pull command like so:

podman-compose pull

Running the above command will pull all the images that are specified in the compose file.

Use a different name for your compose file

Now, I do not know why you might do this. There are several reasons for you to do this. Maybe keeping the compose file's name as docker-compose.yml triggers you to type docker instead of podman.

Whatever the reason might be, you can use either of the following flags to specify the name of the comopse file, like so:

podman-compose -f COMPOSE_FILE_NAME
podman-compose --file COMPOSE_FILE_NAME

Let's assume my compose file is not named docker-compose.yml, but is instead named my-compose-file.yml. To use this compose file, I will run the following command:

podman-compose --file my-compose-file.yml

Running the above command will inform the podman-compose tool that the compose file is named my-compose-file.yml instead of docker-compose.yml.

Conclusion

Podman is an amaizng container orchestration tool; and along with the podman-compose tool, creating multiple containers with your specified details become easier! I recommend that you try out the podman-compose tool and let us know about your experience.