2 points par GN⁺ 2025-05-06 | 1 commentaires | Partager sur WhatsApp
  • Sur un serveur personnel ou un petit VPS, l’automatisation déclarative de Kubernetes est séduisante, mais sa charge CPU et mémoire ainsi que sa complexité d’exploitation peuvent dépasser ses bénéfices réels
  • Kubernetes automatise des tâches comme l’ajustement des Pods et le renouvellement des certificats TLS en maintenant en permanence l’état souhaité, mais cela implique de faire tourner en continu un runtime assez lourd
  • Sur Azure Kubernetes Service, Microk8s, K3S et lors d’expérimentations sur Raspberry Pi, la consommation de ressources au repos ainsi que la chaleur et le bruit du ventilateur se sont révélés problématiques de façon répétée
  • Podman peut transformer des conteneurs en services systemd et détecter puis remplacer de nouvelles images avec io.containers.autoupdate et podman auto-update
  • La combinaison Podman, systemd et user lingering fournit de façon plus simple l’essentiel de l’automatisation recherchée avec Kubernetes, mais l’intégration systemd évolue désormais vers Quadlet

Pourquoi l’automatisation de Kubernetes était trop lourde pour un serveur personnel

  • Kubernetes se compose de multiples éléments, services web, sidecars et webhooks, mais son fonctionnement central ressemble surtout à une boucle qui compare en continu l’état actuel et l’état souhaité pour appliquer les écarts
    • Si un Pod doit exister mais n’existe pas, il est créé
    • Si le nombre de replicas doit être de 3 mais qu’il y en a 4, l’un d’eux est supprimé
  • Ce modèle était particulièrement utile avec des extensions comme cert-manager
    • On déclare qu’un certificat TLS valide doit exister pour un domaine donné
    • Une fois la méthode de demande de certificat définie, un nouveau certificat est obtenu et installé sur le serveur web lorsqu’il manque ou approche de son expiration
  • Pour des expérimentations personnelles, c’était amusant et formateur, mais pour un usage de production réel, cela relevait davantage de l’outil excessif
  • La charge sur les ressources s’est répétée dans plusieurs environnements
    • Sur un NUC, la machine tournait en permanence, chauffait et faisait du bruit, au point de rendre le sommeil difficile
    • Sur Azure Kubernetes Service, l’implémentation de Kubernetes consommait beaucoup de RAM et utilisait environ 7 à 10 % du CPU au repos sur le worker node
    • Une instance unique de Microk8s sur un VPS x86_64 à 2 vCPU utilisait environ 12 % de CPU au repos
    • K3S sur une machine Ampere A1 à 2 vCPU, pourtant réputé plus léger, utilisait environ 6 % de CPU en continu
    • Même sur Raspberry Pi, il n’a pas été possible de trouver une implémentation laissant assez de CPU pour les workloads sans problèmes de chaleur ni de ventilateur

La méthode d’automatisation adoptée avec Podman et systemd

  • La principale raison de conserver Kubernetes était l’automatisation du déploiement
    • Avec GitOps et Flux, les changements étaient faciles à appliquer
    • Grâce à l’automatisation des images de conteneurs et au webhook de Flux v2, lorsqu’une nouvelle image était poussée, le serveur la récupérait en quelques secondes et lançait l’application de production mise à jour
  • Les alternatives classiques trouvées hors de Kubernetes n’étaient pas satisfaisantes
    • Recréer les conteneurs en mémorisant tous les arguments de ligne de commande d’origine impliquait une lourde charge de gestion
    • Les outils réclamant un contrôle total de docker.sock n’étaient pas non plus appréciés
  • Podman auto-updating correspondait de près au besoin
    • Podman peut être vu comme une alternative à la CLI Docker
    • Après avoir créé un conteneur, il est possible de générer un fichier de service systemd
    • Quand le service démarre, il crée ou remplace le conteneur ; quand le service s’arrête, il supprime le conteneur
  • Les mises à jour automatiques reposent sur le tag io.containers.autoupdate
    • Elles s’exécutent une fois par jour via un timer ou en lançant directement podman auto-update
    • Si une nouvelle image est disponible, le conteneur est recréé à partir de cette image
  • L’article de Fedora Magazine, Auto-updating Podman containers with systemd, fournissait l’essentiel de la mise en œuvre, avec en plus deux réglages nécessaires
    • systemctl --user enable mycontainer.service permet de démarrer automatiquement le conteneur à la connexion
    • loginctl enable-linger permet d’activer la session utilisateur au démarrage du serveur
  • La combinaison Podman, systemd et user lingering permet de retrouver environ 99 % des avantages obtenus avec Kubernetes, avec bien moins de complexité et une charge CPU/mémoire nettement plus faible
  • L’ensemble des services a été migré vers un nouveau VPS disposant de moitié moins de vCPU et de RAM que l’ancien, tout en étant plus léger, plus rapide et moins coûteux à faire tourner après plusieurs heures d’exécution
  • En revanche, l’intégration de Podman avec systemd semble déjà dépréciée, et les définitions de conteneurs s’orientent désormais vers des fichiers Quadlet

