Podman Quadlet: Contentores Geridos pelo systemd na PME

O Podman Quadlet permite gerir contentores como unidades nativas do systemd, usando ficheiros declarativos .container, .volume e .network. Para uma PME que precisa de serviços estáveis com reinício automático, dependências entre contentores e integração com o ciclo de vida do sistema, o Quadlet é mais limpo que scripts manuais ou podman generate systemd.

ℹ O Quadlet substitui o podman generate systemd — ficheiros .container são mais simples e declarativos que unidades systemd manuais.

⚠ Os ficheiros Quadlet devem estar em ~/.config/contentores/systemd/ (utilizador) ou /etc/contentores/systemd/ (sistema).

Neste artigo

1. Introdução ao Quadlet

O Quadlet é o mecanismo nativo do Podman para integrar contentores com o systemd. Em vez de gerar unidades systemd manualmente (o antigo podman generate systemd, agora descontinuado), o administrador escreve ficheiros INI com extensões .container, .volume, .network, .kube ou .pod. O Quadlet converte esses ficheiros em unidades systemd reais durante o daemon-reload.

As vantagens para uma PME são concretas: reinício automático em caso de falha, dependências entre serviços (por exemplo, a base de dados arrancar antes da aplicação), gestão centralizada via systemctl e integração com o diário do sistema para registos. Tudo isto sem instalar o serviço Docker.

O Quadlet está disponível a partir do Podman 4.4 ( Janeiro de 2023) e é a forma recomendada pela documentação oficial para gerir contentores em produção com systemd. Para detalhes completos da sintaxe, consultar a página de manual do podman-systemd.unit.

2. Ficheiros .container

O ficheiro .container é o bloco fundamental do Quadlet. Define a imagem, portas, volumes e opções de execução do contentor. A secção [Contentor] descreve o contentor. A secção [Service] controla o comportamento do systemd (reinício, tempo limite, dependências).

# Criar ficheiro .container
mkdir -p ~/.config/containers/systemd
cat > ~/.config/containers/systemd/web.container << 'EOF'
[Container]
Image=docker.io/nginx:alpine
ContainerName=web
PublishPort=8080:80
Volume=web-data:/usr/share/nginx/html:Z
Exec=nginx -g 'daemon off;'
[Service]
Restart=always
TimeoutStartSec=60
EOF
# Recarregar systemd
systemctl --user daemon-reload
systemctl --user start web
systemctl --user status web

Os campos principais da secção [Contentor] incluem:

Campo Descrição
Image Imagem do repositório (ex: docker.io/nginx:alpine)
ContainerName Nome do contentor (usado como nome da unidade systemd)
PublishPort Mapeamento de portas host:contentor
Volume Montagem de volume nomeado ou caminho (com :Z para SELinux)
Exec Comando de entrada (substitui ENTRYPOINT)
Environment Variáveis de ambiente (ex: TZ=Europe/Lisbon)

3. Ficheiros .volume e .network

Para volumes e redes persistentes, o Quadlet oferece ficheiros dedicados. Um ficheiro .volume cria um volume nomeado gerido pelo Podman. Um ficheiro .network define uma rede personalizada. Ambos são convertidos em unidades systemd que arrancam antes dos contentores que delas dependem.

# Ficheiro .volume
# web-data.volume:
[Volume]
VolumeName=web-data

# Ficheiro .network
# mynet.network:
[Network]
NetworkName=mynet

No ficheiro .container, referenciar o volume e a rede pelo nome do ficheiro (sem extensão). O Quadlet resolve automaticamente a dependência:

# app.container com volume e rede
[Container]
Image=docker.io/nginx:alpine
ContainerName=app
Volume=web-data:/usr/share/nginx/html:Z
Network=mynet.network
PublishPort=8080:80

O systemd garante que o volume web-data.volume e a rede mynet.network arrancam antes do contentor app, sem configuração manual de Requires= ou After=.

4. Gestão com systemctl

Depois de colocar os ficheiros Quadlet no directório correcto e fazer daemon-reload, o contentor é gerido como qualquer unidade systemd. O nome da unidade deriva do nome do ficheiro (sem a extensão .container).

# Recarregar unidades systemd
systemctl --user daemon-reload

# Iniciar o contentor
systemctl --user start web

# Verificar estado
systemctl --user status web

