- Como o Podman não tem daemon, é preciso haver um responsável por iniciar os contêineres de forma confiável após o boot do servidor, e o Quadlet resolve isso no formato de arquivos de serviço do systemd
- O método antigo com
podman generate systemdexigia tratar separadamente a criação do contêiner e a geração do arquivo de serviço, além de trazer o custo de edição manual sempre que o arquivo gerado mudava - O Quadlet coloca, em um arquivo
.containerdentro de~/.config/containers/systemd, as configurações[Container],[Service]e[Install], permitindo gerenciar opções do Podman e o comportamento do systemd em um só lugar - No Podman rootless, para iniciar automaticamente no boot, são necessários
WantedBy=default.targete linger ativado;multi-user.targetnão é definido no modo de usuário - Com
AutoUpdate=registry, dependências do systemd, agrupamento de arquivos por diretório e até a ferramenta de conversãopodlet, o Quadlet se encaixa bem na operação do Podman rootless e sem daemon
Por que o Quadlet é necessário
- Quadlet é uma forma de executar contêineres Podman como serviços do systemd
- Permite executar contêineres em segundo plano
- Permite iniciar contêineres automaticamente após reinicializações do servidor
- A ideia de executar contêineres Podman sob o systemd não é nova
- Antes, usava-se o comando
podman generate systemd - Esse comando agora exibe um aviso de descontinuação recomendando migrar para o Quadlet
- Antes, usava-se o comando
- Como o Podman tem arquitetura daemonless, é necessário um responsável por iniciar os contêineres sem depender de um daemon
As limitações do método antigo com podman generate systemd
- No método antigo, primeiro era preciso criar o contêiner com
podman create- O contêiner de exemplo usa a imagem
docker.io/library/postgres:16 - Inclui
-p 5432:5432, montagem de volume, variável de ambientePOSTGRES_PASSWORDe o rótuloio.containers.autoupdate=registry
- O contêiner de exemplo usa a imagem
- Depois, executava-se
podman generate systemd test-db -fn --newpara gerar o arquivocontainer-test-db.service - O arquivo de serviço gerado era colocado em
~/.config/systemd/usere ativado/iniciado com o comando a seguirsystemctl --user enable --now container-test-db
- Esse fluxo fazia repetir criação do contêiner, geração do arquivo de serviço, movimentação do arquivo quando necessário e ativação do serviço
- Quando o comando de criação do contêiner ficava longo, era preciso gerenciar separadamente um script de shell para executá-lo novamente depois
- Para customizar o arquivo de serviço do systemd gerado, era necessário fazer edições manuais toda vez
Estrutura do arquivo Quadlet
- No modelo Quadlet, cria-se o diretório
~/.config/containers/systemde coloca-se dentro dele um arquivo.container - O arquivo de exemplo
test-db.containerinclui os seguintes elementos[Container]Image=docker.io/library/postgres:16AutoUpdate=registryPublishPort=5432:5432Volume=%h/volumes/test-db:/var/lib/postgresql/data:ZEnvironment=POSTGRES_PASSWORD=CHANGE_ME
[Service]Restart=always
[Install]WantedBy=default.target
- O arquivo
.containeré um arquivo de serviço normal do systemd, mas inclui uma seção especial[Container] - Muitas opções de
[Container]correspondem a opções de linha de comando usadas empodman createImage: imagem e tag a serem usadasAutoUpdate=registry: corresponde a--label "io.containers.autoupdate=registry"PublishPort: corresponde a-pVolume: corresponde a-vEnvironment: corresponde a-e
- No diretório home do usuário, deve-se usar o especificador do systemd
%hem vez de~ Restart=alwaysem[Service]faz o contêiner reiniciar sempre, a menos que seja parado manualmenteWantedBy=default.targetem[Install]faz o contêiner iniciar automaticamente no boot
Configurações do systemd necessárias no Podman rootless
- Em contêineres rootless, deve-se usar
default.targetem vez demulti-user.targetmulti-user.targetnão é definido no modo de usuário do systemd- Isso pode ser verificado com
systemctl --user status multi-user.target - No modo de sistema, pode-se verificar com
systemctl status multi-user.target
- Como o contêiner é executado como serviço de usuário do systemd, é preciso ativar o linger para que ele possa iniciar mesmo sem o usuário logado
loginctl enable-linger
- Se for necessário iniciar automaticamente após reinicialização do servidor, ativar o linger é obrigatório
- Para que o systemd detecte um novo arquivo de serviço, execute o seguinte comando
systemctl --user daemon-reload
- O início do contêiner e a verificação de status podem ser feitos tanto pelo systemd quanto pelo Podman
systemctl --user start test-dbsystemctl --user status test-dbpodman ps
- O nome padrão do contêiner recebe o prefixo
systemd-antes do nome do arquivo de serviço- O nome padrão do contêiner para
test-db.containerésystemd-test-db - Essa convenção evita conflitos
- Também é possível definir isso manualmente com a opção
ContainerNamena seção[Container]
- O nome padrão do contêiner para
Vantagens operacionais do Quadlet
- O Quadlet permite gerenciar a configuração do serviço de contêiner em um único arquivo
- Diferentemente do método antigo, não é preciso manter separadamente um script para gerar o arquivo de serviço e o próprio arquivo gerado
- É possível usar as opções disponíveis nas seções
[Unit]e[Service]do systemd- Por exemplo, é possível definir com
StartExecPreum comando a ser executado antes da inicialização do contêiner - Isso reduz a necessidade de editar manualmente arquivos gerados depois
- Por exemplo, é possível definir com
- Em vez de escrever e depurar scripts de shell, é possível operar contêineres com foco em arquivos de configuração
- Também fica mais fácil expressar dependências entre contêineres no estilo do systemd
Expressando dependências entre contêineres
- Se um contêiner de aplicação depende de um contêiner de banco de dados, a relação pode ser definida na seção
[Unit]do systemd - O contêiner OxiTraffic é um exemplo que depende do contêiner
test-db- Em
[Unit], definirRequires=test-db.servicefaz a aplicação iniciar somente quando o banco de dados for iniciado - Definir
After=test-db.serviceevita que os dois contêineres iniciem em paralelo
- Em
- Ao referenciar, usa-se o nome do serviço, não o nome do arquivo
.containertest-db.container: nome do arquivotest-db.service: nome do serviçosystemd-test-db: nome padrão do contêiner
- Para que a aplicação se comunique com o banco de dados, ambos os contêineres precisam adicionar a opção
Networkna seção[Container], mas a parte de rede não é abordada aqui
Vários arquivos e agrupamento
- O Quadlet pode ser organizado com um arquivo
.containerseparado para cada contêiner - Em vez de colocar toda uma aplicação multi-contêiner em um único arquivo Docker Compose, ter um arquivo por contêiner pode reduzir a carga cognitiva
- Quando um arquivo Docker Compose chega a centenas de linhas e dezenas de contêineres, a manutenção pode ficar difícil
- O arquivo Docker Compose do Mailcow é um exemplo de arquivo Compose grande
- O Docker Compose também oferece suporte para dividir a configuração em vários arquivos
- O Quadlet permite colocar arquivos unit dentro de diretórios em
~/.config/containers/systemd- No exemplo, pode-se criar um diretório
oxitraffice manter juntos os arquivos da aplicação e do banco de dados
- No exemplo, pode-se criar um diretório
Atualização de imagens
- Ao definir
AutoUpdate=registry, é possível verificar atualizações de imagem compodman auto-update - Se houver uma nova imagem no registro compatível com a tag em uso, o Podman faz o pull da imagem e reinicia o contêiner
- No Docker, pode ser necessário usar uma ferramenta como Watchtower para isso, mas o Podman oferece essa funcionalidade nativamente
- Tags como
latestpodem ser arriscadas- No OxiTraffic,
latestpode incluir breaking changes da próxima versão - No PostgreSQL, usar
latestpode levar a uma nova versão major, e upgrades major do PostgreSQL sempre exigem migração manual
- No OxiTraffic,
- Em produção, deve-se usar tags que não levem a breaking changes
- Também é possível executar
podman auto-updatemanualmente a cada poucos dias, ver o que foi atualizado e depois verificar se os contêineres continuam funcionando normalmente
podman-compose e ferramentas de migração
podman-composeé um script em Python para executar arquivos Compose com Podman- Os motivos pelos quais é difícil vê-lo como uma alternativa de longo prazo ao Docker Compose são os seguintes
- Ele é uma camada de tradução entre a especificação Compose e Podman/systemd, e não permite usar todos os recursos do systemd
- O projeto oficial do Podman é escrito em linguagens compiladas como Rust ou Go
- O último commit foi há 5 meses, então não parece estar sendo mantido ativamente
- O Quadlet combina melhor com o desenho rootless e sem daemon do Podman
- Para experimentar o Quadlet a partir de um arquivo Compose, é possível usar o podlet
- Trata-se de uma ferramenta em Rust capaz de gerar arquivos Quadlet a partir de comandos Podman ou de arquivos Docker Compose
Leituras adicionais
- Para entender o Quadlet mais a fundo, a man page
podman-systemd.unité útil - O Quadlet pode gerenciar não só contêineres, mas também pod, network e volume
- Se você não estiver acostumado a escrever arquivos unit do systemd, vale consultar as man pages
systemd.unitesystemd.service - Outra perspectiva e um segundo exemplo podem ser vistos em um artigo semelhante do blog.while-true-do
1 comentários
Opiniões do Hacker News
Quadlet é uma das melhores coisas que saíram do Podman, e eu recomendo fortemente para quem tem curiosidade sobre Podman ou quer migrar para workloads baseados em contêineres
Você consegue encaixar e tratar contêineres como serviços comuns do sistema, sem precisar aprender uma camada separada de orquestração para fazê-los funcionar juntos nem depender de recursos não conteinerizados
Basta escrever as units do systemd como você já fazia, e atualizações automáticas ou reinício/notificação do serviço em caso de falha vêm de brinde
A forma de tentar fazer algo parecido com Docker muitas vezes contornava o daemon do Docker com um comando
runenorme, deixando serviços e contêineres fantasmas para trás, enquanto o Quadlet é muito mais limpo e as configurações ficam junto dos locais de units do systemd, como/etc/systemd/,.config/systemde/usr/local/lib/systemd, facilitando o backupNo entanto, ele não é a resposta ao docker-compose no desenvolvimento local, e a equipe do Podman também não parece muito interessada nessa área
Contêineres de usuário são bons para infraestrutura local de teste de longa duração, como bancos de dados em segundo plano, mas são trabalhosos demais para o ciclo comum de compilar →
docker compose up→ testar →docker compose downA resposta prática é usar Quadlet
.kube(Kubernetes play) oudocker composeapontando para o socket do PodmanGostei tanto que venho criando, no tempo livre há alguns meses, uma ferramenta GitOps para gerenciar Quadlet, e isso parece a forma correta de administrar servidores conteinerizados
É importante que
[0]não seja podman-compose. O texto também apontou que o podman-compose é ruim e carece de desenvolvimento. Como o Podman implementa a maior parte da especificação do compose, dá para usardocker composena maioria das situaçõesÉ bem provável que pessoas que tentaram usar quando a RH começou a impulsionar o Podman tenham desistido por causa das indefinições do Podman 3 e da experiência ruim com o podman-compose
Depois de mudar várias flags, atualizar versões e seguir o fluxo em que o próprio podlet recomendava trocar para outra ferramenta, isso virou uma toca de coelho sem fim
No fim, meu systemd simplesmente executa
podman compose upFico curioso para saber qual é a vantagem do Quadlet em comparação a deixar o compose fazer o próprio trabalho
Para referência, o Podman roda com meu usuário, sem daemon nenhum
docker-composeautônomopodman composeDescobri o Quadlet recentemente e montei todo o meu homelab com base em atomic OS e Quadlet rootless; recomendo muito
Também é possível usar ativação por socket do systemd: por exemplo, criar sockets http/https do systemd e ativar automaticamente o Traefik, assim como
ssh.socketepodman.socketativamsshd.serviceepodman.service, respectivamenteEm uma configuração rootless, é praticamente a única forma de preservar o IP de origem, então é quase um salva-vidas. Podman/Docker rootless normalmente não permitem preservar facilmente o IP de origem sem grandes desvantagens
https://github.com/savely-krasovsky/homelab
O Quadlet é uma boa alternativa para o uso do docker compose de “executar todos os contêineres interdependentes em um ambiente parecido com produção”
Mas eu gostaria que ele fosse melhor no outro uso do docker compose, que é o desenvolvimento
O docker compose permite subir juntos um banco de dados, Redis, OpenSearch, outras dependências, um proxy nginx e um contêiner de desenvolvimento com
.:/appmontado como volume; derrubar tudo junto; e colocar odocker-compose.ymlno repositórioComo o Quadlet manda colocar todos os arquivos em
~/.config/containers/systemd, ele deixa de ficar isolado ao projeto e também não é cômodo fazer check-in e compartilhar com outros desenvolvedores. Além disso, eles também teriam que usar PodmanA maioria ainda usa Docker, e ambientes de desenvolvimento hospedados como o Codespaces também fornecem Docker
Por isso uso docker compose com um arquivo YAML versionado. Como eu uso Podman, preciso adicionar manualmente
:Za todos os volumes, mas o Docker comum não consegue lidar com issoSeria bom ter uma alternativa ao docker compose para desenvolvimento, mas o Quadlet não parece se encaixar bem
podman-compose --in-pod=1 systemd -a create-unit, dá para criar um serviçopodman-compose@e, depois, registrar um arquivocompose.ymljunto com$nameusandopodman-compose systemd -a registerAssim é possível gerenciar um pod baseado em arquivo compose como
podman-compose@$name.service, e isso também funciona de forma totalmente rootlesssystemd-runpermite executar um serviço systemd temporário com base em um comando arbitrárioSe necessário, ele cria uma unidade temporária limpa, seguindo as regras de escopo do systemd, até com timer
[1] https://www.freedesktop.org/software/systemd/man/systemd-run...
Ele usa um formato parecido com Kubernetes, com algumas conveniências adicionais como build de contêineres
Se você colocar o arquivo kube play na raiz do projeto e executar
podman kube play project.yaml --build, o pod, os volumes etc. são executados juntosArquivos Quadlet são úteis na etapa de deploy. Se quiser colocar o projeto em uma VPS, dá para usar Kube Quadlet[2] junto com o
project.yamlque você já tem[1] https://docs.podman.io/en/latest/markdown/podman-kube-play.1...
[2] https://docs.podman.io/en/latest/markdown/podman-systemd.uni...
docker-compose.ymlpara desenvolvimento, então entendo a dorEm geral funciona muito bem, mas no OSX às vezes se comporta de forma estranha por causa daquela maldita VM intermediária
De vez em quando verifico a compatibilidade com Podman, mas hoje aceitei que a filosofia rootless é diferente demais para haver compatibilidade completa
Ainda assim, essa ferramenta é ótima para produção. Tenho alguns projetos hobby rodando em um nó bare metal com serviços systemd feitos à mão; atualmente é containerd em modo de usuário
Quando eu tiver tempo, talvez eu migre
É curioso que o texto diga que o Podman-Compose “não é mantido ativamente”, apontando que o último commit foi há 5 meses, e logo em seguida recomende como alternativa o Podlet, cujo último commit também foi há 5 meses
O Podlet pode ser útil, mas não dá suporte a muitos recursos do Docker Compose e nem sempre faz uma conversão limpa
Em especial, não dá suporte ao recurso de empilhar vários arquivos YAML, como em
-f docker-compose.yml -f docker-compose.override.ymlParece que a CLI do compose controla o engine via socket, e os engines do Podman e do Docker têm APIs quase iguais
Uso esse método porque o podman-compose não funcionou como eu esperava
O Docker-compose normalmente é instalado como um plugin do cliente docker, mas eu o uso como uma aplicação independente para usar com o Podman
Além disso, para a configuração de integração, prefiro docker
contextsà variável de ambienteDOCKER_HOSTSe apenas Quadlet puro não for poderoso o bastante, Quadlet[3] e o Podman comum[4] também dão suporte à execução limitada de manifests Kubernetes
Ainda não entendi como o Podman lida com a opção
restartdos arquivos compose. Isso porque o Podman não tem um daemon supervisorPor outro lado, sei que a opção
healthcheckdepende de timers do systemdAo usar Podman no Gentoo, uma distribuição que não usa systemd, os healthchecks automáticos não funcionaram, mas, ao executar o healthcheck manualmente, o restante da configuração prosseguiu até o fim
[1] https://github.com/docker/compose
[2] https://docs.podman.io/en/latest/markdown/podman-system-serv...
[3] https://docs.podman.io/en/latest/markdown/podman-systemd.uni...
[4] https://docs.podman.io/en/latest/markdown/podman-kube-play.1...
O Podlet é uma ferramenta auxiliar e, no longo prazo, é melhor trabalhar com Quadlet
5 meses não significa que algo não seja mantido; para isso, teria que ser algo em torno de 2 anos
Ainda assim, isso aumenta a preocupação. Mas 5 meses definitivamente não são prova de que está sendo mantido
Há muitos motivos para um repositório sem manutenção receber updates, e só o recente e meio ruim recurso de arquivamento do GitHub impede isso
Há alguns anos, ao recriar minha configuração de self-hosting, eu queria tentar algo diferente e escolhi o openSUSE MicroOS; acabei rodando contêineres Podman sob systemd/Quadlet e estou bem satisfeito com a configuração atual
Os contêineres são atualizados automaticamente pelas ferramentas embutidas do Podman, e a consulta de logs e o monitoramento são feitos com as ferramentas habituais do systemd
Quando preciso mudar algo, mesmo que eu tenha esquecido onde ficam os arquivos de configuração, é fácil encontrá-los, lê-los e modificá-los
Também é bom ser rootless e daemonless
No meio do caminho, experimentei algumas coisas, mas podman compose pareceu desajeitado; fico feliz que tenha sido deprecated, e está claro que Quadlet é o caminho a seguir
É preciso levar em conta que há uma curva de aprendizado e menos material do que para Docker
Para desenvolvimento local, se a ideia for subir e derrubar stacks com vários serviços, eu ainda escolheria Docker e docker compose
Levei algum tempo para acertar a configuração, mas fiquei muito impressionado com o fato de quase não exigir manutenção. Até agora, nenhuma
Quem quiser fazer algo parecido pode consultar minha configuração
https://github.com/jeppester/coreos-nextcloud
Estou migrando lentamente todos os nós para MicroOS e, na empresa, também estamos promovendo MicroOS ou algo semelhante
A combinação de rollback automático do sistema operacional base com configuração declarativa de contêineres e updates automáticos parece se encaixar perfeitamente
O formato é mais claro que
podman generate systemdou YAML do Kubernetes, e a integração com systemd também é excelenteO que irrita é que o upstream do Podman não fornece repositórios para Debian/Ubuntu
No Debian stable, fiquei preso na 4.3.1 e perdi muitos recursos novos; no fim, decidi voltar para o Docker compose
As soluções alternativas sugeridas eram compilar o Podman manualmente ou usar
debian/testingEspero sinceramente que essa nova abordagem ajude as pessoas a migrarem do Docker para o Podman
Docker-Compose é um motivo pelo qual muita gente hesita em fazer a migração, e comigo foi assim também
Para ser honesto, antes do Quadlet o Podman não tinha uma resposta adequada
Se você hesitava em sair do Docker por causa do Docker-Compose, Podman com Quadlet é uma alternativa muito mais comparável
Você provavelmente sentirá menos falta do Docker do que imagina, e ainda ganha uma melhoria de segurança ao executar contêineres rootless
Colocar tudo em
~/.config/quadlet/systemdnão funcionaPara desenvolvimento e testes, isso é essencial; hoje o Quadlet é estritamente uma solução de implantação
Gosto muito do Quadlet porque ele permite usar contêineres como serviços comuns do sistema
Mas a experiência de usuário de contêineres rootless não combina bem com essa conceitualização
Normalmente, serviços do sistema rodam como usuários do sistema na sessão systemd do sistema, mas serviços de contêineres rootless ficam na sessão systemd de usuário do usuário do sistema
Seria bom poder executar Quadlet rootless dentro da sessão do sistema
user-lingere executar como rootless via systemd de usuárioEu sempre fiz assim
Também seria bom poder executar Quadlet rootless com a opção
DynamicUser=DynamicUser=era uma ótima forma de restringir privilégios de serviços do sistema, mas hoje não se encaixa bem com o PodmanÉ interessante ver o Quadlet na primeira página do Hacker News. Acho que ele não recebeu atenção suficiente
Ygal e Valentin, do projeto, já enviaram um guest post sobre como executar o cliente de túnel do inlets. É parecido com Ngrok/Cloudflared, mas auto-hospedado, sem as limitações de SaaS
https://inlets.dev/blog/2023/10/03/client-quadlet.html
Eles puderam usar
[kube]em vez de[container]para levar YAML padrão do Kubernetes, o que o torna bastante portávelPara quem tiver interesse, criei um template Ansible que mostra como a implantação com Quadlet ficou fácil recentemente
GH: https://github.com/Mati365/hetzner-podman-bunjs-deploy
example.site.orgem vez desite.example.orghttps://en.wikipedia.org/wiki/Example.com