← Voltar para o Blog

Podman e containers sem root: vale trocar o Docker?

Rodar container sem daemon e sem privilégio elimina uma classe inteira de risco. A compatibilidade é alta, a migração é curta — e há três diferenças que decidem se compensa.

Equipe EasyOps Cloud · · 7 min de leitura

Existe uma característica do Docker que raramente é examinada: o daemon roda como root, e quem pertence ao grupo docker fala com ele. Na prática, estar nesse grupo equivale a ter root na máquina — basta subir um container montando o disco inteiro.

Isso não é falha; é decorrência do desenho. Mas é uma concentração de privilégio que incomoda em ambiente com várias pessoas, e é o principal argumento do Podman.

As três diferenças que importam

Sem daemon. O Podman executa o container como processo filho do seu comando. Não há serviço central rodando, nem ponto único que, se cair, leva todos os containers junto.

Sem privilégio. Cada usuário roda os próprios containers, sem grupo especial e sem root. O root dentro do container é mapeado para o seu usuário comum fora dele.

Integração nativa com systemd. Um container vira uma unit de verdade, com Restart, dependências, limites de recurso e log no journal — os mesmos recursos descritos no artigo sobre escrever units.

A compatibilidade de comandos é alta o bastante para que o alias resolva boa parte:

alias docker=podman
podman run -d --name web -p 8080:80 nginx:alpine
podman ps
podman logs web

Ele usa as mesmas imagens e os mesmos registros. Não há formato proprietário.

O que muda ao rodar sem privilégio

Quatro diferenças aparecem no primeiro dia, e todas têm solução conhecida.

Portas abaixo de 1024 não são acessíveis a usuário comum. O padrão é publicar em porta alta e deixar um proxy reverso na frente — o que você provavelmente já faz. Se precisar mesmo:

sudo sysctl net.ipv4.ip_unprivileged_port_start=80

Mapeamento de usuários precisa estar configurado. É o que permite o container ter root interno sem root real:

grep "^$USER:" /etc/subuid /etc/subgid
# se vazio:
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER
podman system migrate

Dono dos arquivos em volume fica diferente do esperado. Um arquivo criado pelo container aparece no host pertencendo a um UID alto da faixa mapeada. O podman tem uma opção que resolve:

podman run -v /dados:/dados:U minha-imagem

Rede é em espaço de usuário, o que custa um pouco de desempenho em cenários de tráfego muito alto. Para a maioria das aplicações, a diferença é imperceptível.

Container como serviço, que é o ponto forte

Aqui o Podman entrega algo que o Docker não tem com a mesma elegância. Em vez de depender da política de reinício do daemon, o container vira uma unit:

# ~/.config/containers/systemd/api.container
[Unit]
Description=API do MeuApp

[Container]
Image=meuregistro/minha-api:1.4
PublishPort=8080:3000
EnvironmentFile=/etc/meuapp/env
Volume=dados-api:/dados
Memory=1G

[Service]
Restart=always

[Install]
WantedBy=default.target
systemctl --user daemon-reload
systemctl --user start api
journalctl --user -u api -f

O arquivo é lido pelo systemd, que gera a unit automaticamente. Você ganha dependências entre serviços, limites de recurso via cgroups, log no journal e reinício gerenciado — sem nenhuma camada extra.

Para que os serviços do usuário subam no boot, sem ninguém logado:

sudo loginctl enable-linger $USER

Esquecer essa linha é o tropeço mais comum: tudo funciona até o primeiro reinício, e então os containers não voltam.

Compose e pods

Se hoje você usa compose, há dois caminhos.

O primeiro é manter o arquivo, usando a implementação compatível:

sudo apt install podman-compose
podman-compose up -d

Funciona para a maior parte dos arquivos, com arestas em recursos menos comuns.

O segundo, e melhor a médio prazo, é migrar para units. A tradução é direta e o resultado é mais robusto:

podman generate systemd --new --name api > ~/.config/systemd/user/api.service

O Podman também tem o conceito de pod — um grupo de containers compartilhando rede, que se enxergam por localhost:

podman pod create --name meuapp -p 8080:3000
podman run -d --pod meuapp --name db postgres:16
podman run -d --pod meuapp --name api minha-api:1.4

Para quem pretende usar Kubernetes um dia, o vocabulário é o mesmo — e o Podman gera manifesto compatível com podman generate kube. Para quem não pretende, é apenas uma forma conveniente de agrupar.

Onde a migração costuma travar

Vale conhecer antes de decidir:

  • Ferramentas que falam com o socket do Docker. Agente de monitoramento, sistema de implantação e qualquer coisa que use a API. O Podman oferece um socket compatível, mas nem tudo funciona igual:
systemctl --user enable --now podman.socket
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock
  • Docker Swarm, que não tem equivalente.
  • Imagem que exige privilégio real — algumas ferramentas de rede e armazenamento.
  • Documentação e respostas de fórum, que assumem Docker. Você vai traduzir mais do que gostaria no começo.
  • Conhecimento da equipe. É custo real, ainda que a curva seja curta.

Vale a troca?

Depende de qual problema você tem.

Compensa quando várias pessoas rodam containers na mesma máquina e você não quer distribuir o equivalente a root; quando a política de segurança exige que nada rode privilegiado; quando os serviços já são gerenciados por systemd e ter containers no mesmo modelo simplifica; ou em ambiente RHEL e derivados, onde o Podman é o padrão suportado.

Não compensa quando há um único operador de confiança na máquina, o Docker funciona e a equipe já o domina. Trocar ferramenta que funciona por outra equivalente custa tempo e rende pouco.

Vale notar que o Docker também suporta modo sem privilégio hoje. Se o incômodo é apenas esse, dá para resolver sem trocar:

dockerd-rootless-setuptool.sh install

O argumento remanescente do Podman é a ausência de daemon e a integração com systemd, não mais a exclusividade do modo sem root.

Uma recomendação prática

Para operação existente e estável, não há urgência. Os ganhos são reais e incrementais, e migrar por migrar consome tempo que rende mais em outro lugar — na rotina de restauração testada, por exemplo, que tem retorno bem maior.

Para máquina nova, ou para quando o assunto "quem tem acesso ao Docker é root" aparecer numa auditoria, aí vale começar por ele. Em RHEL, AlmaLinux e Rocky, é o caminho que a distribuição já toma.

E independentemente da escolha, vale aplicar o que o artigo sobre Docker em produção descreve: limite de memória, rotação de log, política de reinício e usuário sem privilégio dentro do container. Essas medidas valem para os dois, e resolvem mais incidentes do que a escolha entre uma ferramenta e outra.

Como testar sem compromisso

A avaliação custa pouco, e não exige remover nada. Os dois convivem na mesma máquina, com armazenamentos separados:

sudo apt install podman
podman run --rm hello-world
podman info | grep -E 'rootless|graphRoot'

O rootless: true confirma que está rodando sem privilégio. O graphRoot apontando para dentro do seu diretório pessoal mostra que as imagens ficam separadas das do Docker — nada é compartilhado, e nada é sobrescrito.

Um teste representativo leva uma tarde: suba um serviço secundário com Podman, converta para unit, e opere assim por algumas semanas. As diferenças que importam — permissão em volume, publicação de porta, comportamento no reinício — aparecem nesse uso real, e não em uma comparação de tabela.

Se a experiência for boa, a migração dos demais serviços passa a ser mecânica. Se não for, você desinstala e não perdeu nada além do tempo do teste.

O que a discussão realmente revela

Vale um passo atrás. O debate entre as duas ferramentas costuma girar em torno de recursos, e o ponto de fundo é outro: quanto privilégio a sua operação distribui sem perceber?

Grupo docker equivalente a root é o exemplo mais visível, e não é o único. Chave de acesso ao bucket com permissão de exclusão, conta de serviço com shell válido, sudo irrestrito para quem só precisa reiniciar um serviço — todos são a mesma categoria de problema, tratada nos artigos sobre usuários e sudo e ransomware.

Trocar de ferramenta de container resolve um item dessa lista. Fazer a lista inteira, e revisá-la periodicamente, resolve a categoria — e costuma render mais que qualquer migração isolada.

Se a troca por Podman servir de gatilho para essa revisão mais ampla, ela já valeu independentemente do resultado final.

Um detalhe de operação que costuma pegar

Uma diferença prática que aparece cedo e confunde quem vem do Docker: as imagens e os containers de cada usuário são separados. Baixar uma imagem como você não a torna disponível para o serviço que roda com outro usuário, e um sudo podman ps não mostra os seus containers — mostra os do root, que é outro conjunto inteiro.

podman images              # os seus
sudo podman images         # os do root, separados
podman info | grep graphRoot

Isso é consequência direta do modelo sem privilégio e costuma explicar o "instalei e sumiu" do primeiro dia. A recomendação é decidir cedo sob qual usuário os serviços vão rodar — normalmente um usuário dedicado à aplicação, com linger habilitado — e manter tudo ali, em vez de alternar entre o seu usuário e o root conforme o comando.

Vale conferir também o espaço ocupado, que passa a viver no diretório pessoal em vez de /var/lib/docker. Uma cota apertada em /home produz um erro de "sem espaço" em lugar inesperado, e a limpeza segue a mesma lógica do artigo sobre disco cheio:

podman system df
podman system prune -a --filter 'until=168h'

Suba um servidor em minutos

Preço em real, suporte em português e dados no Brasil.

Criar conta