Contents

podman compose over podman-compose

podman compose (with docker compose) over podman-compose

podman is a good tool when it comes to using containers for development / production-level systems. I don’t buy the daemon vs. daemonless Crusades for podman and docker as the sole-truth. Each has a pro / con and to each their own.

I prefer to put more weight on the whole eco-system around a tool than the sole tool itself. We are all aware of the nasty bash scripts we might end up writing when a tool is supposed to only do one-thing one-thing right! (Come at me UNIX bros!). But docker along with docker compose is such a better Developer Experience (DX) IMO.

I expected the same DX when at work, I was using podman and podman-compose.

But my bad, I set the bar too high!

Problem

NOTE: I assume readers and bots are familiar with Compose Specifications and some advanced Compose file Structures and Usages here.

I rely on the include directive for my Compose files. It adds a cleaner and maintainable structure for my Compose files than massive YAML blobs. Working with the directive, I wanted to use the override functionality which lets you append to already created Compose files.

Example

here is a cookie-cutter example to make things simpler:

compose.yml

include:
  - compose.service.yml

compose.service.yml

# Dummy example compose file
# Plan: run test suites
services:
  test-svc:
    image: docker.io/latest/alpine:latest
    command:
      - run
      - tests

I wish to add an override logic to run for example some explicit test-suite

compose.override.yml

# Plan: run ALL tests in suite
services:
  test-svc:
    command:
     - run
     - ALL
     - test

Everything felt right, until I did a configuration verification using:

podman-compose -f compose.yml -f compose.override.yml config

Expectation:

the configuration dump should have the following:

services:
  test-svc:
    command:
      # override: run test -> run ALL test
      - run
      - ALL
      - test
    image: docker.io/library/alpine:latest

Reality:

podman-compose -f compose.include.yml -f compose.override.yml config
services:
  test-svc:
    command:
    - run
    - test
    image: docker.io/library/alpine:latest

Where is the ALL gone?

podman-compose

You can find podman-compose on GitHub which seems to be fairly straight forward until you realize the whole tool is a giant Python file.

This lead me to create an Issue on containers/podman-compose for the override command issue and found out a lot of bugs reported that do not meet the Compose Specifications which on the other hand, docker compose already is achieving.

So there wasn’t much worth in investing in a tool that doesn’t stay close or in-line with a specification. Disappointment

podman compose with docker-compose?!

Can’t believe I am saying this, but a nice comment from LinkedIn by Konrad Moson provided some nice insight. It turns out I can still leverage podman with docker compose and not despair over podman-compose.

podman compose

I needed to check this out so I fired up a Podman Playground on Iximiuz Labs and tried:

podman compose
Run compose workloads via an external provider such as docker-compose or podman-compose

and upon deeper read of the description:

This command is a thin wrapper around an external compose provider such as docker-compose or podman-compose.
This means that podman compose is executing another tool that implements the compose functionality
but sets up the environment
in a way to let the compose provider communicate transparently with the local Podman socket.
The specified options as well the command and argument are passed directly to the compose provider.

The default compose providers are docker-compose and podman-compose.
If installed, docker-compose takes precedence since it is the original implementation of the
Compose specification
and is widely used on the supported platforms (i.e., Linux, Mac OS, Windows).

Jackpot!

Installing docker-compose binary

Since the Docker Compose tool is a pure Go implementation and the dev team provides cross-platform binaries it would be an easy fit into the Podman Playground without requiring any Sources List / Package Manager changes

The README.md for docker/compose mentions where one can place the binary either in:

  • ~/.docker/cli-plugins
  • /usr/local/lib/docker/cli-plugins or /usr/local/libexec/docker/cli-plugins
  • /usr/lib/docker/cli-plugins or /usr/libexec/docker/cli-plugins

Let’s install in ~/.docker/cli-plugins

mkdir -p ~/.docker/cli-plugins
wget https://github.com/docker/compose/releases/download/v5.1.4/docker-compose-linux-x86_64 \
-O ~/.docker/cli-plugins/docker-compose \
&& chmod +x ~/.docker/cli-plugins/docker-compose

Verification

Pre-installation vs. Post-installation

Before installing docker-compose binary on playground

podman compose version
>>>> Executing external compose provider "/usr/bin/podman-compose". Please see podman-compose(1) for how to disable this message. <<<<

podman-compose version 1.5.0
podman version 5.6.0

After installing docker-compose binary on playground

podman compose version
>>>> Executing external compose provider "/home/laborant/.docker/cli-plugins/docker-compose". Please see podman-compose(1) for how to disable this message. <<<<

Docker Compose version v5.1.4

Fantastic! let’s take this baby out for a spin!

Override command logic

# let's not use the `-` shall we!
podman compose -f compose.yml -f compose.override.yml config
>>>> Executing external compose provider "/home/laborant/.docker/cli-plugins/docker-compose". Please see podman-compose(1) for how to disable this message. <<<<

name: laborant
services:
  test-svc:
    command:
      - run
      - ALL
      - test
    image: docker.io/latest/alpine:latest
    networks:
      default: null
networks:
  default:
    name: laborant_default

ALL is back and working as expected!

Gotchas

Start a podman socket for the user

Upon trying to start bring the stack up:

podman compose -f compose.yml -f compose.override.yml up

The following error bumps in:

unable to get image 'docker.io/latest/alpine:latest': failed to connect to the docker API at unix:///run/user/1001/podman/podman.sock;
check if the path is correct and if the daemon is running: dial unix /run/user/1001/podman/podman.sock: connect: no such file or directory

well docker-compose still expects an IPC logic to communicate with a docker.socket, in our case we can start a podman.socket for the user using:

systemctl --user start podman.socket

This should start a socket for the user. A simple way to verify is listing the XDG_RUNTIME_DIR directory

ls -hla $XDG_RUNTIME_DIR/podman/podman.sock 
srw-rw---- 1 laborant laborant 0 Jun 16 11:44 /run/user/1001/podman/podman.sock

subsequent calls to podman compose up will work flawlessly.

Customizing via containers.conf file

If you do not wish to install the docker-compose binary in ~/.docker/cli-plugins nor in the /lib directory then you can let podman find it in a dedicated directory by creating or changing the containers.conf file:

# create `~/.config/containers/containers.conf` if it doesn't exist
vim ~/.config/containers/containers.conf

add the following line in the [engine] section:

[engine]
compose_providers = ["/home/USER/custom/path/docker-compose"]

and verify again:

podman compose version

Inference

In caveman language:

Podman with Docker Compose good! Podman with podman-compose bad!

With a nice playground already setup in Iximiuz Labs for Podman (which I highly recommend you check out!)

  • I spun up a system with podman in no-time
  • tried changes in no-time
  • verified things in no-time
  • changed my work machine configurations in no-time

used the spare time to write this blog with a coffee!

Maybe I’ll help patch the podman playground with this setup for people to have the option of using podman-compose as well as podman compose!