O que é o Podman
A linha de comando do Podman é muito parecida com a do Docker; a maior diferença é que ele não tem um daemon residente. O Docker depende de um dockerd que roda constantemente como root para gerenciar os contêineres; o Podman não tem esse papel. Isso traz duas consequências diretas: os contêineres podem ser criados e executados por usuários comuns (modo rootless), e também podem ser entregues ao systemd para serem gerenciados como serviços.
O Podman também tem alguns subcomandos que o Docker não tem, como pod (grupo de contêineres), kube, quadlet e auto-update; os dois últimos serão usados adiante.
Instalação no Ubuntu 26.04
sudo apt install podman
Em um contêiner Ubuntu 26.04.1 LTS (arm64), instalei o podman 5.7.0. O mesmo repositório também tem podman-compose (1.5.0), podman-docker, buildah, skopeo, crun e netavark. Executando podman info como root, ele mostra Rootless como false, o driver de armazenamento overlay, o runtime crun e o backend de rede netavark.
Verificando:
podman --version
podman run --rm docker.io/library/alpine:3.20 echo hello-from-podman
Se a saída for hello-from-podman, é possível executar contêineres. Escrevi o nome da imagem completo, docker.io/library/alpine:3.20, porque incluir o domínio do repositório é o que menos deixa margem a ambiguidade. Uma observação sobre meu ambiente de teste: testei de forma aninhada dentro de outro contêiner Docker; por causa das restrições de cgroup, precisei de um parâmetro extra para funcionar, o que você não vai precisar em um host real.
Se você sabe usar docker, sabe usar podman
Os subcomandos listados em podman --help cobrem praticamente os que o Docker usa no dia a dia: build, run, create, start, stop, restart, rm, ps, images, rmi, pull, push, logs, exec, inspect, cp, port, stats, top, volume, network, secret, entre outros. O podman run também suporta -p/--publish, -v/--volume, --userns, e o --restart pode assumir os valores always, no, never, on-failure, unless-stopped.
Um ponto de atenção: podman ps só mostra os contêineres criados pelo usuário atual. Contêineres criados por um usuário comum não são visíveis para outros usuários, nem para o Podman executado como root. Diante da pergunta "para onde foi o contêiner", confirme primeiro com qual usuário o comando foi executado.
Duas formas de transição
Instalar podman-docker. Depois de instalar esse pacote, /usr/bin/docker é um script shell bem curto: ele primeiro verifica se /etc/containers/nodocker (ou ~/.config/containers/nodocker) existe; se não existir, escreve na saída de erro a linha Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg. e então faz exec /usr/bin/podman "$@". Por isso, docker --version na verdade exibe podman version 5.7.0. Se achar o aviso irritante, basta criar esse arquivo:
sudo apt install podman-docker
sudo touch /etc/containers/nodocker
Ele apenas repassa o comando ao Podman. Cada subcomando e parâmetro docker usado nos seus scripts precisa ser testado por você para ver se tem correspondência no Podman; programas que dependem da API do daemon do Docker (como docker.sock) não foram verificados por mim.
Usar podman compose. O podman compose não implementa compose por conta própria; a ajuda diz que ele executa por meio de um provedor externo, como docker-compose ou podman-compose. Ao executar podman compose version no contêiner, ele primeiro imprimiu o caminho do provedor externo que estava chamando e depois exibiu o número de versão do próprio provedor (Docker Compose version 2.40.3+ds1-0ubuntu1). Portanto, antes de usá-lo, a máquina precisa ter um provedor de compose instalado.
Preparação para o modo rootless: subuid e subgid
Ao executar o Podman como usuário comum, ele cria automaticamente um namespace de usuário para esse usuário, e os intervalos disponíveis estão escritos em /etc/subuid e /etc/subgid. A página de manual exige: o usuário precisa ter múltiplos intervalos de UID/GID nesses dois arquivos. O método de adição indicado pelo manual:
sudo usermod --add-subuids 10000-75535 nome-do-usuário
sudo usermod --add-subgids 10000-75535 nome-do-usuário
Os locais de dados do rootless também são diferentes dos do root: a configuração é lida de $XDG_CONFIG_HOME, ou de ~/.config/containers quando não definida; as imagens ficam em $XDG_DATA_HOME, ou em ~/.local/share/containers/storage quando não definido; os dados temporários vão em ${XDG_RUNTIME_DIR}/containers. Para diagnosticar problemas de rootless, comece por esses diretórios.
Usando o Quadlet para que contêineres iniciem com o sistema
O podman generate systemd já aparece marcado como [DEPRECATED] na ajuda do 5.7.0. A abordagem atual é o Quadlet: ele é o gerador de systemd do Podman, lê arquivos .container, .volume, .network, .build, .pod, .kube, .artifact e gera um .service de mesmo nome para cada arquivo. Esses arquivos são lidos no boot e ao executar systemctl daemon-reload, tanto no systemd em nível de sistema quanto em nível de usuário.
Onde colocar. Os caminhos de busca para root, em ordem de prioridade, são: /run/containers/systemd/ (temporário, para testes), /etc/containers/systemd/ (definidos pelo administrador) e /usr/share/containers/systemd/ (definidos pela distribuição). Para usuários comuns, são $XDG_RUNTIME_DIR/containers/systemd/, ~/.config/containers/systemd/ e os diretórios sob /etc/containers/systemd/users/.
Como escrever. Abaixo está um exemplo que realmente usei, salvo como /etc/containers/systemd/web.container:
[Unit]
Description=Demo web server
[Container]
Image=docker.io/library/nginx:1.27-alpine
PublishPort=8080:80
AutoUpdate=registry
[Service]
Restart=always
[Install]
WantedBy=default.target
A seção [Container] usa a sintaxe própria do Quadlet: Image= especifica a imagem e PublishPort= corresponde ao --publish do podman run. As seções [Service], [Install] e afins são passadas ao systemd sem alterações, então Restart=always funciona como em qualquer serviço systemd escrito normalmente.
O que foi gerado. Não é preciso escrever o arquivo de serviço à mão; para ver o resultado gerado, use o dry-run, que apenas imprime, sem instalar:
/usr/lib/systemd/system-generators/podman-system-generator --dryrun
Para o arquivo acima, o web.service que ele gera tem como ExecStart:
/usr/bin/podman run --name systemd-%N --replace --rm --cgroups=split --sdnotify=conmon -d --label io.containers.autoupdate=registry --publish 8080:80 docker.io/library/nginx:1.27-alpine
Ele também adiciona Type=notify, Delegate=yes, KillMode=mixed, o ExecStop é /usr/bin/podman rm -v -f -i systemd-%N, e o [Unit] ganha After=network-online.target. Daí dá para tirar três conclusões: o nome do contêiner é fixado como systemd-<nome-da-unidade>; o contêiner leva --rm, então assim que o serviço para o contêiner é removido, sem deixar uma pilha de contêineres finalizados; e o AutoUpdate=registry se transforma na etiqueta io.containers.autoupdate=registry, que é o interruptor da atualização automática.
Esse resultado gerado foi o que validei com o dry-run. Meu ambiente de teste não tinha systemd em execução, portanto nunca executei de fato o systemctl para iniciá-lo. O procedimento padrão é sudo systemctl daemon-reload seguido de sudo systemctl start web.service; se o contêiner não subir, veja os logs com journalctl -u web.service. Para ver os contêineres criados por unidades em nível de sistema, execute sudo podman ps como root — e não esqueça o que foi dito antes: contêineres de usuários diferentes não são visíveis entre si.
Há ainda o grupo de subcomandos podman quadlet — install, list, print, rm — usado para gerenciar esses arquivos em si.
Atualização automática
A ajuda do podman auto-update diz que ele trata de contêineres executados por unidades systemd, com a política de atualização especificada pela etiqueta io.containers.autoupdate. É exatamente essa etiqueta que o AutoUpdate=registry acima gera. Disparando manualmente uma vez:
sudo podman auto-update
O sudo é necessário porque os contêineres criados por unidades em nível de sistema pertencem ao root. O significado completo da política registry, e como fazer com que ela execute periodicamente, não foram aprofundados por mim; consulte man podman-auto-update.
Algumas dúvidas comuns
- O comando docker exibe uma linha extra de aviso a cada execução: crie
/etc/containers/nodocker(para todos os usuários) ou~/.config/containers/nodocker(para o usuário atual). - podman compose não encontra provedor: instale primeiro
podman-composeou docker-compose. - Contêiner rootless não inicia: verifique se o usuário atual tem múltiplos intervalos em
/etc/subuide/etc/subgid. - Alteração no arquivo .container não surtiu efeito: os arquivos Quadlet só são lidos no boot e no
daemon-reload; depois de alterar, rode primeirosudo systemctl daemon-reloade depois reinicie o serviço correspondente.



