Podman Compose lets you run docker-compose files without needing Docker installed.
Here’s a basic docker-compose.yaml file for a simple web application:
version: '3.8'
services:
web:
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html
To run this with Podman Compose, first save the above content as docker-compose.yaml. Then, create a directory named html in the same location and put an index.html file inside it.
Now, from your terminal, run:
podman-compose up -d
This command will:
- Parse
docker-compose.yaml: It reads the configuration for your services. - Pull images: If
nginx:latestisn’t already on your system, Podman will download it. - Create networks: It sets up any necessary networks for your services to communicate.
- Create volumes: It prepares any persistent storage volumes defined.
- Start containers: It launches the containers based on the specified images and configurations.
You can then verify the running container:
podman ps
You should see an nginx container listed. To access the web server, open your browser and go to http://localhost:8080. You’ll see the content of your index.html file.
To stop and remove the containers, networks, and volumes created by Podman Compose, use:
podman-compose down
The core problem Podman Compose solves is the dependency on the Docker daemon. Docker requires a background daemon to manage containers, networks, and volumes. This daemon has root privileges, which can be a security concern and also adds overhead. Podman, on the other hand, is daemonless. It interacts directly with the Linux kernel’s containerization features (like namespaces and cgroups) using a fork/exec model. This means Podman containers can run as unprivileged users, enhancing security and reducing resource consumption. Podman Compose essentially translates the docker-compose YAML syntax into Podman commands, allowing you to leverage familiar orchestration patterns without the Docker daemon.
Podman Compose doesn’t just mimic docker-compose; it actively translates the YAML structure into Podman’s native API calls. For instance, when you define a ports mapping like "8080:80", Podman Compose ensures that the host port 8080 is correctly bound to the container’s port 80 using Podman’s port forwarding mechanisms. Similarly, volumes are mapped to Podman’s volume management, which can be named volumes or bind mounts to host directories. The networks directive translates into Podman’s network stack, creating CNI (Container Network Interface) networks that allow containers to discover and communicate with each other. This translation is key to its functionality, as it bridges the gap between the Docker Compose specification and Podman’s execution environment.
A common misconception is that Podman Compose is a direct fork of the original docker-compose project. While it uses the same parsing logic and aims for high compatibility, the underlying execution engine is entirely different. docker-compose relies on the Docker API, which in turn communicates with the Docker daemon. Podman Compose, however, uses libpod (the Podman library) to directly manage the lifecycle of containers, networks, and volumes. This means that when you run podman-compose up, it’s not sending instructions to a separate daemon; it’s invoking Podman’s functionality directly from your user space, which is a fundamental architectural difference.
The next concept you’ll likely explore is managing more complex multi-service applications, including inter-service communication and dependency ordering.