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 — ORQUESTACIÓN ROOTLESS podman pod (espacio de nombres de usuario rootless) app (Node.js) puerto: 3000 depends_on: db healthcheck: /health db (PostgreSQL) puerto: 5432 volumen: pgdata:Z healthcheck: pg_isready redis (Caché) puerto: 6379 volumen: redis-data healthcheck: ping systemd Quadlet inicio auto unidades usuario Sin daemon root — los contenedores se ejecutan como tu usuario mediante espacios de nombres

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 sudo solo 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:

AspectoDockerPodman
ArquitecturaCliente-servidor daemonFork/exec, sin daemon
Privilegio por defectoSe ejecuta como rootRootless por defecto
Soporte ComposePlugin docker composepodman-compose o podman compose
Formato de imagenOCI (compatible con Docker)OCI (compatible con Docker)
Requerimiento de socket/var/run/docker.sock (root)Socket de usuario opcional
Integración con systemdArchivos de unidad externosSoporte nativo con Quadlet
Compatibilidad CLIImplementación de referenciaDrop-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 :Z reetiqueta 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

HerramientaRootlessDaemonIntegración systemdCompose SpecExport Kubernetes
Docker ComposeNo (rootful)Sí (dockerd)Solo externoCompletoNo
podman-composeNoVia Quadletv2/v3No
podman composeNoVia Quadletv2/v3No
Nerdctl + containerdParcialSí (containerd)LimitadoCompletoNo
Podman QuadletNoNativoDeclarativoVia podman kube generate
Kubernetes (k3s)ParcialExternoVia KomposeSí (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/subuid y /etc/subgid para 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 :Z en 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 systemd para definiciones de servicios declarativas y mantenibles

Artículos Relacionados