How to Configure Podman Compose on RHEL 7

Podman Compose is a Python script that implements the Docker Compose file specification against the Podman container engine. It allows you to use your existing docker-compose.yml files with Podman, either with the rootless model for increased security or as root on systems where Docker is not installed. Because Podman has no daemon, Podman Compose uses a slightly different internal model — services run as individual containers coordinated through a Podman pod rather than a Docker-managed network — but for most workloads the docker-compose.yml syntax transfers without modification. This tutorial covers installing Podman Compose on RHEL 7, running a multi-service stack, understanding the key differences from Docker Compose, and exploring Podman’s native pod model.

Prerequisites

  • RHEL 7.6 or later with Podman installed (see the previous tutorial on installing Podman)
  • Python 3 and pip3 available (python3 --version)
  • Root or sudo access for system-wide installation, or a virtual environment for user-level
  • Familiarity with Docker Compose YAML syntax

Step 1: Install Python 3 and pip

RHEL 7 ships with Python 2.7 as the default. Python 3 is available from the SCL (Software Collections Library) or EPEL. Install Python 3 if it is not already present:

# Enable EPEL if not already done
sudo yum install -y epel-release

# Install Python 3
sudo yum install -y python3 python3-pip

# Verify
python3 --version
pip3 --version

Alternatively, using Software Collections:

sudo yum install -y centos-release-scl
sudo yum install -y rh-python36
scl enable rh-python36 bash

Step 2: Install Podman Compose

Install Podman Compose from PyPI using pip3:

sudo pip3 install podman-compose

Verify the installation:

podman-compose --version

If you prefer a user-level (non-root) installation, use the --user flag and ensure ~/.local/bin is in your PATH:

pip3 install --user podman-compose

echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

To install a specific version or upgrade:

sudo pip3 install --upgrade podman-compose

# Pin to a specific version
sudo pip3 install "podman-compose==1.0.6"

Step 3: Create a Sample Project

Create a project directory with a simple multi-service docker-compose.yml. This example runs a WordPress site with a MySQL backend:

mkdir -p ~/wpsite
cd ~/wpsite

cat > docker-compose.yml <<'EOF'
version: "3"

services:
  db:
    image: mysql:5.7
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wpuser
      MYSQL_PASSWORD: wppass
    volumes:
      - db_data:/var/lib/mysql

  wordpress:
    image: wordpress:6-apache
    restart: unless-stopped
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wpuser
      WORDPRESS_DB_PASSWORD: wppass
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wp_content:/var/www/html/wp-content
    depends_on:
      - db

volumes:
  db_data:
  wp_content:
EOF

Step 4: Start the Stack with podman-compose up

# Pull images first (recommended to see errors early)
podman-compose pull

# Start all services in detached mode
podman-compose up -d

Check that the containers are running:

podman ps

You should see two containers running, typically named with the pattern <projectname>_<service>_1.

Step 5: View Logs and Manage the Stack

# Follow all service logs
podman-compose logs -f

# Follow logs for a specific service
podman-compose logs -f db

# Stop all services (containers stopped, not removed)
podman-compose stop

# Start stopped services
podman-compose start

# Stop and remove all containers and networks
podman-compose down

# Stop, remove containers AND volumes (data loss)
podman-compose down -v

# Restart a single service
podman-compose restart wordpress

Execute a command inside a running service container:

podman-compose exec db mysql -u root -p

Step 6: Key Differences from Docker Compose

While Podman Compose aims for compatibility, there are important behavioural differences to be aware of:

Pod vs Network Model

By default, Podman Compose creates a single Podman pod for each compose project. All containers in the project share the pod’s network namespace, meaning they can reach each other on localhost (not by service name). This differs from Docker Compose, where each service gets its own network interface and communicates by service name through Docker’s internal DNS.

To use the Docker-like network model with DNS-based service discovery, set the PODMAN_COMPOSE_PROVIDER environment variable or pass the --pod-args flag. Some versions of Podman Compose support a --no-pod flag to create individual containers connected by a bridge network instead:

podman-compose --no-pod up -d

No Built-in Scaling

Podman Compose does not support --scale or deploy.replicas. Each service runs as exactly one container. For scaling, use Podman’s native pod commands or consider Kubernetes/OpenShift.

Volume Handling

Named volumes defined in the compose file are created as Podman named volumes. Bind mounts work identically to Docker. SELinux relabelling may be required for bind mounts — append :z (shared) or :Z (private) to mount options:

volumes:
  - ./config:/app/config:Z

env_file Support

Podman Compose supports env_file in service definitions, same as Docker Compose:

services:
  app:
    image: myapp:latest
    env_file:
      - .env
      - secrets.env

Step 7: Understanding Podman Pods

Pods are a Kubernetes-inspired concept in Podman where multiple containers share the same network namespace, UTS namespace, and optionally IPC namespace. This is the foundation of how Podman Compose groups services.

# List all pods
podman pod list

# Inspect the pod created by podman-compose
podman pod inspect wpsite

You can also create and manage pods manually:

# Create a pod that exposes ports 80 and 3306
podman pod create --name mypod -p 80:80 -p 3306:3306

# Add a container to the pod
podman run -d --pod mypod --name mydb 
  -e MYSQL_ROOT_PASSWORD=secret 
  mysql:5.7

# Add a second container to the same pod
podman run -d --pod mypod --name myweb nginx:alpine

# List containers in the pod
podman ps --pod

# Stop the entire pod (all containers)
podman pod stop mypod

# Start the pod
podman pod start mypod

# Remove the pod and all containers in it
podman pod rm -f mypod

Within a pod, containers communicate via localhost because they share the same network stack:

# Inside myweb container, reach MySQL on localhost:3306
podman exec -it myweb sh -c "nc -zv localhost 3306"

Step 8: Generate systemd Services for a Compose Stack

To make a Podman Compose stack start automatically at boot, generate systemd unit files from the pod:

# Start the stack so the pod and containers exist
podman-compose up -d

# Find the pod name
podman pod list

# Generate systemd units for the pod and all its containers
mkdir -p ~/.config/systemd/user/
cd ~/.config/systemd/user/

podman generate systemd --pod-prefix "" --separator "-" 
  --files --name wpsite

# Reload daemon and enable
systemctl --user daemon-reload
systemctl --user enable pod-wpsite.service
systemctl --user start pod-wpsite.service

# Persist after logout
sudo loginctl enable-linger $(whoami)

Conclusion

Podman Compose brings the familiar Docker Compose workflow to the Podman ecosystem on RHEL 7, letting you reuse existing docker-compose.yml files with minimal changes while gaining the security benefits of Podman’s daemonless, rootless architecture. Understanding the key differences — particularly the pod networking model versus Docker’s bridge networking — prevents subtle connectivity issues and helps you decide when to use --no-pod mode for direct service-name DNS resolution. For teams migrating from Docker to Podman, Podman Compose provides a smooth transition path: start by simply replacing docker-compose with podman-compose in your existing workflows, then gradually adopt Podman-native features such as pods and podman generate systemd to integrate your containerised workloads fully into RHEL 7’s systemd service management.