2 points par GN⁺ 2025-03-25 | 1 commentaires | Partager sur WhatsApp
  • 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 systemd obligeait à 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 .container sous ~/.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.target et l’activation de linger ; multi-user.target n’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 conversion podlet, 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
  • 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’environnement POSTGRES_PASSWORD et le label io.containers.autoupdate=registry
  • Ensuite, on exécutait podman generate systemd test-db -fn --new pour générer le fichier container-test-db.service
  • Le fichier de service généré était placé dans ~/.config/systemd/user, puis activé et démarré avec la commande suivante
    • systemctl --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/systemd et on y place des fichiers .container
  • Le fichier d’exemple test-db.container contient les éléments suivants
    • [Container]
      • Image=docker.io/library/postgres:16
      • AutoUpdate=registry
      • PublishPort=5432:5432
      • Volume=%h/volumes/test-db:/var/lib/postgresql/data:Z
      • Environment=POSTGRES_PASSWORD=CHANGE_ME
    • [Service]
      • Restart=always
    • [Install]
      • WantedBy=default.target
  • Un fichier .container est 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 avec podman create
    • Image : l’image et le tag à utiliser
    • AutoUpdate=registry : correspond à --label "io.containers.autoupdate=registry"
    • PublishPort : correspond à -p
    • Volume : correspond à -v
    • Environment : correspond à -e
  • Pour le répertoire personnel de l’utilisateur, il faut utiliser le spécificateur systemd %h au lieu de ~
  • Restart=always dans [Service] fait en sorte que le conteneur redémarre toujours tant qu’il n’est pas arrêté manuellement
  • WantedBy=default.target dans [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.target et non multi-user.target
    • multi-user.target n’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-db
    • systemctl --user status test-db
    • podman 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.container est systemd-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 ContainerName de la section [Container]

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 StartExecPre une commande à exécuter avant le démarrage du conteneur
    • Cela réduit les modifications manuelles ultérieures des fichiers générés
  • 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.service dans [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
  • Lorsqu’on référence un service, on utilise le nom du service et non le nom du fichier .container
    • test-db.container : nom du fichier
    • test-db.service : nom du service
    • systemd-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 Network dans la section [Container], mais le réseau n’est pas traité ici

Plusieurs fichiers et regroupement

  • Quadlet peut être configuré avec un fichier .container distinct 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
  • 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 oxitraffic et y placer ensemble les fichiers de l’application et de la base de données

Mise à jour des images

  • En définissant AutoUpdate=registry, on peut vérifier les mises à jour d’images avec podman 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 latest peuvent être risqués
    • Dans OxiTraffic, latest peut inclure des breaking changes de la version suivante
    • Avec PostgreSQL, utiliser latest peut entraîner un passage à une nouvelle version majeure, et les upgrades majeurs de PostgreSQL nécessitent toujours une migration manuelle
  • En production, il faut utiliser des tags qui ne conduisent pas à des breaking changes
  • Il est aussi possible d’exécuter manuellement podman auto-update tous 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-compose est 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

1 commentaires

 
GN⁺ 2025-03-25
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 sauvegardes
    En 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 down
    La réponse réaliste est soit un Quadlet .kube (Kubernetes play), soit l’utilisation de docker compose avec le socket Podman
    Je 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 utiliser docker compose
    Il 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

    • J’ai voulu essayer Quadlet et podlet pour me rapprocher de la façon de faire de RH, mais l’expérience en venant de docker compose sur Podman a été horrible
      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 up
      Je 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
    • L’astuce pour le développement consiste à activer le socket Podman, au niveau utilisateur si ce sont des conteneurs rootless, puis à utiliser le docker-compose autonome
    • Sous Windows ou Mac, on ne peut pas utiliser systemd, donc il ne reste finalement que podman compose
  • J’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.socket et podman.socket activent respectivement sshd.service et podman.service
    Dans 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

    • Je me demande combien de temps il faut pour que Traefik s’active
  • 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 .:/app monté en volume, puis de tout supprimer ensemble, et de mettre le docker-compose.yml dans le dépôt
    Quadlet 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 Podman
    La 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 ça
    J’aimerais bien avoir une alternative à docker compose pour le développement, mais Quadlet ne semble pas vraiment adapté

    • Avec podman-compose --in-pod=1 systemd -a create-unit, on peut créer un service podman-compose@, puis enregistrer un fichier compose.yml avec $name via podman-compose systemd -a register
      On peut alors gérer le pod basé sur le fichier compose avec podman-compose@$name.service, et cela fonctionne aussi entièrement en rootless
    • Dans ce cas, ce que tu cherches, ce sont les pods Podman, et pour ma part j’orchestrerais l’ensemble avec Ansible, puis je distribuerais les playbooks Ansible à tout le monde pour qu’ils les exécutent en local
    • systemd-run permet d’exécuter un service systemd transitoire à partir d’une commande arbitraire
      Si 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...
    • Je vois plutôt Quadlet comme un outil pour le déploiement. Si tu cherches une alternative à compose, mieux vaut regarder Podman Kube Play[1]
      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 ensemble
      Les 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.yaml que 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...
    • Dans notre entreprise aussi, on utilise docker-compose.yml pour le développement, donc je comprends la douleur
      Globalement, ç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.yml

    • Si vous aimez les fichiers compose, vous pouvez utiliser l’application compose de Docker[1] avec Podman[2]
      La 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 contexts docker à la variable d’environnement DOCKER_HOST
      Si 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 restart des fichiers compose, puisqu’il n’a pas de démon de supervision
      En revanche, je sais que l’option healthcheck repose sur des timers systemd
      Quand 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...
    • Pour être juste, les fonctionnalités de Podlet n’ont pas besoin de mises à jour continues, contrairement à podman compose
      Podlet est un outil d’appoint, et à long terme il vaut mieux travailler avec Quadlet
    • La date du dernier commit n’est pas un indicateur fiable pour montrer qu’un projet est maintenu, mais elle peut montrer qu’il ne l’est pas
      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

    • Je fais tourner Nextcloud avec Fedora CoreOS sur une vieille workstation bon marché
      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
    • La combinaison Quadlet + MicroOS est très puissante, tout comme d’autres distributions atomic comme Fedora CoreOS
      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 systemd ou que le YAML Kubernetes, et l’intégration systemd est excellente
    Ce 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

    • J’ai rencontré le même problème en essayant d’utiliser Quadlet sur un Raspberry Pi sous Debian
      Les contournements proposés consistaient à compiler Podman soi-même ou à utiliser debian/testing
  • J’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

    • Je ne migrerai pas tant qu’il ne sera pas possible d’avoir plusieurs environnements Quadlet indépendants
      Tout mettre dans ~/.config/quadlet/systemd, ça ne marche pas
      Pour 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

    • Je me demande s’il y a une différence concrète avec le fait d’activer user-linger et d’exécuter en rootless via le systemd utilisateur
      C’est ce que j’ai toujours fait
    • Moi aussi, j’aimerais pouvoir exécuter des Quadlet rootless au sein de la session système
      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’hui
  • C’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 bonne

  • Pour 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