In this blog, you will take a look at Podman Compose. With Podman Compose, you can use compose files according to the Compose Spec in combination with a Podman backend. Enjoy!
Introduction
A good starting point and a must-read is this blog provided by RedHat. In short, Podman Compose is not directly maintained by the Podman team, and neither is Docker Compose, of course. Podman Compose has a more limited feature set than Docker Compose and in general, it is advised to use Kubernetes YAML files for this purpose. See “Podman Equivalent for Docker Compose” for how this can be used. However, the Podman team will fix issues in Podman when required for Podman Compose. It is also possible to use Docker Compose in combination with Podman, as is described in the post “Use Docker Compose with Podman to Orchestrate Containers on Fedora Linux.”
In this post, you will use Podman Compose to run some basic containers. Sources used in this blog are available at GitHub and the container image is available at DockerHub. The container image is built in a previous blog post “Is Podman a Drop-in Replacement for Docker?”. You might want to check it out when you want to know more about Podman compared to Docker. The image contains a basic Spring Boot application with one REST endpoint which returns a hello message.
Prerequisites
The prerequisites needed for this blog are:
- Basic Linux knowledge
- Basic container knowledge
- Basic Podman knowledge
- Basic Docker Compose knowledge
Podman Compose With One Container
Let’s start with a basic single container defined in compose file docker-compose/1-docker-compose-one-service.yaml
. One service is defined as exposing port 8080 in order to be able to access the endpoint.
services: helloservice-1: image: docker.io/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT ports:
- 8080:8080
It is assumed that you have Podman installed already. Execute the following command from the root of the repository.
$ podman-compose -f docker-compose/1-docker-compose-one-service.yaml up -d
Error: unknown shorthand flag: 'f' in -f
As expected, this does not work. Podman Compose is not included or available when you have installed Podman. Docker Compose does not require an additional installation. Podman Compose is a community project not maintained by the Podman team and that is why it is not part of the Podman installation.
Installation instructions for Podman Compose can be found on the Podman Compose GitHub pages. The easiest way is to use pip
, the Python package installer. This requires an installed Python version and pip
.
$ pip3 install podman-compose
Run the Podman Compose command again.
$ podman-compose -f docker-compose/1-docker-compose-one-service.yaml up -d
podman-compose version: 1.0.6
['podman', '--version', '']
using podman version: 3.4.4
** excluding: set()
['podman', 'ps', '--filter', 'label=io.podman.compose.project=docker-compose', '-a', '--format', '{{ index .Labels "io.podman.compose.config-hash"}}']
['podman', 'network', 'exists', 'docker-compose_default']
podman run --name=docker-compose_helloservice-1_1 -d --label io.podman.compose.config-hash=b2928552303ab947ea3497ef5e1eff327c1c9672a8454f18f9dbee4578061370 --label io.podman.compose.project=docker-compose --label io.podman.compose.version=1.0.6 --label PODMAN_SYSTEMD_UNIT=podman-compose@docker-compose.service --label com.docker.compose.project=docker-compose --label com.docker.compose.project.working_dir=/home/.../mypodmanplanet/docker-compose --label com.docker.compose.project.config_files=docker-compose/1-docker-compose-one-service.yaml --label com.docker.compose.container-number=1 --label com.docker.compose.service=helloservice-1 --net docker-compose_default --network-alias helloservice-1 -p 8080:8080 docker.io/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT
302dcf140babae07c416e8556e11fc13918bd1fe3c52b737f4ab091f3599291e
exit code: 0
Verify whether the container has started successfully.
$ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3104b5a4c418 docker.io/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT About a minute ago Up About a minute ago 0.0.0.0:8080->8080/tcp docker-compose_helloservice-1_1
Verify whether the endpoint can be reached.
$ curl http://localhost:8080/hello
Hello Podman!
Shut down the container.
$ podman-compose -f docker-compose/1-docker-compose-one-service.yaml down
podman-compose version: 1.0.6
['podman', '--version', '']
using podman version: 3.4.4
** excluding: set()
podman stop -t 10 docker-compose_helloservice-1_1
docker-compose_helloservice-1_1
exit code: 0
podman rm docker-compose_helloservice-1_1
3104b5a4c4189777b21c2658a3d3c4df91b3f804d5c9bced63532f0318e9e9df
exit code: 0
Running a basic service just worked.
Podman Compose With Two Containers
Let’s run two containers defined in compose file docker-compose/2-docker-compose-two-services.yaml
. One service is available at port 8080 and the other one at port 8081.
services: helloservice-1: image: docker.io/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT ports: - 8080:8080 helloservice-2: image: docker.io/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT ports:
- 8081:8080
Run the Compose file from the root of the repository.
$ podman-compose -f docker-compose/2-docker-compose-two-services.yaml up -d
podman-compose version: 1.0.6
['podman', '--version', '']
using podman version: 3.4.4
** excluding: set()
['podman', 'ps', '--filter', 'label=io.podman.compose.project=docker-compose', '-a', '--format', '{{ index .Labels "io.podman.compose.config-hash"}}']
['podman', 'network', 'exists', 'docker-compose_default']
podman run --name=docker-compose_helloservice-1_1 -d --label io.podman.compose.config-hash=d73c6cebbe901d7e4f27699b4308a39acaa4c3517293680c24ea1dce255177cf --label io.podman.compose.project=docker-compose --label io.podman.compose.version=1.0.6 --label PODMAN_SYSTEMD_UNIT=podman-compose@docker-compose.service --label com.docker.compose.project=docker-compose --label com.docker.compose.project.working_dir=/home/.../mypodmanplanet/docker-compose --label com.docker.compose.project.config_files=docker-compose/2-docker-compose-two-services.yaml --label com.docker.compose.container-number=1 --label com.docker.compose.service=helloservice-1 --net docker-compose_default --network-alias helloservice-1 -p 8080:8080 docker.io/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT
ff344fb5e22800c2c7454d66572bbcad22a47536d0dc930960ea06844b7838f3
exit code: 0
['podman', 'network', 'exists', 'docker-compose_default']
podman run --name=docker-compose_helloservice-2_1 -d --label io.podman.compose.config-hash=d73c6cebbe901d7e4f27699b4308a39acaa4c3517293680c24ea1dce255177cf --label io.podman.compose.project=docker-compose --label io.podman.compose.version=1.0.6 --label PODMAN_SYSTEMD_UNIT=podman-compose@docker-compose.service --label com.docker.compose.project=docker-compose --label com.docker.compose.project.working_dir=/home/.../mypodmanplanet/docker-compose --label com.docker.compose.project.config_files=docker-compose/2-docker-compose-two-services.yaml --label com.docker.compose.container-number=1 --label com.docker.compose.service=helloservice-2 --net docker-compose_default --network-alias helloservice-2 -p 8081:8080 docker.io/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT
e88b6d4eb33b8869b2fa7c964cd153a2920558a27b7bc8cf0d2b9f4d881a89ee
exit code: 0
Verify whether both containers are running.
e88b6d4eb33b docker.io/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT 33 seconds ago Up 33 seconds ago 0.0.0.0:8081->8080/tcp docker-compose_helloservice-2_1″ data-lang=”text/x-sh”>
$ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ff344fb5e228 docker.io/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT 35 seconds ago Up 35 seconds ago 0.0.0.0:8080->8080/tcp docker-compose_helloservice-1_1
e88b6d4eb33b docker.io/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT 33 seconds ago Up 33 seconds ago 0.0.0.0:8081->8080/tcp docker-compose_helloservice-2_1
Verify whether both endpoints are accessible.
$ curl http://localhost:8080/hello
Hello Podman!
$ curl http://localhost:8081/hello
Hello Podman!
In the output after executing the podman-compose
command, you can see that a default network docker-compose_default
is created. A network alias helloservice-1
is created for container 1 and a network alias helloservice-2
is created for container 2.
Enter container 1 and try to access the endpoint of container 2 using the network alias. Beware to use the internal port 8080 instead of the external port mapping to port 8081!
$ podman exec -it docker-compose_helloservice-1_1 sh
/opt/app $ wget http://helloservice-2:8080/hello
Connecting to helloservice-2:8080 (10.89.1.3:8080)
saving to 'hello'
hello 100% |*********************************************************************************************************************| 13 0:00:00 ETA 'hello' saved
As you can see, the services can access each other using the network alias.
Finally, stop the containers.
$ podman-compose -f docker-compose/2-docker-compose-two-services.yaml down
podman-compose version: 1.0.6
['podman', '--version', '']
using podman version: 3.4.4
** excluding: set()
podman stop -t 10 docker-compose_helloservice-2_1
docker-compose_helloservice-2_1
exit code: 0
podman stop -t 10 docker-compose_helloservice-1_1
docker-compose_helloservice-1_1
exit code: 0
podman rm docker-compose_helloservice-2_1
e88b6d4eb33b8869b2fa7c964cd153a2920558a27b7bc8cf0d2b9f4d881a89ee
exit code: 0
podman rm docker-compose_helloservice-1_1
ff344fb5e22800c2c7454d66572bbcad22a47536d0dc930960ea06844b7838f3
exit code: 0
Conclusion
Podman Compose works with some basic Compose files. However, Podman Compose lacks features compared to Docker Compose. This list cannot be easily found (at least, I could not find it). This means that it is a risk of using Podman Compose instead of Docker Compose. Besides that, RedHat itself recommends using Kubernetes YAML files instead of Compose files. If you are using Podman, it is better to use the Kubernetes YAML files for container orchestration.