1 commentaires

 
GN⁺ 2025-05-06
Avis de Hacker News
  • Je comprends totalement le ressenti de l’auteur original. Au travail, on gère relativement facilement plusieurs clusters Kubernetes qui font tourner des dizaines de microservices, mais pour des projets perso sans revenus, le budget est trop serré pour utiliser Kubernetes même si on en a envie.
    Sur un VPS à 10 $/mois avec 1 vCPU partagé et 2 Go de RAM, Kubernetes est beaucoup trop lourd. Au lieu de Deployments, je lance manuellement docker compose up/down en SSH ; au lieu d’un Ingress, je m’appuie sur la découverte de conteneurs de Traefik ; et comme je ne peux pas utiliser les CronJobs, j’ai même écrit un petit script pour gérer crontab de façon idempotente.
    Ce que je veux vraiment, c’est une alternative légère qui fournisse une API compatible Kubernetes et tourne bien même sur un VPS bon marché. L’écart entre l’orchestration de conteneurs de niveau entreprise et l’hébergement low cost pour projets perso reste beaucoup trop grand.

    • Selon l’étendue de la Kube API dont on a besoin, Podman peut remplir ce rôle. Il peut créer des conteneurs et des pods à partir de manifestes Kubernetes, ce qui le fait fonctionner comme un docker compose utilisant des manifestes Kubernetes.
      On peut aussi l’utiliser avec des unités systemd, comme dans l’approche décrite dans l’article. Podman prend également en charge la majeure partie, voire la totalité, de l’API Docker, donc docker compose fonctionne aussi, et on peut se connecter à un socket distant via SSH pour travailler.
      https://docs.podman.io/en/latest/markdown/podman-kube-play.1...
      https://docs.podman.io/en/latest/markdown/podman-systemd.uni...
    • Je me demande si tu as regardé k0s ou k3s. Il existe pas mal de retours où ils sont bien utilisés à petite échelle : https://news.ycombinator.com/item?id=43593269
    • Je ne veux pas donner l’impression de faire la promo d’Oracle, mais l’Oracle Cloud Free Tier est incroyablement généreux. On peut y faire tourner pas mal de choses, y compris un petit cluster k8s, et le service de plan de contrôle k8s est gratuit.
      Ils offrent gratuitement 4 cœurs ARM64 et 24 Go de RAM, que l’on peut répartir sur 1 à 4 nœuds selon la configuration souhaitée.
      https://www.oracle.com/cloud/free/
    • On peut faire à l’ancienne avec quelque chose comme Ansible. Je gère entièrement quelques serveurs dédiés avec Ansible, et on peut s’en servir comme une sorte de docker compose renforcé.
      Avec Traefik et des labels, on généralise le reverse proxy et les certificats TLS, puis on ajoute Authelia comme fournisseur d’authentification simple. Il y a aussi beaucoup de projets d’exemple sur GitHub, et avec un week-end de configuration on obtient un système assez facile à administrer.
    • Puisque tu as déjà dit que le coût d’utilisation de Kubernetes est trop élevé, selon l’axe sur lequel tu mesures l’efficacité, une solution maison peut en fait être plus efficace.
  • systemd se fait beaucoup critiquer, mais il résout vraiment énormément de problèmes, donc il ne faut pas l’écarter trop vite. Quand il a commencé à arriver par défaut dans les distributions, une bonne partie du rejet venait du fait que les gens devaient changer leurs habitudes.
    Il y a les conteneurs, machinectl, nspawn, qui est un chroot plus puissant, vmspawn quand on a besoin de virtualisation complète, importctl pour télécharger, importer et exporter des machines, homed/homectl pour faciliter le chiffrement des répertoires personnels et le contrôle des permissions, etc.
    Au lieu de fstab, on traite les montages comme des unités ; on contrôle l’ordre de démarrage ainsi que le lancement et l’arrêt des services ; et il fournit aussi des timers plus puissants que cron. Par exemple, on peut savoir qu’une tâche n’a pas pu s’exécuter parce que la machine était éteinte, ou la lancer avec un délai après le démarrage sous certaines conditions.
    Les unités de service permettent de contrôler finement les tâches et de restreindre les permissions, et systemctl edit permet de créer des overrides sans toucher à la configuration d’origine. C’est un peu pénible à apprendre au début, mais de toute façon, pour faire des choses complexes, aucun outil ne permet d’éviter totalement la documentation.

    • Si systemd a été critiqué pendant ses premières années, peut-être presque dix ans, ce n’était pas parce que le projet lui-même était mauvais. Au contraire, il était suffisamment bon pour réussir malgré plusieurs problèmes.
      Le problème, c’était l’attitude des mainteneurs. Ils cassaient sans scrupule des choses qui fonctionnaient bien, sans fournir de correctifs appropriés. Si systemd ne t’a jamais fait souffrir, c’est peut-être que tu es arrivé plus tard, ou que tes besoins coïncidaient par hasard avec ceux des mainteneurs principaux.
    • La seule chose qui me déplaît dans systemd, c’est qu’un binaire issu d’une base de code gigantesque joue le rôle de PID 1, et qu’il a un comportement encore plus complexe pour tenter de s’exec lui-même sur place lors des mises à niveau.
      Un programme qui fait exactement à 100 % ce que PID 1 doit faire, et rien d’autre, peut être beaucoup plus petit. Si on lance systemd par-dessus, un problème dans systemd ne mène pas immédiatement à un kernel panic.
      Source : https://ewontfix.com/14/
    • J’ai du mal à accepter l’idée qu’il faudrait oublier cron. Il fonctionne bien depuis 50 ans, et soudain il serait devenu une très mauvaise solution qui devrait naturellement être remplacée par systemd.
    • Si l’on oublie fstab au profit des montages systemd, les règles d’automount sont complexes et, même en les alignant 1:1 avec la documentation, il arrive qu’elles ne fonctionnent tout simplement pas, si bien que le système de fichiers peut ne pas être monté à temps.
    • systemd est excellent pour un Linux de bureau ou serveur moderne, ou pour des usages similaires. Mais si l’on essaie de faire quelque chose qui sort du modèle prévu par le projet, on se heurte aux moqueries et à la résistance. Il suffit de demander à l’équipe musl.
      Pour les distributions ou les projets upstream, il simplifie énormément la vie, mais en contrepartie il ajoute une complexité croissante dans les couches les plus basses du système. Selon le point de vue, des éléments comme journalctl, timedatectl, la dépendance à dbus ou son remplacement peuvent être vus comme contraires à la philosophie Unix.
      Si l’objectif est simplement de coordonner des processus, de les exécuter dans le bon ordre et de garantir l’activation automatique, je le considère comme un outil d’un niveau plus approprié que k8s ou Docker.
  • J’ai fait tourner mon homelab pendant un bon moment avec podman-systemd, autrement dit Quadlet, et chaque fois que je regardais une nouvelle variante de k8s, ça ne valait pas la peine d’accepter la complexité supplémentaire. Mes vieux playbooks Ansible suffisent déjà à pré-télécharger les images et à mettre les fichiers d’unités au bon endroit
    J’ai aussi fait tourner toute la stack de mon imprimante 3D Voron avec podman-systemd, ce qui permet de mettre à jour et de revenir en arrière sur tous les composants d’un coup. Cela dit, j’envisage maintenant aussi une approche avec mkosi et systemd-sysupdate pour mettre à jour et rollbacker toute l’image disque en une seule fois
    Le principal problème, c’est que les gens distribuent généralement seulement des fichiers docker-compose, qu’il faut donc convertir en unités systemd, et que certaines images Docker ont, côté utilisateurs et permissions, une complexité inutile pour Podman. En particulier, si un conteneur refuse de s’exécuter en root ou bascule vers un autre utilisateur, il faut parfois se coltiner des mappings d’ID userns pénibles
    Malgré tout, dans l’ensemble, c’est beaucoup moins complexe que n’importe quelle configuration k8s ou variante de k8s. J’aime aussi le fait que tout soit intégré à systemd et journald, sans être scindé entre deux endroits

    • J’utilise une approche similaire depuis plusieurs années : https://github.com/Mati365/hetzner-podman-bunjs-deploy. C’est basé sur Podman et systemd, et rien n’a cassé depuis
      Comme il suffit de déposer les unités, c’est très stable et simple
    • Pour convertir des fichiers compose en fichiers Quadlet, on peut utiliser podlet : https://github.com/containers/podlet
    • Au final, j’ai l’impression que c’est plutôt un nœud unique, ou un ensemble de nœuds indépendants. Podman/systemd/Quadlet peut être un détail d’implémentation de la manière dont un nœud k8s exécute des conteneurs, en quelque sorte quelque chose qui ressemble à la CRI
      Mais ça ne remplace pas l’abstraction d’orchestration et de scheduling sur plusieurs nœuds fournie par k8s. Il manque la partie « voici des machines capables d’exécuter des fichiers Podman-systemd, voici la spécification que je veux lancer, placez-la comme il faut »
    • Même expérience. Le workflow consiste à lancer le conteneur avec une commande podman run, vérifier qu’il tourne correctement, puis créer un fichier conteneur de base avec podlet, et enfin modifier ce fichier en séparant les volumes et le réseau dans d’autres fichiers Quadlet
      Le projet podman-compose semble toujours activement maintenu et peut être une bonne alternative à docker-compose. Mais l’intégration entre Podman et systemd est tellement satisfaisante
  • L’étape suivante pour simplifier encore cela consiste à gérer les conteneurs avec Quadlet dans systemd. Les détails sont ici : https://www.redhat.com/en/blog/quadlet-podman

    • Quadlet est exactement cette voie-là. C’est vraiment une excellente manière d’exécuter des conteneurs, avec une impression de « configurer et oublier ». Sur Fedora ou Rocky Linux, au moins, il n’y a même pas besoin d’installer de paquet supplémentaire
    • C’était abordé à la fin de l’article, mais l’auteur ne l’avait pas encore examiné. Comme l’intégration systemd de Podman semble déjà dépréciée et qu’il est maintenant question de définir les conteneurs via des fichiers « Quadlet », il a laissé ça comme quelque chose à apprendre plus tard
    • Si je suis venu lire les commentaires, c’était pour vérifier si quelqu’un avait mentionné Quadlet. La semaine dernière, j’ai migré mon serveur domestique de docker compose vers Podman Quadlet rootless ; la transition a été difficile, mais je suis très satisfait du résultat
    • Cet article a aussi beaucoup aidé à migrer en douceur mon homelab vers Quadlet : https://news.ycombinator.com/item?id=43456934
  • J’ai créé skate : https://github.com/skateco/skate. C’est essentiellement fait pour ce genre d’usage, mais avec la prise en charge de plusieurs hôtes et aussi des manifestes k8s. En interne, ça utilise Podman et systemd

    • J’aime beaucoup cette approche. C’est vraiment frustrant qu’il n’existe pas de manière simple d’exécuter Docker/Podman sur plusieurs hôtes. Docker Swarm est malheureusement, de fait, laissé à l’abandon depuis 2019
      En revanche, je trouve que k8s a une API et une expérience utilisateur catastrophiques. La spec Docker Compose est beaucoup plus conviviale, donc j’expérimente actuellement un docker-compose multi-hôtes : https://github.com/psviderski/uncloud
  • Je suis revenu à une approche où je empaquette de nouveau en paquets deb et les exécute directement avec systemd sur des instances EC2, sans utiliser de conteneurs. Les instances sont placées dans un Auto Scaling Group derrière un ALB, et au démarrage un simple ansible-pull installe le deb
    C’est assez brut de décoffrage, mais j’en avais assez du HCL dans du YAML dans du JSON à n’en plus finir. Maintenant, je veux seulement avoir à gérer un peu de YAML Ansible

    • Ce qui est bien avec cette approche, c’est que lorsqu’il y a un bug dans une bibliothèque commune, il suffit d’exécuter apt full-upgrade et de redémarrer uniquement les processus en cours pour être protégé
      Pas besoin de reconstruire quoi que ce soit, ni de chercher comment mettre à jour une bibliothèque enfouie au fin fond d’un conteneur que l’on a peut-être construit soi-même, ou pas
    • J’ai pris la même direction pour une application très simple. systemd s’est révélé étonnamment agréable, et j’ai beaucoup aimé le fait d’exécuter le service avec le minimum de privilèges via un compte utilisateur attribué par le système
      Grâce à la prise en charge des cgroups, c’est aussi pratique pour faire tourner plusieurs services sur un seul VPS
    • Quand on pense au nombre de vies humaines gaspillées dans le domaine de la « gestion de YAML à grande échelle », ça donne le vertige
  • L’article datant de plus d’un an, il existe désormais même ParticleOS, une distribution d’OS officiellement prise en charge par systemd pour les workflows immuables
    https://github.com/systemd/particleos
    https://news.ycombinator.com/item?id=43649088

    • L’étape logique suivante serait de remplacer le noyau Linux par systemd-kernel, et là ce serait complet
  • À la lecture, tout cela semble pouvoir être remplacé par une commande docker compose et quelque chose comme Caddy, qui récupère automatiquement les certificats
    Avec seulement compose.yaml, en gros une seule ligne suffit : docker compose up -d --pull always. Pour la configuration CI, scp compose.yaml user@remote-host:~/ puis ssh user@remote-host 'docker compose up -d --pull always' suffisent aussi
    L’avantage, c’est que c’est simple et que ça fonctionne aussi sur une machine de développement. Bien sûr, si l’objectif secondaire est d’essayer des choses intéressantes et d’apprendre, Quadlet, k8s et systemd sont aussi de bons choix

    • Il suffit d’exécuter une seule fois docker context create --docker 'host=ssh://user@remote-host' remote-host
      Ensuite, on peut utiliser docker -c remote-host compose -f compose.yaml up -d --pull always, sans avoir à copier le fichier. De plus, si l’on configure les informations utilisateur dans ~/.ssh/config, il n’est plus nécessaire d’écrire user@ dans les appels SSH, ce qui facilite la copie de la documentation ou des commandes au sein d’une équipe
    • On peut faire comme dans le commentaire voisin, ou définir la variable d’environnement DOCKER_HOST. Attention toutefois : l’interpolation du fichier compose utilise les variables d’environnement locales
  • Comme je pense que déployer sur un seul serveur ne devrait pas être aussi compliqué, j’ai créé un outil qui déploie comme je le souhaite : https://harbormaster.readthedocs.io/
    Harbormaster localise les dépôts via un fichier YAML, les clone et les met à jour périodiquement, puis exécute les fichiers Docker Compose qu’ils contiennent. Tout l’état est également conservé dans un seul répertoire, ce qui facilite les sauvegardes
    Si vous n’avez besoin que d’un seul serveur, c’est l’outil d’orchestration de conteneurs le plus simple et le meilleur que j’aie vu jusqu’ici. J’aime le fait que toute la configuration soit déclarée dans le dépôt, que tout l’état soit dans un répertoire et que tout soit simplement des fichiers Compose

  • En lisant les commentaires ici, j’ai l’impression de prendre un coup de vieux. Plus personne n’utilise simplement ssh et nginx ?
    On entasse tout dans une seule machine, on la sauvegarde de manière agressive, et c’est réglé. Pour un usage domestique, il n’est vraiment pas nécessaire d’aller jusqu’à gérer des microservices

    • Je n’utilise que nginx et quelques services personnalisés, mais c’est possible parce que mes besoins sont très limités. Dès que ça se complique un peu, ou qu’il faut lancer plusieurs nœuds pour avoir de la redondance, les conteneurs commencent à devenir extrêmement pertinents