# Parar e desactivar
systemctl --user stop web
systemctl --user disable web

# Activar arranque no arranque
systemctl --user enable web

# Ver registos (journal)
journalctl --user -u web -f

Em modo rootless (utilizador normal), é necessário activar a persistência para que os serviços do utilizador arranquem sem sessão activa:

# Activar lingering para o utilizador
sudo loginctl enable-linger $USER

# Verificar
loginctl show-user $USER | grep Linger

5. Implantação de Serviços

Um cenário típico de PME: um servidor web nginx com uma base de dados PostgreSQL. Com Quadlet, define-se cada serviço num ficheiro separado e declara-se a dependência. O ficheiro db.container arranca primeiro. O web.container depende dele via Requires= e After= na secção [Unit].

# db.container
[Container]
Image=docker.io/postgres:16-alpine
ContainerName=db
Volume=db-data:/var/lib/postgresql/data:Z
Network=mynet.network
Environment=POSTGRES_PASSWORD=segredo
Environment=POSTGRES_DB=appdb

# web.container
[Unit]
Requires=db-container.service
After=db-container.service

[Container]
Image=docker.io/nginx:alpine
ContainerName=web
Volume=web-data:/usr/share/nginx/html:Z
Network=mynet.network
PublishPort=8080:80

[Service]
Restart=always
RestartSec=5

O nome da unidade gerada pelo Quadlet segue o padrão nome-container.service. Por isso, no Requires= usa-se db-container.service e não db.service.

6. Quadlet vs docker-compose vs podman generate

Existem três abordagens comuns para gerir contentores em servidores Linux. Cada uma tem um propósito distinto:

Método Vantagens Desvantagens
Quadlet Nativo systemd, políticas de reinício, dependências, sem serviço de fundo Requer Podman 4.4+, sintaxe INI menos familiar
docker-compose Sintaxe YAML conhecida, ecossistema amplo Precisa de serviço Docker (ou podman-compose), sem integração systemd nativa
podman generate systemd Gera .service a partir de contentor existente Descontinuado, ficheiros gerados difíceis de manter

Para uma PME que já usa systemd como sistema de init (a maioria das distribuições modernas), o Quadlet é a opção mais integrada. O artigo sobre Docker Compose na PME cobre a abordagem alternativa com YAML. Mais sobre contentores e orquestração no Curso Linux Dia 22 e na abordagem com Nomad (artigo 18366).

7. Erros Comuns e Lista de Verificação

Os problemas mais frequentes ao migrar para Quadlet resultam de pequenos detalhes de sintaxe ou localização dos ficheiros:

  • Directório errado: ficheiros fora de ~/.config/contentores/systemd/ não são detectados.
  • Esquecer o daemon-reload: sem systemctl --user daemon-reload o systemd não vê os ficheiros novos.
  • Persistência desactivada: contentores rootless não arrancam no boot sem loginctl enable-linger.
  • Nome de unidade incorrecto: usar db.service em vez de db-container.service em dependências.
  • SELinux sem :Z: volumes sem a opção :Z podem falhar em sistemas com SELinux activo.

Para diagnosticar erros de conversão do Quadlet, o comando /usr/libexec/podman/quadlet --dryrun (ou /usr/lib/podman/quadlet --dryrun em algumas distribuições) mostra as unidades systemd geradas sem as aplicar.

# Pré-validar ficheiros Quadlet
/usr/libexec/podman/quadlet --dryrun --user

# Ver unidades geradas
ls ~/.config/systemd/user/*container*.service

Lista de verificação antes de produção:

  • ✓ Ficheiros Quadlet no directório correcto (utilizador ou sistema)
  • daemon-reload executado após criar ou alterar ficheiros
  • ✓ Persistência activada para rootless (loginctl enable-linger)
  • ✓ Dependências declaradas em [Unit] com Requires= e After=
  • Restart=always na secção [Service] para reinício automático
  • ✓ Volumes com opção :Z em sistemas SELinux
  • --dryrun executado para validar conversão
  • ✓ Registos confirmados com journalctl --user -u nome

O Quadlet é a forma recomendada pela documentação do Podman e pela Arch Wiki para integrar contentores com systemd. Para PMEs que já administram servidores com systemd, reduz a complexidade operacional e elimina a dependência do Docker daemon.