TL;DR — Resumen Rápido
Guía completa de Podman Compose para orquestación rootless. Instala, configura y migra desde Docker Compose con systemd y Quadlet en Ubuntu y Fedora.
Podman Compose lleva el flujo de trabajo familiar de Docker Compose al motor de contenedores Podman, que es daemonless y rootless. Si buscas una alternativa a Docker que no requiera un daemon privilegiado en segundo plano, no exponga una superficie de ataque de root y se integre de forma nativa con systemd, esta guía es para ti. Aprenderás a instalar Podman y podman-compose, configurar espacios de nombres de usuario rootless, migrar proyectos de Docker Compose existentes, gestionar pods y habilitar el inicio automático mediante Quadlet.
Requisitos Previos
Antes de comenzar, asegúrate de tener:
- Un sistema Linux: Ubuntu 22.04/24.04, Fedora 39+ o RHEL/Rocky Linux 9
- Una cuenta de usuario normal (root no es necesario para las operaciones diarias)
- Conocimiento básico de la sintaxis YAML de Docker Compose
- Acceso a
sudosolo para la instalación inicial
Por Qué Usar Podman en Lugar de Docker
La arquitectura de Docker se centra en un daemon privilegiado (dockerd) que se ejecuta como root. Cada llamada al CLI de docker pasa por un socket Unix propiedad de root. Esto significa que cualquier proceso que pueda acceder al socket de Docker tiene efectivamente root en el host, un riesgo de seguridad importante.
Podman adopta un enfoque fundamentalmente diferente:
| Aspecto | Docker | Podman |
|---|---|---|
| Arquitectura | Cliente-servidor daemon | Fork/exec, sin daemon |
| Privilegio por defecto | Se ejecuta como root | Rootless por defecto |
| Soporte Compose | Plugin docker compose | podman-compose o podman compose |
| Formato de imagen | OCI (compatible con Docker) | OCI (compatible con Docker) |
| Requerimiento de socket | /var/run/docker.sock (root) | Socket de usuario opcional |
| Integración con systemd | Archivos de unidad externos | Soporte nativo con Quadlet |
| Compatibilidad CLI | Implementación de referencia | Drop-in (alias docker=podman) |
Instalación
Ubuntu 22.04 / 24.04
sudo apt update
sudo apt install -y podman
podman --version
Para Podman 5.x en Ubuntu 22.04, agrega el repositorio oficial de Kubic:
. /etc/os-release
echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/unstable/xUbuntu_${VERSION_ID}/ /" \
| sudo tee /etc/apt/sources.list.d/kubic-podman.list
curl -fsSL "https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/unstable/xUbuntu_${VERSION_ID}/Release.key" \
| sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/kubic-podman.gpg
sudo apt update && sudo apt install -y podman
Fedora / RHEL / Rocky Linux
# Fedora
sudo dnf install -y podman
# RHEL 9 / Rocky Linux 9
sudo dnf install -y container-tools
Alias Drop-in para Docker
sudo apt install -y podman-docker # Ubuntu
sudo dnf install -y podman-docker # Fedora/RHEL
Configuración de Contenedores Rootless
La operación rootless depende de los espacios de nombres de usuario de Linux y los mapeos de UID/GID definidos en /etc/subuid y /etc/subgid.
grep "^$(whoami)" /etc/subuid /etc/subgid
Si faltan las entradas:
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $(whoami)
podman system migrate
Verifica el funcionamiento rootless:
podman run --rm hello-world
Para puertos por debajo de 1024:
echo 'net.ipv4.ip_unprivileged_port_start=80' | sudo tee /etc/sysctl.d/99-unprivileged-ports.conf
sudo sysctl --system
Instalación de podman-compose
# Mediante pip (todas las distribuciones)
pip install --user podman-compose
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
# Fedora / RHEL
sudo dnf install -y podman-compose
# Ubuntu
sudo apt install -y podman-compose
Podman 4.4+ incluye un subcomando podman compose incorporado que delega automáticamente a podman-compose o docker-compose:
podman compose version
Creación de un compose.yaml para Podman
Podman Compose soporta la Especificación Compose (sintaxis v2/v3). Tus archivos docker-compose.yml existentes funcionan sin modificaciones en la gran mayoría de los casos.
Ejemplo completo de stack de producción — API Node.js con PostgreSQL y Redis:
# compose.yaml
name: myapp
services:
api:
build:
context: ./api
dockerfile: Containerfile
image: myapp-api:latest
ports:
- "3000:3000"
environment:
NODE_ENV: production
DATABASE_URL: "postgresql://appuser:${DB_PASSWORD}@db:5432/appdb"
REDIS_URL: "redis://redis:6379"
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
volumes:
- ./api/logs:/app/logs:Z
networks:
- backend
restart: unless-stopped
db:
image: docker.io/library/postgres:16-alpine
environment:
POSTGRES_DB: appdb
POSTGRES_USER: appuser
POSTGRES_PASSWORD: "${DB_PASSWORD}"
volumes:
- pgdata:/var/lib/postgresql/data:Z
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
networks:
- backend
restart: unless-stopped
redis:
image: docker.io/library/redis:7-alpine
command: redis-server --save 60 1 --loglevel warning
volumes:
- redis-data:/data:Z
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 5
networks:
- backend
restart: unless-stopped
networks:
backend:
driver: bridge
volumes:
pgdata:
redis-data:
Notas específicas de Podman:
- Prefijo
docker.io/library/: Podman no agrega Docker Hub como registro implícito. Siempre usa referencias de imagen completamente calificadas. - Etiqueta de volumen
:Z: En sistemas con SELinux habilitado (Fedora, RHEL, Rocky), el sufijo:Zreetiqueta el volumen para que el proceso del contenedor pueda acceder a él.
Inicia el stack:
podman-compose up -d
podman pod ps
podman ps
podman-compose logs -f api
Gestión de Pods
Cuando podman-compose inicia un stack con múltiples servicios, crea un pod de Podman que agrupa los contenedores y comparte un espacio de nombres de red:
podman pod ps
podman pod inspect myapp_default
podman pod stats myapp_default
podman-compose down
podman-compose down -v
Construcción de Imágenes con Buildah y Containerfiles
# Containerfile
FROM docker.io/library/node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
FROM docker.io/library/node:22-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
RUN adduser -D -u 1001 appuser
USER appuser
EXPOSE 3000
CMD ["node", "server.js"]
podman build -t myapp-api:latest -f Containerfile ./api
Integración con systemd: Quadlet
Quadlet es la forma moderna de ejecutar contenedores de Podman como servicios de systemd sin escribir archivos de unidad manualmente. Viene incluido con Podman 4.4+.
Crea ~/.config/containers/systemd/myapp-db.container:
[Unit]
Description=Base de Datos MyApp
[Container]
Image=docker.io/library/postgres:16-alpine
Environment=POSTGRES_DB=appdb
Environment=POSTGRES_USER=appuser
EnvironmentFile=%h/.config/myapp/db.env
Volume=%h/.local/share/myapp/pgdata:/var/lib/postgresql/data:Z
HealthCmd=pg_isready -U appuser -d appdb
HealthInterval=10s
[Service]
Restart=always
[Install]
WantedBy=default.target
Activa:
systemctl --user daemon-reload
systemctl --user enable --now myapp-db
journalctl --user -u myapp-db -f
loginctl enable-linger $(whoami)
Comparación: Herramientas de Orquestación Compose
| Herramienta | Rootless | Daemon | Integración systemd | Compose Spec | Export Kubernetes |
|---|---|---|---|---|---|
| Docker Compose | No (rootful) | Sí (dockerd) | Solo externo | Completo | No |
| podman-compose | Sí | No | Via Quadlet | v2/v3 | No |
podman compose | Sí | No | Via Quadlet | v2/v3 | No |
| Nerdctl + containerd | Parcial | Sí (containerd) | Limitado | Completo | No |
| Podman Quadlet | Sí | No | Nativo | Declarativo | Via podman kube generate |
| Kubernetes (k3s) | Parcial | Sí | Externo | Via Kompose | Sí (nativo) |
Migración desde Docker Compose
# Paso 1 — Alias docker a podman
alias docker=podman
alias docker-compose=podman-compose
# Permanente
echo "alias docker=podman" >> ~/.bashrc
echo "alias docker-compose=podman-compose" >> ~/.bashrc
Actualiza las referencias de imagen:
# Antes (Docker)
image: postgres:16-alpine
# Después (mejor práctica Podman)
image: docker.io/library/postgres:16-alpine
Agrega etiquetas de volumen SELinux en sistemas RHEL/Fedora y elimina privileged: true donde sea posible.
Casos Especiales y Advertencias
Diferencias de red: El modo rootless de Podman usa pasta/slirp4netns en lugar de redes de puente del kernel. Las redes macvlan e ipvlan requieren modo root.
Puertos por debajo de 1024: Los contenedores rootless no pueden enlazar puertos de host por debajo de 1024 por defecto. Configura net.ipv4.ip_unprivileged_port_start=80 o usa un proxy inverso.
Compatibilidad con docker.sock: Herramientas como Portainer requieren el socket Docker. Podman lo proporciona mediante podman system service. Inicia con systemctl --user start podman.socket.
Errores de SELinux: Si un montaje de volumen falla en RHEL/Fedora, agrega la etiqueta :Z. Nunca deshabilites SELinux.
Solución de Problemas
Errores de “short-name resolution”: Podman requiere nombres de imagen completamente calificados. Agrega unqualified-search-registries = ["docker.io"] a /etc/containers/registries.conf.
“newuidmap/newgidmap not found”: Instala el paquete uidmap (sudo apt install uidmap).
El contenedor no puede acceder a internet: Instala slirp4netns (sudo apt install slirp4netns) o passt en Ubuntu 24.04 (sudo apt install passt).
Resumen
- Podman es un motor de contenedores sin daemon y rootless por defecto, compatible con OCI y el CLI de Docker
- podman-compose soporta Compose Spec v2/v3 y ejecuta stacks de múltiples servicios sin privilegios de root
- Configura
/etc/subuidy/etc/subgidpara el mapeo de UID rootless antes de ejecutar cargas de trabajo multi-contenedor - Usa siempre referencias de imagen completamente calificadas y agrega etiquetas de volumen
:Zen sistemas con SELinux - Quadlet proporciona integración nativa con systemd para inicio automático y registro en journal de servicios en contenedores
- Para cargas de trabajo en producción, prefiere Quadlet sobre
podman generate systemdpara definiciones de servicios declarativas y mantenibles