Podman Compose brings Docker Compose-style multi-container orchestration to Podman without requiring a Docker daemon or root privileges. It reads standard docker-compose.yml files and translates them into podman commands, so existing Compose definitions work without modification. On RHEL 8, Podman is already installed, and Podman Compose can be added from EPEL or via pip. This tutorial covers both installation methods, running a Compose stack rootlessly, using Podman’s native Kubernetes YAML support as an alternative, and configuring user-mode networking with slirp4netns.

Prerequisites

  • RHEL 8 with Podman installed (dnf install -y podman)
  • Root or sudo access for system-wide installation; pip method works per-user
  • Python 3.6 or later (included in RHEL 8)
  • EPEL repository enabled if using the dnf method
  • slirp4netns installed for rootless networking (dnf install -y slirp4netns)

Step 1 — Install Podman Compose

Install slirp4netns first — it provides the user-mode networking stack that rootless containers rely on for port mapping and inter-container communication.

sudo dnf install -y slirp4netns

Method A — from EPEL (recommended for system-wide use):

sudo dnf install -y epel-release
sudo dnf install -y podman-compose
podman-compose --version

Method B — from pip (works without EPEL, installs into virtualenv or user site):

pip3 install --user podman-compose
# Ensure ~/.local/bin is in PATH
echo 'export PATH=$HOME/.local/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
podman-compose --version

Step 2 — Run a Compose Stack Rootlessly

Podman Compose reads the same docker-compose.yml files Docker Compose uses. Create a simple two-service stack to verify the setup.

mkdir -p ~/testapp && cd ~/testapp

cat > docker-compose.yml <<'EOF'
version: "3.9"
services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
  cache:
    image: redis:7-alpine
    command: redis-server --save ""
EOF

podman-compose up -d
podman-compose ps

Check the nginx welcome page is reachable:

curl -s http://localhost:8080 | head -5

Tear the stack down when finished:

podman-compose down

Step 3 — Create a Custom Podman Network

By default Podman Compose creates a network per project. You can also create networks manually and reference them by name in your Compose file for more control over subnets and DNS.

podman network create appnet
podman network ls
podman network inspect appnet

Reference the pre-existing network in docker-compose.yml:

cat >> docker-compose.yml <<'EOF'

networks:
  default:
    external: true
    name: appnet
EOF

Step 4 — Use Podman’s Native Kubernetes YAML Support

Podman can export any running pod or container as a Kubernetes YAML manifest with podman generate kube, and deploy it back with podman play kube. This is Podman’s native alternative to Compose for grouping containers into pods.

# Create a pod with two containers
podman pod create --name mypod -p 8081:80
podman run -d --pod mypod --name mynginx nginx:alpine
podman run -d --pod mypod --name myredis redis:7-alpine

# Export the pod definition as Kubernetes YAML
podman generate kube mypod > mypod.yaml
cat mypod.yaml

Tear down the pod and replay it from the YAML file:

podman pod stop mypod && podman pod rm mypod
podman play kube mypod.yaml
podman pod ps

Step 5 — Rootless Networking with slirp4netns

slirp4netns implements a user-mode TCP/IP stack inside the network namespace of a rootless container, allowing it to reach the internet and expose ports without kernel-level privileges. Verify it is active for a running container:

# Run a rootless container and inspect its network namespace
podman run -d --name nettest -p 8082:80 nginx:alpine
podman inspect nettest --format '{{.NetworkSettings.Networks}}'

# See the slirp4netns process providing the network
ps aux | grep slirp4netns

For inter-container DNS resolution within a Podman network, Podman uses its built-in DNS plugin (aardvark-dns on newer versions, dnsname plugin on RHEL 8). Install the plugin if not already present:

sudo dnf install -y podman-plugins
podman network create --dns-enable=true dnsnet
podman network inspect dnsnet | grep -i dns

Step 6 — Run Podman Compose as a systemd Service

Wrap a Podman Compose stack in a simple systemd user service so it restarts automatically after login or reboot.

mkdir -p ~/.config/systemd/user

cat > ~/.config/systemd/user/testapp.service <<'EOF'
[Unit]
Description=testapp podman-compose stack
After=default.target

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=%h/testapp
ExecStart=/usr/local/bin/podman-compose up -d
ExecStop=/usr/local/bin/podman-compose down

[Install]
WantedBy=default.target
EOF

systemctl --user daemon-reload
systemctl --user enable --now testapp.service
systemctl --user status testapp.service

Conclusion

Podman Compose extends Podman’s daemonless, rootless container model to multi-service applications defined in standard Docker Compose files. Whether you install it from EPEL or pip, it integrates cleanly with existing docker-compose.yml definitions, and Podman’s native podman play kube command offers a path toward Kubernetes-compatible workloads without leaving the local environment. Combined with slirp4netns for user-mode networking and systemd for service management, Podman Compose provides a complete container workflow on RHEL 8 that requires no root daemon at any point.

Next steps: How to Install Podman as a Rootless Docker Alternative on RHEL 8, How to Deploy Applications with Docker Compose on RHEL 8, and How to Set Up a Private Docker Registry on RHEL 8.