TL;DR — Resumo Rápido
Guia completo do Podman Compose para orquestração rootless. Instale, configure e migre do Docker Compose com systemd e Quadlet no Ubuntu e Fedora.
O Podman Compose traz o fluxo de trabalho familiar do Docker Compose para o motor de contêineres Podman, que é sem daemon e rootless. Se você procura uma alternativa ao Docker que não exija um daemon privilegiado em segundo plano, não exponha superfície de ataque root e se integre nativamente ao systemd, este guia é para você. Você aprenderá a instalar o Podman e o podman-compose, configurar namespaces de usuário rootless, migrar projetos Docker Compose existentes, gerenciar pods e habilitar o início automático através do Quadlet.
Pré-requisitos
Antes de começar, certifique-se de ter:
- Um sistema Linux: Ubuntu 22.04/24.04, Fedora 39+ ou RHEL/Rocky Linux 9
- Uma conta de usuário normal (root não é necessário para operações diárias)
- Conhecimento básico da sintaxe YAML do Docker Compose
- Acesso a
sudoapenas para a instalação inicial
Por Que Usar o Podman em Vez do Docker?
A arquitetura do Docker centraliza-se em um daemon privilegiado (dockerd) executando como root. Cada chamada ao CLI docker passa por um socket Unix de propriedade do root, o que significa que qualquer processo que possa acessar o socket Docker tem efetivamente root no host.
O Podman adota uma abordagem fundamentalmente diferente:
| Aspecto | Docker | Podman |
|---|---|---|
| Arquitetura | Cliente-servidor daemon | Fork/exec, sem daemon |
| Privilégio padrão | Executa como root | Rootless por padrão |
| Suporte Compose | Plugin docker compose | podman-compose ou podman compose |
| Formato de imagem | OCI (compatível com Docker) | OCI (compatível com Docker) |
| Requisito de socket | /var/run/docker.sock (root) | Socket de usuário opcional |
| Integração systemd | Arquivos de unidade externos | Suporte nativo com Quadlet |
| Compatibilidade CLI | Implementação de referência | Drop-in (alias docker=podman) |
Instalação
Ubuntu 22.04 / 24.04
sudo apt update
sudo apt install -y podman
podman --version
Para Podman 5.x no Ubuntu 22.04, adicione o repositório oficial 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
sudo dnf install -y podman # Fedora
sudo dnf install -y container-tools # RHEL 9 / Rocky Linux 9
Alias Drop-in para Docker
sudo apt install -y podman-docker # Ubuntu
sudo dnf install -y podman-docker # Fedora/RHEL
Configuração de Contêineres Rootless
A operação rootless depende de namespaces de usuário Linux e mapeamentos de UID/GID definidos em /etc/subuid e /etc/subgid.
grep "^$(whoami)" /etc/subuid /etc/subgid
Se as entradas estiverem ausentes:
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $(whoami)
podman system migrate
podman run --rm hello-world
Para portas abaixo de 1024:
echo 'net.ipv4.ip_unprivileged_port_start=80' | sudo tee /etc/sysctl.d/99-unprivileged-ports.conf
sudo sysctl --system
Instalação do podman-compose
# Via pip (todas as distribuições)
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
O Podman 4.4+ inclui um subcomando podman compose embutido que delega automaticamente para podman-compose ou docker-compose:
podman compose version
Criando um compose.yaml para o Podman
O Podman Compose suporta a Especificação Compose (sintaxe v2/v3). Seus arquivos docker-compose.yml existentes funcionam sem modificações na grande maioria dos casos.
Exemplo completo de stack de produção — API Node.js com PostgreSQL e 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 do Podman:
- Prefixo
docker.io/library/: O Podman não adiciona o Docker Hub como registro implícito. Sempre use referências de imagem totalmente qualificadas. - Rótulo de volume
:Z: Em sistemas com SELinux (Fedora, RHEL, Rocky), o sufixo:Zreetiqueta o volume para que o processo do contêiner possa acessá-lo.
Inicie o stack:
podman-compose up -d
podman pod ps
podman ps
podman-compose logs -f api
Gerenciamento de Pods
Quando o podman-compose inicia um stack com múltiplos serviços, ele cria um pod do Podman que agrupa os contêineres e compartilha um namespace de rede:
podman pod ps
podman pod inspect myapp_default
podman pod stats myapp_default
podman-compose down
podman-compose down -v
Construção de Imagens com Buildah e 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
Integração com systemd: Quadlet
O Quadlet é a forma moderna de executar contêineres Podman como serviços systemd sem escrever arquivos de unidade manualmente. Vem incluído com o Podman 4.4+.
Crie ~/.config/containers/systemd/myapp-db.container:
[Unit]
Description=Banco de Dados 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
Ative:
systemctl --user daemon-reload
systemctl --user enable --now myapp-db
journalctl --user -u myapp-db -f
loginctl enable-linger $(whoami)
Comparação: Ferramentas de Orquestração Compose
| Ferramenta | Rootless | Daemon | Integração systemd | Compose Spec | Exportação Kubernetes |
|---|---|---|---|---|---|
| Docker Compose | Não (rootful) | Sim (dockerd) | Apenas externo | Completo | Não |
| podman-compose | Sim | Não | Via Quadlet | v2/v3 | Não |
podman compose | Sim | Não | Via Quadlet | v2/v3 | Não |
| Nerdctl + containerd | Parcial | Sim (containerd) | Limitado | Completo | Não |
| Podman Quadlet | Sim | Não | Nativo | Declarativo | Via podman kube generate |
| Kubernetes (k3s) | Parcial | Sim | Externo | Via Kompose | Sim (nativo) |
Migrando do Docker Compose
# Passo 1 — Alias docker para podman
alias docker=podman
alias docker-compose=podman-compose
echo "alias docker=podman" >> ~/.bashrc
echo "alias docker-compose=podman-compose" >> ~/.bashrc
Atualize as referências de imagem:
# Antes (Docker)
image: postgres:16-alpine
# Depois (melhor prática Podman)
image: docker.io/library/postgres:16-alpine
Adicione rótulos de volume SELinux em sistemas RHEL/Fedora e remova privileged: true onde possível.
Casos Especiais e Advertências
Diferenças de rede: O modo rootless do Podman usa pasta/slirp4netns em vez de redes bridge do kernel. Redes macvlan e ipvlan requerem modo root.
Portas abaixo de 1024: Contêineres rootless não podem vincular portas de host abaixo de 1024 por padrão. Configure net.ipv4.ip_unprivileged_port_start=80 ou use um proxy reverso.
Compatibilidade com docker.sock: Ferramentas como Portainer requerem o socket Docker. O Podman fornece um socket compatível via podman system service. Inicie com systemctl --user start podman.socket.
Negações do SELinux: Se uma montagem de volume falhar no RHEL/Fedora, adicione o rótulo :Z. Nunca desabilite o SELinux.
Solução de Problemas
Erros de “short-name resolution”: O Podman requer nomes de imagem totalmente qualificados. Adicione unqualified-search-registries = ["docker.io"] ao /etc/containers/registries.conf.
“newuidmap/newgidmap not found”: Instale o pacote uidmap (sudo apt install uidmap).
Contêiner não acessa a internet: Instale slirp4netns (sudo apt install slirp4netns) ou passt no Ubuntu 24.04 (sudo apt install passt).
Resumo
- O Podman é um motor de contêineres sem daemon e rootless por padrão, compatível com OCI e o CLI do Docker
- O podman-compose suporta Compose Spec v2/v3 e executa stacks de múltiplos serviços sem privilégios root
- Configure
/etc/subuide/etc/subgidpara mapeamento de UID rootless antes de executar cargas de trabalho com múltiplos contêineres - Sempre use referências de imagem totalmente qualificadas e adicione rótulos de volume
:Zem sistemas com SELinux - O Quadlet fornece integração nativa com systemd para início automático e registro de journal de serviços em contêineres
- Para cargas de trabalho em produção, prefira o Quadlet ao
podman generate systemdpara definições de serviços declarativas e manuteníveis