- Comme Podman n’a pas de démon, il lui faut un acteur d’exécution capable de lancer les conteneurs de manière fiable après le démarrage du serveur ; Quadlet résout cela avec une approche basée sur des fichiers de service systemd
- L’ancien
podman generate systemdobligeait à gérer séparément la création du conteneur et la génération du fichier de service, et imposait une charge de modification manuelle à chaque changement du fichier généré - Quadlet regroupe les réglages
[Container],[Service]et[Install]dans des fichiers.containersous~/.config/containers/systemd, afin de gérer au même endroit les options Podman et le comportement systemd - Avec Podman rootless, le démarrage automatique au boot nécessite
WantedBy=default.targetet l’activation de linger ;multi-user.targetn’est pas défini en mode utilisateur - Avec
AutoUpdate=registry, les dépendances systemd, le regroupement de fichiers par répertoire et l’outil de conversionpodlet, Quadlet convient bien à l’exploitation de Podman rootless et daemonless
Pourquoi Quadlet est nécessaire
- Quadlet est une méthode qui permet d’exécuter des conteneurs Podman comme des services systemd
- Il permet d’exécuter des conteneurs en arrière-plan
- Il permet de démarrer automatiquement les conteneurs après un redémarrage du serveur
- Le fait d’exécuter des conteneurs Podman sous systemd n’est pas nouveau en soi
- Auparavant, on utilisait la commande
podman generate systemd - Cette commande affiche désormais un avertissement de dépréciation invitant à migrer vers Quadlet
- Auparavant, on utilisait la commande
- Comme Podman a une architecture daemonless, il lui faut un acteur d’exécution capable de démarrer les conteneurs sans démon
Les inconvénients de l’ancienne approche podman generate systemd
- L’ancienne approche nécessitait d’abord de créer le conteneur avec
podman create- Le conteneur d’exemple utilise l’image
docker.io/library/postgres:16 - Il inclut
-p 5432:5432, un montage de volume, la variable d’environnementPOSTGRES_PASSWORDet le labelio.containers.autoupdate=registry
- Le conteneur d’exemple utilise l’image
- Ensuite, on exécutait
podman generate systemd test-db -fn --newpour générer le fichiercontainer-test-db.service - Le fichier de service généré était placé dans
~/.config/systemd/user, puis activé et démarré avec la commande suivantesystemctl --user enable --now container-test-db
- Ce flux obligeait à répéter la création du conteneur, la génération du fichier de service, le déplacement éventuel du fichier et l’activation du service
- Lorsque la commande de création du conteneur s’allongeait, il fallait gérer séparément un script shell pour pouvoir la réexécuter plus tard
- Pour personnaliser le fichier de service systemd généré, il fallait à chaque fois le modifier manuellement
Structure des fichiers Quadlet
- Avec l’approche Quadlet, on crée le répertoire
~/.config/containers/systemdet on y place des fichiers.container - Le fichier d’exemple
test-db.containercontient les éléments suivants[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
- Un fichier
.containerest un fichier de service systemd ordinaire, mais il inclut une section spéciale[Container] - Beaucoup d’options de
[Container]correspondent aux options en ligne de commande utilisées avecpodman createImage: l’image et le tag à utiliserAutoUpdate=registry: correspond à--label "io.containers.autoupdate=registry"PublishPort: correspond à-pVolume: correspond à-vEnvironment: correspond à-e
- Pour le répertoire personnel de l’utilisateur, il faut utiliser le spécificateur systemd
%hau lieu de~ Restart=alwaysdans[Service]fait en sorte que le conteneur redémarre toujours tant qu’il n’est pas arrêté manuellementWantedBy=default.targetdans[Install]permet au conteneur de démarrer automatiquement au boot
Réglages systemd nécessaires avec Podman rootless
- Pour les conteneurs rootless, il faut utiliser
default.targetet nonmulti-user.targetmulti-user.targetn’est pas défini dans le mode utilisateur de systemd- On peut le vérifier avec
systemctl --user status multi-user.target - En mode système, on peut le vérifier avec
systemctl status multi-user.target
- Comme le conteneur s’exécute comme service utilisateur systemd, il faut activer linger pour qu’il démarre même si l’utilisateur ne se connecte pas
loginctl enable-linger
- Si le démarrage automatique après redémarrage du serveur est nécessaire, l’activation de linger est indispensable
- Pour que systemd détecte un nouveau fichier de service, il faut exécuter la commande suivante
systemctl --user daemon-reload
- Le démarrage du conteneur et la vérification de son état peuvent se faire à la fois avec systemd et avec Podman
systemctl --user start test-dbsystemctl --user status test-dbpodman ps
- Par défaut, le nom du conteneur est le nom du fichier de service précédé de
systemd-- Le nom de conteneur par défaut de
test-db.containerestsystemd-test-db - C’est une règle de nommage destinée à éviter les collisions
- Il est possible de le définir directement avec l’option
ContainerNamede la section[Container]
- Le nom de conteneur par défaut de
Avantages opérationnels de Quadlet
- Quadlet permet de gérer la configuration d’un service de conteneur dans un seul fichier
- Il n’est plus nécessaire de gérer séparément le script qui génère le fichier de service et le fichier de service généré, comme avec l’ancienne approche
- On peut utiliser les options disponibles dans les sections
[Unit]et[Service]de systemd- Par exemple, on peut définir avec
StartExecPreune commande à exécuter avant le démarrage du conteneur - Cela réduit les modifications manuelles ultérieures des fichiers générés
- Par exemple, on peut définir avec
- Au lieu d’écrire et de déboguer des scripts shell, on peut exploiter les conteneurs autour de fichiers de configuration
- Il est plus facile d’exprimer les dépendances entre conteneurs avec l’approche systemd
Exprimer les dépendances entre conteneurs
- Si un conteneur d’application dépend d’un conteneur de base de données, on peut définir la relation avec la section
[Unit]de systemd - Le conteneur OxiTraffic est un exemple de conteneur dépendant de
test-db- Définir
Requires=test-db.servicedans[Unit]fait en sorte que l’application ne démarre que lorsque la base de données démarre - Définir
After=test-db.serviceévite que les deux conteneurs démarrent en parallèle
- Définir
- Lorsqu’on référence un service, on utilise le nom du service et non le nom du fichier
.containertest-db.container: nom du fichiertest-db.service: nom du servicesystemd-test-db: nom de conteneur par défaut
- Pour que l’application communique avec la base de données, les deux conteneurs doivent ajouter l’option
Networkdans la section[Container], mais le réseau n’est pas traité ici
Plusieurs fichiers et regroupement
- Quadlet peut être configuré avec un fichier
.containerdistinct pour chaque conteneur - Par rapport à l’approche consistant à tout mettre dans un seul fichier Docker Compose pour une application multi-conteneurs, les fichiers par conteneur peuvent réduire la charge cognitive
- Lorsqu’un fichier Docker Compose contient des centaines de lignes et des dizaines de conteneurs, il peut devenir difficile à maintenir
- Le fichier Docker Compose de Mailcow est un exemple de gros fichier Compose
- Docker Compose prend aussi en charge le découpage en plusieurs fichiers
- Quadlet permet de placer des fichiers unit dans des répertoires à l’intérieur de
~/.config/containers/systemd- Dans l’exemple, on peut créer un répertoire
oxitrafficet y placer ensemble les fichiers de l’application et de la base de données
- Dans l’exemple, on peut créer un répertoire
Mise à jour des images
- En définissant
AutoUpdate=registry, on peut vérifier les mises à jour d’images avecpodman auto-update - S’il existe dans le registre une nouvelle image compatible avec le tag utilisé, Podman pull l’image et redémarre le conteneur
- Avec Docker, il peut être nécessaire d’utiliser un outil comme Watchtower pour cela, mais Podman fournit cette fonctionnalité nativement
- Les tags comme
latestpeuvent être risqués- Dans OxiTraffic,
latestpeut inclure des breaking changes de la version suivante - Avec PostgreSQL, utiliser
latestpeut entraîner un passage à une nouvelle version majeure, et les upgrades majeurs de PostgreSQL nécessitent toujours une migration manuelle
- Dans OxiTraffic,
- En production, il faut utiliser des tags qui ne conduisent pas à des breaking changes
- Il est aussi possible d’exécuter manuellement
podman auto-updatetous les quelques jours, de regarder ce qui a été mis à jour, puis de vérifier que les conteneurs fonctionnent normalement
podman-compose et outils de migration
podman-composeest un script Python qui exécute des fichiers Compose avec Podman- Il est difficile de le considérer comme une alternative à long terme à Docker Compose pour les raisons suivantes
- C’est une couche de traduction entre la spécification Compose et Podman/systemd, et elle ne permet pas d’utiliser toutes les fonctionnalités de systemd
- Les projets Podman officiels sont écrits dans des langages compilés comme Rust ou Go
- Le dernier commit date d’il y a 5 mois, ce qui laisse penser qu’il n’est pas maintenu activement
- Quadlet correspond mieux à la conception rootless et daemonless de Podman
- Pour essayer Quadlet à partir d’un fichier Compose, on peut utiliser podlet
- C’est un outil en Rust capable de créer des fichiers Quadlet à partir de commandes Podman ou de fichiers Docker Compose
Pour aller plus loin
- Pour comprendre Quadlet plus en profondeur, la page man
podman-systemd.unitest utile - Quadlet peut gérer non seulement des conteneurs, mais aussi des pods, des réseaux et des volumes
- Si l’écriture de fichiers unit systemd ne vous est pas familière, vous pouvez consulter les pages man
systemd.unitetsystemd.service - Un autre point de vue et un deuxième exemple sont disponibles dans un article similaire de blog.while-true-do
1 commentaires
Avis sur Hacker News
Quadlet est l’une des meilleures choses sorties de Podman, et je le recommande vivement à quiconque s’intéresse à Podman ou envisage de migrer vers des workloads basés sur des conteneurs
On peut intégrer et gérer des conteneurs comme des services système ordinaires, sans devoir apprendre une couche d’orchestration distincte pour les faire fonctionner ensemble ni dépendre de ressources non conteneurisées
Il suffit d’écrire les unités systemd comme on le faisait déjà, avec en prime les mises à jour automatiques et le redémarrage/les alertes en cas d’échec du service
Les approches qui tentaient de faire quelque chose de similaire avec Docker finissaient souvent par contourner le démon Docker avec une énorme commande
run, laissant derrière elles des services fantômes et des conteneurs ; Quadlet est beaucoup plus propre, et sa configuration se trouve aussi aux emplacements des unités systemd comme/etc/systemd/,.config/systemd,/usr/local/lib/systemd, ce qui facilite les sauvegardesEn revanche, ce n’est pas la réponse à docker-compose pour le développement local, et l’équipe Podman ne semble pas particulièrement intéressée par ce domaine
Les conteneurs utilisateur conviennent bien à une infrastructure de test locale de longue durée, comme une base de données en arrière-plan, mais ils sont trop fastidieux pour la boucle habituelle compiler →
docker compose up→ tester →docker compose downLa réponse réaliste est soit un Quadlet
.kube(Kubernetes play), soit l’utilisation dedocker composeavec le socket PodmanJe l’aime au point de développer sur mon temps libre depuis quelques mois un outil GitOps pour gérer Quadlet, et cela me semble être la bonne façon d’administrer des serveurs conteneurisés
Il est important de noter que
[0]n’est pas podman-compose. L’article souligne aussi que podman-compose n’est pas terrible et manque de développement. Podman implémente la majeure partie de la spécification compose, donc dans la plupart des cas on peut utiliserdocker composeIl est très probable que les personnes qui ont essayé Podman lorsque RH a commencé à le pousser soient parties à cause du caractère bancal de Podman 3 et de la mauvaise expérience avec podman-compose
Entre les différents flags à modifier, les versions à mettre à jour, et podlet lui-même qui recommandait de passer à un autre outil, je suis tombé dans un terrier sans fin
Au final, mon systemd exécute simplement
podman compose upJe me demande quel est l’avantage de Quadlet par rapport au fait de laisser compose faire son travail
À noter que Podman tourne sous mon utilisateur, sans aucun démon
docker-composeautonomepodman composeJ’ai découvert Quadlet récemment et construit tout mon homelab autour d’un atomic OS et de Quadlet rootless ; je le recommande vivement
L’activation par socket systemd est également possible : par exemple, on peut créer des sockets systemd http/https et auto-activer Traefik, de la même manière que
ssh.socketetpodman.socketactivent respectivementsshd.serviceetpodman.serviceDans une configuration rootless, c’est pratiquement la seule façon de préserver l’IP source, donc c’est presque un sauveur. Podman/Docker rootless ne permettent généralement pas de préserver facilement l’IP source sans gros inconvénients
https://github.com/savely-krasovsky/homelab
Quadlet est une bonne alternative pour l’usage de docker compose consistant à « exécuter tous les conteneurs interdépendants dans un environnement proche de la production »
Mais j’aimerais qu’il soit meilleur pour l’autre usage de docker compose : le développement
docker compose permet de lancer ensemble une base de données, Redis, OpenSearch, d’autres dépendances, un proxy nginx et un conteneur de développement avec
.:/appmonté en volume, puis de tout supprimer ensemble, et de mettre ledocker-compose.ymldans le dépôtQuadlet demande de placer tous les fichiers dans
~/.config/containers/systemd, donc ce n’est plus isolé au projet, et ce n’est pas pratique non plus à committer et partager avec d’autres développeurs. En plus, eux aussi doivent utiliser PodmanLa plupart utilisent encore Docker, et Docker est aussi fourni dans les environnements de développement hébergés comme Codespaces
Du coup on utilise docker compose avec un fichier YAML committé. Comme j’utilise Podman, je dois ajouter manuellement
:Zà tous les volumes, mais Docker standard ne sait pas gérer çaJ’aimerais bien avoir une alternative à docker compose pour le développement, mais Quadlet ne semble pas vraiment adapté
podman-compose --in-pod=1 systemd -a create-unit, on peut créer un servicepodman-compose@, puis enregistrer un fichiercompose.ymlavec$nameviapodman-compose systemd -a registerOn peut alors gérer le pod basé sur le fichier compose avec
podman-compose@$name.service, et cela fonctionne aussi entièrement en rootlesssystemd-runpermet d’exécuter un service systemd transitoire à partir d’une commande arbitraireSi nécessaire, il crée une unité transitoire propre respectant les règles de portée systemd, jusqu’aux timers inclus
[1] https://www.freedesktop.org/software/systemd/man/systemd-run...
Il utilise un format proche de Kubernetes, avec quelques fonctions pratiques en plus, comme la construction de conteneurs
En plaçant le fichier kube play à la racine du projet et en exécutant
podman kube play project.yaml --build, les pods, volumes, etc. sont lancés ensembleLes fichiers Quadlet sont utiles à l’étape de déploiement. Si tu veux mettre le projet sur un VPS, tu peux utiliser Kube Quadlet[2] avec le
project.yamlque tu as déjà[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.ymlpour le développement, donc je comprends la douleurGlobalement, ça fonctionne très bien, mais sous OSX, ça se comporte parfois bizarrement à cause de cette fichue VM intermédiaire
Je vérifie de temps en temps la compatibilité avec Podman, mais j’ai fini par accepter que la philosophie rootless est désormais trop différente pour qu’une compatibilité totale soit possible
Cela dit, cet outil est excellent pour la production. Je fais tourner quelques projets perso sur des nœuds bare metal avec des services systemd faits maison ; actuellement, c’est containerd en mode utilisateur
Quand j’aurai le temps, j’essaierai peut-être de migrer
Il est amusant que cet article qualifie Podman-Compose de « pas activement maintenu », en soulignant que le dernier commit date de 5 mois, puis recommande aussitôt comme alternative Podlet, dont le dernier commit date lui aussi de 5 mois
Podlet peut être utile, mais il ne prend pas en charge beaucoup de fonctionnalités de Docker Compose et ne produit pas toujours une conversion propre
En particulier, il ne prend pas en charge l’empilement de plusieurs fichiers YAML comme
-f docker-compose.yml -f docker-compose.override.ymlLa CLI compose semble contrôler le moteur via un socket, et Podman et le moteur Docker ont quasiment la même API
J’utilise cette méthode parce que podman-compose ne se comportait pas comme prévu
Docker-compose s’installe généralement comme plugin du client docker, mais moi je l’utilise comme application autonome pour l’utiliser avec Podman
Pour la configuration de l’intégration, je préfère aussi les
contextsdocker à la variable d’environnementDOCKER_HOSTSi Quadlet seul n’est pas assez puissant, Quadlet[3] et Podman[4] standard prennent aussi en charge l’exécution limitée de manifests Kubernetes
Je n’ai pas encore compris comment Podman traite l’option
restartdes fichiers compose, puisqu’il n’a pas de démon de supervisionEn revanche, je sais que l’option
healthcheckrepose sur des timers systemdQuand j’utilisais Podman sur Gentoo, une distribution sans systemd, les healthchecks automatiques ne fonctionnaient pas, mais en lançant le healthcheck manuellement, le reste de la configuration allait jusqu’au bout
[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...
Podlet est un outil d’appoint, et à long terme il vaut mieux travailler avec Quadlet
5 mois ne veulent pas dire qu’un projet n’est pas maintenu ; il faudrait plutôt parler d’environ 2 ans
Cela dit, ça augmente quand même les inquiétudes. Mais 5 mois ne prouvent absolument pas qu’il est maintenu
Il existe beaucoup de raisons pour lesquelles un dépôt non maintenu peut être mis à jour, et seule la médiocre fonctionnalité récente d’archivage de GitHub peut l’empêcher
Il y a quelques années, en repartant de zéro pour ma configuration self-hosted, j’ai voulu essayer autre chose et j’ai choisi openSUSE MicroOS ; j’ai fini par faire tourner des conteneurs Podman sous systemd/Quadlet, et je suis plutôt satisfait de ma configuration actuelle
Les conteneurs sont automatiquement mis à jour avec les outils intégrés de Podman, et je consulte les logs et fais la supervision avec les outils systemd habituels
Quand je dois changer quelque chose, même si j’ai oublié où se trouvent les fichiers de configuration, ils sont faciles à retrouver, à lire et à modifier
Le rootless et le daemonless sont aussi appréciables
J’ai essayé quelques autres choses au passage, mais podman compose m’a paru lourd, je suis content qu’il soit deprecated, et il est clair que Quadlet est la voie à suivre
Il faut accepter une courbe d’apprentissage et moins de ressources que pour Docker
Pour lancer et arrêter en développement local des stacks composées de plusieurs services, je choisirais encore Docker et docker compose
Il m’a fallu un peu de temps pour obtenir la bonne configuration, mais je suis très impressionné par le fait que cela ne demande presque aucune maintenance. Jusqu’ici, aucune
Ceux qui veulent tenter quelque chose de similaire peuvent consulter ma configuration
https://github.com/jeppester/coreos-nextcloud
Je migre progressivement tous mes nœuds vers MicroOS, et au travail aussi nous poussons MicroOS ou quelque chose de similaire
L’association du rollback automatique de l’OS de base avec une configuration déclarative des conteneurs et des mises à jour automatiques donne vraiment l’impression de parfaitement s’emboîter
Le format est plus clair que
podman generate systemdou que le YAML Kubernetes, et l’intégration systemd est excellenteCe qui est agaçant, c’est que l’upstream de Podman ne fournit pas de dépôt pour Debian/Ubuntu
Coincé en 4.3.1 sur Debian stable, je suis passé à côté de beaucoup de nouvelles fonctionnalités, et j’ai fini par décider de revenir à Docker compose
Les contournements proposés consistaient à compiler Podman soi-même ou à utiliser
debian/testingJ’espère sincèrement que cette nouvelle approche aidera les gens à passer de Docker à Podman
Docker-Compose est la raison pour laquelle beaucoup hésitent à franchir le pas, et c’était aussi mon cas
Il faut bien l’admettre, avant Quadlet, Podman n’avait pas vraiment de réponse satisfaisante
Si Docker-Compose vous retenait de quitter Docker, Podman avec Quadlet est une alternative bien plus comparable
Docker vous manquera moins que vous ne le pensez, et vous bénéficierez aussi d’une meilleure sécurité grâce à l’exécution de conteneurs rootless
Tout mettre dans
~/.config/quadlet/systemd, ça ne marche pasPour le développement et les tests, c’est indispensable, et aujourd’hui Quadlet est strictement une solution de déploiement
J’aime beaucoup Quadlet, car il permet d’utiliser les conteneurs comme des services système ordinaires
Cela dit, l’expérience utilisateur des conteneurs rootless ne colle pas vraiment avec cette conceptualisation
En général, les services système s’exécutent dans la session systemd du système en tant qu’utilisateur système, mais les services de conteneurs rootless existent dans la session systemd utilisateur de l’utilisateur système
Ce serait bien de pouvoir exécuter des Quadlet rootless au sein de la session système
user-lingeret d’exécuter en rootless via le systemd utilisateurC’est ce que j’ai toujours fait
J’aimerais aussi pouvoir exécuter des Quadlet rootless avec l’option
DynamicUser=DynamicUser=était une excellente façon de limiter les privilèges des services système, mais cela ne s’accorde pas très bien avec Podman aujourd’huiC’est intéressant de voir Quadlet en une de Hacker News. Je trouve qu’il n’a pas reçu assez d’attention
Ygal et Valentin, du projet, nous avaient envoyé un article invité sur la façon d’exécuter le client de tunnel inlets. C’est similaire à Ngrok/Cloudflared, mais auto-hébergé, sans les limites du SaaS
https://inlets.dev/blog/2023/10/03/client-quadlet.html
Ils ont utilisé
[kube]au lieu de[container], ce qui leur a permis d’utiliser du YAML Kubernetes standard, avec une portabilité assez bonnePour les personnes intéressées, j’ai récemment créé un template Ansible qui montre à quel point déployer avec Quadlet est devenu simple
GH : https://github.com/Mati365/hetzner-podman-bunjs-deploy
example.site.orgau lieu desite.example.orghttps://en.wikipedia.org/wiki/Example.com