Docker vs Podman em 2026: O guia completo de migração que ninguém pediu (mas todo mundo precisa)
Algo estranho tá rolando no mundo dos containers. Docker — a ferramenta que literalmente inventou containerização — tá perdendo espaço de mansinho. E não pra uma startup badalada, mas pra um projeto open-source que a maioria dos devs nem testou ainda: Podman.
Os números são claros. As estrelas do Podman no GitHub passaram de 30.000 no início de 2026. Red Hat, SUSE e Canonical incluem ele de fábrica nas distros. Kubernetes tirou o Docker como runtime na versão 1.24, e desde então muitos times começaram a se perguntar "será que nossa stack de containers tá boa assim?". Pra completar, as mudanças de licenciamento do Docker Desktop transformaram "a ferramenta grátis que todo mundo usa" em "algo que custa 10M."
Mas a maioria dos artigos de comparação erra o alvo: não se trata de Podman ser "melhor" que Docker. Se trata de entender se o seu workflow, tamanho do time, requisitos de segurança e target de deploy fazem um ser concretamente melhor que o outro pro seu caso.
Nesse guia a gente mergulha nas diferenças de arquitetura, percorre cenários reais de migração, mede o que realmente importa e monta um framework de decisão concreto. Sem enrolação e sem "depende" genérico. Bora.
Arquitetura: A divisão fundamental
Antes de mais nada, precisa entender a maior diferença de design entre Docker e Podman. Todo o resto vem daí.
Docker: tem um daemon rodando o tempo todo
Docker funciona com uma arquitetura cliente-servidor onde um daemon persistente (dockerd) fica sempre em background:
┌─────────────┐ ┌──────────────┐ ┌───────────────┐
│ docker CLI │────▶│ dockerd │────▶│ containerd │
│ (cliente) │ │ (daemon) │ │ (runtime) │
└─────────────┘ └──────────────┘ └───────────────┘
│
Roda como root
Sempre escutando
Gerencia todos os containers
Quando você roda docker run nginx, o CLI manda um request pro daemon, que baixa a imagem, cria o container e gerencia o ciclo de vida inteiro. Roda como root por padrão e gerencia todos os containers do sistema a partir de um único processo.
As vantagens são reais:
- Gerenciamento central: um processo tem visibilidade de todo o estado
- Background transparente: containers continuam vivos mesmo se você fechar o terminal
- Ecossistema depende dele: Docker Compose, Swarm e milhares de ferramentas esperam o socket do daemon
Os custos também:
- Superfície de ataque grande: daemon roda como root. Se for comprometido, atacante ganha root no host
- Ponto único de falha:
dockerdcaiu, todos os containers caem junto - Recursos em idle: daemon consome memória e CPU mesmo quando tá parado
Podman: sem daemon
Podman resolve de outro jeito. Não tem daemon nenhum.
┌─────────────┐ ┌───────────────┐
│ podman CLI │────▶│ conmon │
│ (direto) │ │ (monitor por │
└─────────────┘ │ container) │
└───────────────┘
│
Roda como usuário
Modelo fork-exec
Cada container independente
Quando você roda podman run nginx, Podman forkeia diretamente o processo do container usando conmon (um monitor leve). Sem daemon. Cada container roda como processo independente na sua conta de usuário.
O que você ganha com isso?
- Sem root: containers rodam com seu UID por padrão
- Sem ponto único de falha: um container caindo não afeta os outros
- Zero overhead em idle: nada roda quando você não tá usando containers
- Integração com systemd: containers viram serviços systemd normais
O que perde?
- Sem estado centralizado: gerenciamento por sessão (o banco do Podman cuida da persistência)
- Background precisa de setup: pra container sobreviver ao logout precisa de
podman generate systemdou flags--restart - Ferramentas que esperam Docker: as que dependem de
/var/run/docker.sockprecisam de adaptação
Segurança: Por que isso realmente importa
"Containers rootless" parece buzzword até você entender o que concretamente isso previne.
O problema do root no Docker
O daemon do Docker roda como root por padrão. Quando você monta um volume com -v /host/path:/container/path, o processo do container pode ler e escrever esses arquivos como root no host. Docker tem mitigações (user namespaces, seccomp, AppArmor), mas são opt-in e a maioria dos times não ativa.
Pra dimensionar o risco:
# Escape de container com daemon root docker run -v /:/host --privileged alpine chroot /host # → acesso root completo ao filesystem do host
O modo rootless do Docker (disponível desde 20.10) resolve, mas precisa de configuração explícita:
# Habilitar rootless dockerd-rootless-setuptool.sh install # Verificar docker info | grep "Root Dir" # Deve mostrar algo em ~/.local/share/docker
Na prática, a maioria das instalações continua rodando o daemon como root. É o padrão e a maioria dos tutoriais nem menciona rootless.
Podman: rootless de fábrica
Podman roda rootless sem configurar nada. Sai assim da caixa:
# Funciona direto, sem root, sem daemon, sem setup podman run -d nginx # Verificar que roda com seu usuário podman top -l user # Mostra seu UID, não root
Por baixo dos panos, Podman usa Linux user namespaces pra mapear UIDs do container pra UIDs não-privilegiados do host:
# Dentro do container, nginx acha que é root (UID 0) # Mas no host, tá rodando como seu usuário (ex: UID 1000) podman unshare cat /proc/self/uid_map # Output: # 0 1000 1 # 1 100000 65536
Se alguém escapar do container, obtém apenas os permissões do seu usuário não-privilegiado. Root fica fora de alcance.
Segurança: a comparação
| Feature | Docker (padrão) | Docker (rootless) | Podman |
|---|---|---|---|
| Daemon roda como | root | usuário | Sem daemon |
| UID do container no host | root | mapeado | mapeado |
| Socket privilegiado | /var/run/docker.sock (root) | $XDG_RUNTIME_DIR/docker.sock | Nenhum |
| Capabilities padrão | Amplas | Reduzidas | Mínimas |
| SELinux/AppArmor | Opcional | Opcional | Habilitado por padrão |
| Perfil Seccomp | Perfil padrão | Perfil padrão | Padrão mais restritivo |
| Se daemon comprometido | Acesso root completo | Acesso de usuário | N/A |
Pra times com requisitos de compliance (SOC 2, PCI-DSS, HIPAA), a postura de segurança do Podman simplifica muito a auditoria.
Compatibilidade CLI: A realidade do "alias docker=podman"
Uma das decisões mais inteligentes do Podman foi fazer a CLI praticamente 100% compatível com Docker:
# Adiciona no .bashrc/.zshrc alias docker=podman # E tudo isso funciona normalmente: docker pull nginx docker run -d -p 8080:80 nginx docker ps docker build -t myapp . docker push myregistry/myapp
O que funciona direto
docker run/build/pull/pushdocker ps/logs/execdocker images/rmidocker network create/ls/rmdocker volume create/ls/rm
O que não funciona
Docker Compose — Podman oferece podman-compose e suporta Docker Compose v2 via socket de compatibilidade:
# Opção 1: podman-compose (Python, mais simples) pip install podman-compose podman-compose up -d # Opção 2: socket compatível → Docker Compose v2 systemctl --user enable --now podman.socket export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock docker compose up -d
Docker Swarm — Podman não suporta. Se você usa Swarm (cada vez mais raro), é blocker total.
Docker-in-Docker (DinD) — Comum em CI/CD, mas no Podman é diferente:
# Docker: precisa de privileged docker run --privileged -v /var/run/docker.sock:/var/run/docker.sock docker # Podman: rootless, sem privileged podman run --security-opt label=disable \ -v $XDG_RUNTIME_DIR/podman/podman.sock:/var/run/docker.sock \ docker
Features do Docker Desktop — GUI, Kubernetes integrado, Extensions e Dev Environments não têm equivalente direto no Podman. Podman Desktop cobre parte, mas não é a mesma coisa.
Kubernetes: A vantagem real do Podman
Aqui o Podman tem algo que Docker não consegue replicar por design.
Suporte nativo a Pods
Podman trabalha com pods — grupos de containers que compartilham network namespace, igual ao Kubernetes — como cidadãos de primeira classe:
# Criar um pod podman pod create --name webapp -p 8080:80 # Adicionar containers podman run -d --pod webapp --name frontend nginx podman run -d --pod webapp --name api node:20-slim # Ambos compartilham localhost # frontend acessa a API em localhost:3000
Isso é exatamente como o Kubernetes organiza containers. Docker não tem esse conceito — cada container vive no seu próprio network namespace.
Gerar YAML do Kubernetes
Dá pra exportar um pod rodando diretamente pra YAML compatível com Kubernetes:
# Gerar YAML de um pod em execução podman generate kube webapp > webapp.yaml cat webapp.yaml
# Gerado pelo Podman apiVersion: v1 kind: Pod metadata: name: webapp spec: containers: - name: frontend image: docker.io/library/nginx:latest ports: - containerPort: 80 hostPort: 8080 - name: api image: docker.io/library/node:20-slim
E funciona na direção inversa:
# Rodar YAML Kubernetes localmente podman play kube webapp.yaml # Derrubar podman play kube webapp.yaml --down
Esse workflow de podman play kube tem usos muito concretos:
- Desenvolvimento local que replica produção Kubernetes exatamente
- Testar manifests sem levantar cluster
- Migração gradual de Docker Compose pra Kubernetes
Docker e Kubernetes: a relação é indireta
A abordagem do Docker pro Kubernetes passa por ferramentas intermediárias:
# Docker Desktop inclui K8s single-node # Mas é um cluster K8s completo, não um conceito leve de pod # Converter Compose pra K8s precisa de ferramenta externa kompose convert -f docker-compose.yaml # → o output geralmente precisa de bastante edição manual
Docker Compose e Kubernetes são abstrações fundamentalmente diferentes. Compose define serviços, Kubernetes define workloads. A conversão sempre perde informação. O conceito de pod do Podman fecha essa lacuna nativamente.
Docker Compose vs Podman Compose: O que rola na prática
A maioria dos devs não roda container solto — orquestra vários containers com Compose. Aqui a migração fica interessante.
Docker Compose (v2)
Docker Compose v2 é maduro e com bastante rodagem em produção:
# docker-compose.yaml services: web: build: ./frontend ports: - "3000:3000" depends_on: - api - db environment: - API_URL=http://api:4000 api: build: ./backend ports: - "4000:4000" depends_on: db: condition: service_healthy environment: - DATABASE_URL=postgresql://postgres:secret@db:5432/myapp db: image: postgres:16 volumes: - pgdata:/var/lib/postgresql/data environment: - POSTGRES_PASSWORD=secret healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s timeout: 5s retries: 5 volumes: pgdata:
docker compose up -d docker compose logs -f docker compose down
As opções no Podman
Opção 1: podman-compose (Python, da comunidade):
pip install podman-compose podman-compose up -d
Simples e leve. Mas não cobre todas as features do Docker Compose v2 (healthcheck.condition, alguns modos de rede, profiles).
Opção 2: Docker Compose v2 via socket Podman (pra setups complexos):
# Levantar socket Docker-compatível do Podman systemctl --user start podman.socket # Apontar CLI pro Podman export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock # Docker Compose funciona normalmente docker compose up -d
Passando pela API compatível do Podman, a compatibilidade é total. É o caminho mais suave pra arquivos Compose complexos.
Opção 3: Quadlet (nativo do Podman, integrado com systemd):
# ~/.config/containers/systemd/webapp.container [Container] Image=docker.io/library/nginx:latest PublishPort=8080:80 Volume=webdata:/usr/share/nginx/html [Service] Restart=always [Install] WantedBy=default.target
systemctl --user daemon-reload systemctl --user start webapp.service
Quadlet define containers como unit files do systemd. Mais voltado pra produção que Compose, mas precisa reescrever a orquestração.
CI/CD: Integração em pipelines
CI/CD é a parte mais chatinha da migração, porque quase toda infra CI foi construída pensando em Docker.
GitHub Actions
Docker (padrão):
jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build image run: docker build -t myapp:${{ github.sha }} . - name: Push to registry run: | echo ${{ secrets.REGISTRY_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin docker push ghcr.io/${{ github.repository }}/myapp:${{ github.sha }}
Podman (substituição direta):
jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build image run: podman build -t myapp:${{ github.sha }} . - name: Push to registry run: | podman login ghcr.io -u ${{ github.actor }} -p ${{ secrets.REGISTRY_TOKEN }} podman push ghcr.io/${{ github.repository }}/myapp:${{ github.sha }}
Podman vem pré-instalado nos runners ubuntu-latest do GitHub. Literalmente troca o nome do comando e pronto.
GitLab CI
GitLab CI tradicionalmente usa DinD (Docker-in-Docker), que precisa de modo privilegiado:
Docker (precisa de privileged):
build: image: docker:latest services: - docker:dind variables: DOCKER_TLS_CERTDIR: "/certs" script: - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA . - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
Podman (sem privileged):
build: image: quay.io/podman/stable script: - podman build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA . - podman push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
Não precisar de --privileged elimina uma superfície de ataque importante no CI. Mudança silenciosa mas de peso.
Buildah: builds especializados
O ecossistema do Podman inclui o Buildah, ferramenta dedicada a construir imagens com capacidades que docker build não tem:
# Build from scratch: sem imagem base, superfície de ataque mínima container=$(buildah from scratch) buildah copy $container ./static-binary /app buildah config --entrypoint '["/app"]' $container buildah commit $container myapp:minimal # → imagem sem pacotes, sem shell, só o binário
# Controle no nível de cada camada buildah run $container -- pip install -r requirements.txt buildah run $container -- pip cache purge buildah commit $container myapp:optimized
Buildah é especialmente útil em ambientes com segurança rigorosa, porque nunca levanta daemon e consegue buildar imagens sem runtime de container nenhum.
Benchmarks: Os números que importam
Vamos ao que realmente faz diferença no dia a dia:
Startup
Início de container (nginx, Alpine, SSD):
Docker: ~0.8-1.2s (daemon já rodando)
Podman: ~0.5-0.9s (fork-exec, sem daemon)
Primeiro container depois do boot:
Docker: ~2-4s (tem que esperar o daemon)
Podman: ~0.5-0.9s (não tem daemon pra esperar)
Podman ganha no cold-start. Em servidores long-running onde o daemon já tá de pé, a diferença é irrelevante.
Build
Build de imagem (Node.js multi-stage, cache frio):
Docker BuildKit: ~45-60s
Podman (Buildah): ~48-65s
Cache quente:
Docker BuildKit: ~3-5s
Podman (Buildah): ~3-5s
Praticamente igual. BuildKit tem leves vantagens em cache pra builds multi-stage complexos, mas a diferença raramente passa dos 10%.
Memória
Consumo idle:
Docker daemon: ~50-100MB (sempre rodando)
Podman: ~0MB (nada roda em idle)
Por container:
Docker: ~5-10MB (conmon + shim)
Podman: ~3-8MB (só conmon)
Custo zero em idle pesa em máquinas de dev e runners CI. Num servidor de produção com 50+ containers, o overhead por container é quase idêntico.
Pull de imagens
nginx:latest (comprimido ~70MB):
Docker: ~4-6s
Podman: ~4-6s
Imagem ML grande (~5GB):
Docker: ~45-90s
Podman: ~45-90s
Sem diferença relevante. Mesmo protocolo OCI, mesma velocidade.
Docker Desktop vs Podman Desktop
Pra devs em macOS e Windows, a experiência desktop importa:
Docker Desktop
- Custo: grátis pra uso pessoal, educação e empresas <250 funcionários com faturamento <24/mês/usuário pro resto (Business tier)
- Kubernetes: cluster single-node integrado
- Extensions: marketplace com 100+ extensões
- Dev Environments: ambientes remotos estilo Codespaces
- VM: gerenciamento automático de VM Linux em macOS/Windows
- Recursos: GUI pra limites de CPU/memória
- Volumes: GUI pra inspeção e gerenciamento
Podman Desktop
- Custo: grátis, open-source (Apache 2.0)
- Kubernetes: integração Kind/Minikube (não integrado)
- Extensions: sistema de plugins crescendo
- VM: gerenciamento automático via
podman machine - Recursos: controles básicos de CPU/memória
- Pods: UI de primeira classe pra criar e gerenciar pods
Pra devs solo e times pequenos, Podman Desktop compete bem. Pra times maiores que dependem das Extensions, Dev Environments ou features enterprise do Docker Desktop (SSO, gestão de acesso a imagens, Hardened Desktop), Docker ainda leva vantagem.
Playbook de migração: De Docker pra Podman
Se decidiu migrar, essa é a ordem que funciona melhor:
Fase 1: Desenvolvimento local (Semana 1-2)
# 1. Instalar # macOS: brew install podman podman machine init podman machine start # Linux (Ubuntu/Debian): sudo apt install podman # 2. Alias (não quebra nada, Docker continua funcionando) echo 'alias docker=podman' >> ~/.zshrc source ~/.zshrc # 3. Testar workflows existentes docker pull your-registry/your-app:latest docker run -d -p 3000:3000 your-registry/your-app:latest # 4. Testar compatibilidade Compose systemctl --user start podman.socket export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock docker compose up -d
Fase 2: Pipeline CI/CD (Semana 3-4)
# Job paralelo ao build Docker existente pra validar sem quebrar nada build-podman: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build with Podman run: | podman build -t myapp:${{ github.sha }} . podman push ghcr.io/${{ github.repository }}/myapp:${{ github.sha }}
Fase 3: Produção (Semana 5+)
# Gerar serviços systemd dos containers podman generate systemd --new --files --name webapp # Instalar e ativar cp container-webapp.service ~/.config/systemd/user/ systemctl --user enable --now container-webapp.service # Ou use Quadlet (veja a seção acima)
Pegadinhas da migração
- Permissões de volume: modo rootless mapeia UIDs diferente. Pode precisar de
podman unshare chownpra volumes montados - Bind de porta: rootless não consegue bindar portas abaixo de 1024 sem
sysctl net.ipv4.ip_unprivileged_port_start=0 - Modos de rede:
--network=hostfunciona diferente em rootless - Mount do socket: ferramentas que montam
/var/run/docker.sockprecisam apontar pro socket do Podman
Framework de decisão: Docker vs Podman em 2026
Sem enrolação, concreto:
Fica com Docker se:
- Teu time tem menos de 250 pessoas (faturamento <$10M) e Docker Desktop é grátis. O ecossistema pesa
- Depende de Docker Swarm. Podman não tem alternativa
- Teus pipelines usam features Docker-específicas (cache mounts avançados do BuildKit, Compose completo em testes, DinD) e trocar tem custo alto
- Usa Extensions do Docker Desktop no dia a dia (scan de vulnerabilidades, explorador de logs, ferramentas de DB)
- Time trabalha em macOS/Windows e precisa da experiência polida do Docker Desktop
Muda pro Podman se:
- Compliance de segurança é prioridade. Rootless por padrão, sem daemon privilegiado, capabilities mínimas — postura significativamente mais forte
- Tá pagando Docker Desktop com time grande. 28.800/ano. Podman Desktop é grátis
- Mira em Kubernetes e quer desenvolvimento local refletindo produção. O conceito de pod e
podman play kubesão ferramentas genuinamente úteis - Roda em servidores Linux e quer gerenciamento nativo com systemd (Quadlet)
- Precisa de builds rootless no CI. Buildar sem privileged é melhoria real de segurança
- Eficiência de recursos importa (runners compartilhados, laptops de dev). Zero overhead de daemon idle soma
Abordagem híbrida (o mais comum)
A realidade: a maioria dos times não migra da noite pro dia.
- Podman nos servidores Linux — rootless, systemd, sem licensing
- Docker Desktop nas máquinas de dev — UX polida, extensions, onboarding fácil
- Podman no CI/CD — sem containers privilegiados, pré-instalado nos runners GitHub
O padrão OCI garante imagens 100% intercambiáveis, então esse mix funciona sem atrito.
Olhando pra frente: 2026 e além
O ecossistema de containers converge em padrões e diverge em implementação.
Padronização OCI tá pronta. Imagens, runtimes e specs de distribuição são maduros. Docker e Podman buildam e rodam as mesmas imagens. A era "funciona no Docker, quebra no Podman" ficou pra trás.
Containers WebAssembly (Wasm) tão aparecendo como tecnologia complementar. Docker (via runwasi) e Podman (via crun-wasm) conseguem rodar workloads Wasm junto com containers Linux tradicionais. Iniciam em milissegundos, usam fração da memória e oferecem sandboxing mais forte. Não vão substituir containers Linux, mas vão pegar uma fatia crescente de workloads leves.
Rootless como padrão tá virando norma na indústria. Docker vem melhorando o modo rootless a cada release. A filosofia do Podman — rootless e sem daemon por padrão — tá ganhando o argumento arquitetural, independente de qual ferramenta você usa.
Dev Containers e ambientes de desenvolvimento baseados em containers continuam amadurecendo. Docker (via spec Dev Containers) e Podman (via Podman Desktop) suportam esse padrão. Se o futuro do desenvolvimento é containers do começo ao fim, a escolha do runtime fica ainda mais importante.
Conclusão
A resposta honesta: depende do que você tá otimizando, mas tá menos ambíguo do que dois anos atrás.
Se segurança, custo e alinhamento com Kubernetes são prioridade, Podman é a escolha mais forte em 2026. Rootless por padrão, zero overhead de daemon, suporte nativo a pods — são vantagens técnicas genuínas que Docker vem correndo atrás.
Se maturidade do ecossistema, experiência desktop em macOS/Windows e inércia do tooling pesam mais, Docker segue como padrão pragmático. O ecossistema é maior, o desktop mais polido, e tem mais tutoriais, respostas no Stack Overflow e templates CI que assumem Docker.
A boa notícia: como as duas seguem OCI, não tem lock-in. Dá pra começar com Docker, usar Podman no CI, botar Podman em produção e manter Docker Desktop pro dev local. Imagens, registries e Dockerfiles (sim, Podman builda Dockerfiles) são os mesmos.
O mundo dos containers se dividiu não por incompatibilidade, mas por filosofia: daemon centralizado vs daemonless, root por padrão vs rootless por padrão, produto comercial vs projeto comunitário. Em 2026, as duas filosofias entregam resultados de nível produção. Sua escolha deveria refletir suas restrições e prioridades, não qual ferramenta tem mais torcida no Twitter.
Escolhe um, bota containers pra rodar, e foca no que realmente é difícil: o código dentro deles.
Explore ferramentas relacionadas
Experimente estas ferramentas gratuitas do Pockit