Kubernetes durch systemd ersetzen (2024)
(blog.yaakov.online)- Auf persönlichen Servern und kleinen VPS ist die deklarative Automatisierung von Kubernetes zwar attraktiv, aber CPU- und Speicherlast sowie die betriebliche Komplexität können den tatsächlichen Nutzen übersteigen
- Kubernetes automatisiert Dinge wie die Abstimmung von Pods und die Erneuerung von TLS-Zertifikaten, indem es fortlaufend den gewünschten Zustand herstellt, hält dafür aber ständig eine recht große Runtime am Laufen
- Bei Experimenten mit Azure Kubernetes Service, Microk8s, K3S und Raspberry Pi waren Leerlauf-Ressourcenverbrauch, Hitzeentwicklung und Lüftergeräusche wiederholt ein Problem
- Podman kann Container in systemd-Dienste verwandeln und mit
io.containers.autoupdatesowiepodman auto-updateneue Images erkennen und ersetzen - Die Kombination aus Podman, systemd und User-Lingering bietet den Großteil der gewünschten Kubernetes-Automatisierung deutlich einfacher, allerdings verlagert sich die systemd-Integration von Podman in Richtung Quadlet
Warum die Kubernetes-Automatisierung für persönliche Server zu schwergewichtig war
- Kubernetes besteht aus mehreren Komponenten, Web-Services, Sidecars und Webhooks, aber das Kerngeschehen ähnelt eher einer Schleife, die fortlaufend Ist-Zustand und Soll-Zustand vergleicht und Unterschiede anwendet
- Wenn ein Pod vorhanden sein sollte, aber fehlt, wird er erstellt
- Wenn es 3 Replikate geben sollte, aber 4 existieren, wird eines entfernt
- Dieses Modell war besonders bei Erweiterungen wie cert-manager nützlich
- Es wird deklariert, dass für eine bestimmte Domain ein gültiges TLS-Zertifikat vorhanden sein muss
- Wenn festgelegt ist, wie das Zertifikat angefordert wird, beschafft das System ein neues Zertifikat und installiert es im Webserver, sobald keines vorhanden ist oder das Ablaufdatum naht
- Für persönliche Experimente war das interessant und lehrreich, für den tatsächlichen Betrieb aber eher ein überdimensioniertes Werkzeug
- Die Ressourcenlast zeigte sich in mehreren Umgebungen immer wieder
- Auf einem NUC lief der Rechner ständig weiter, wurde heiß und erzeugte Lüftergeräusche, sodass Schlafen schwierig war
- In Azure Kubernetes Service belegte die Kubernetes-Implementierung viel RAM und nutzte auf Worker-Nodes im Leerlauf etwa 7–10 % CPU
- Eine einzelne Microk8s-Instanz auf einem x86_64-VPS mit 2 vCPU lag im Leerlauf bei etwa 12 % CPU
- K3S auf einer Ampere-A1-Maschine mit 2 vCPU gilt zwar als leichter, verbrauchte aber dennoch rund 6 % CPU dauerhaft
- Auch auf dem Raspberry Pi wurde keine Implementierung gefunden, die ohne Hitze- und Lüfterprobleme genug CPU für die Workloads übrig ließ
Der geänderte Automatisierungsansatz mit Podman und systemd
- Der wichtigste Grund, Kubernetes weiter einzusetzen, war die Automatisierung von Deployments
- Mit GitOps und Flux ließen sich Änderungen einfach umsetzen
- Mit der Container-Image-Automatisierung und Webhooks in Flux v2 wurde nach dem Push eines neuen Images innerhalb weniger Sekunden das neue Image auf den Server gezogen und die Produktionsanwendung gestartet
- Frühere Alternativen außerhalb von Kubernetes waren nicht zufriedenstellend
- Container neu zu erstellen, indem alle ursprünglichen Kommandozeilenargumente gemerkt werden mussten, bedeutete hohen Verwaltungsaufwand
- Werkzeuge, die vollständige Kontrolle über
docker.sockverlangen, waren ebenfalls unerwünscht
- Podman auto-updating kam den benötigten Funktionen am nächsten
- Podman kann als Alternative zur Docker CLI gesehen werden
- Nach dem Erstellen eines Containers lässt sich eine systemd-Service-Datei erzeugen
- Beim Start des Dienstes wird der Container erstellt oder ersetzt, beim Stoppen des Dienstes wird der Container entfernt
- Automatische Updates funktionieren über das Tag
io.containers.autoupdate- Sie laufen einmal täglich per Timer oder durch direktes Ausführen von
podman auto-update - Wenn ein neues Image vorhanden ist, wird der Container mit diesem Image neu erstellt
- Sie laufen einmal täglich per Timer oder durch direktes Ausführen von
- Der Fedora-Magazine-Artikel Auto-updating Podman containers with systemd lieferte den Großteil der Umsetzung, zusätzlich waren noch zwei Einstellungen nötig
- Mit
systemctl --user enable mycontainer.servicewird der Container beim Login automatisch gestartet - Mit
loginctl enable-lingerwird sichergestellt, dass die Benutzersitzung beim Serverstart läuft
- Mit
- Mit der Kombination aus Podman, systemd und User-Lingering werden etwa 99 % der Vorteile erreicht, die zuvor mit Kubernetes erzielt wurden, bei deutlich geringerer Komplexität sowie niedrigerer CPU- und Speicherlast
- Der gesamte Dienst wurde vom bisherigen VPS auf einen neuen VPS mit halb so vielen vCPU und halb so viel RAM umgezogen; über mehrere Stunden Laufzeit hinweg war er leichter, schneller und verursachte geringere Compute-Kosten
- Allerdings scheint die systemd-Integration von Podman bereits veraltet zu sein, und bei Container-Definitionen geht die Diskussion inzwischen in Richtung Quadlet
1 Kommentare
Meinungen auf Hacker News
Ich kann die Gefühle des Autors des Originals vollkommen nachvollziehen. Im Job verwalten wir relativ problemlos mehrere Kubernetes-Cluster mit Dutzenden Microservices, aber bei Hobbyprojekten ohne Einnahmen ist das Budget so klein, dass ich Kubernetes selbst dann nicht nutzen kann, wenn ich es möchte.
Auf einem VPS für 10 US-Dollar im Monat mit 1 gemeinsam genutzten vCPU und 2 GB RAM ist Kubernetes viel zu schwergewichtig. Statt Deployments führe ich per SSH manuell
docker compose up/downaus, statt Ingress verlasse ich mich auf die Container-Erkennung von Traefik, und weil ich keine CronJobs nutzen kann, habe ich sogar ein kleines Skript geschrieben, das crontab idempotent verwaltet.Was ich wirklich will, ist eine leichtgewichtige Alternative, die eine Kubernetes-kompatible API bietet und auch auf günstigen VPS gut läuft. Die Lücke zwischen Container-Orchestrierung auf Enterprise-Niveau und billigem Hosting für Hobbyprojekte ist immer noch viel zu groß.
docker composefür Kubernetes-Manifests.Es lässt sich auch wie im Artikel beschrieben zusammen mit systemd-Units verwenden. Podman unterstützt außerdem die Docker API größtenteils oder vollständig, sodass auch
docker composefunktioniert; man kann sich auch per SSH mit einem entfernten Socket verbinden und damit arbeiten.https://docs.podman.io/en/latest/markdown/podman-kube-play.1...
https://docs.podman.io/en/latest/markdown/podman-systemd.uni...
Kostenlos gibt es 4 ARM64-Kerne und 24 GB RAM, die man je nach gewünschter Konfiguration auf 1 bis 4 Nodes aufteilen kann.
https://www.oracle.com/cloud/free/
docker composenutzen.Mit Traefik und Labels lassen sich Reverse Proxy und TLS-Zertifikate verallgemeinern, und Authelia kann man als einfachen Authentifizierungsanbieter davorschalten. Auf GitHub gibt es viele Beispielprojekte, und wenn man ein Wochenende in die Einrichtung steckt, bekommt man ein ziemlich gut wartbares System.
systemd bekommt viel Kritik ab, löst aber wirklich viele Probleme und sollte daher nicht vorschnell abgetan werden. Als es in Distributionen standardmäßig Einzug hielt, mochten viele Leute vor allem nicht, dass sie sich umstellen mussten.
Es gibt Container,
machinectl,nspawnals leistungsfähigeres chroot,vmspawnfür den Fall, dass vollständige Virtualisierung nötig ist,importctlzum Herunterladen, Importieren und Exportieren von Maschinen sowiehomed/homectl, was Verschlüsselung und Rechteverwaltung für Home-Verzeichnisse erleichtert.Statt
fstabbehandelt man Mounts als Units, steuert Boot-Reihenfolge sowie Start und Stopp von Diensten und bekommt auch Timer, die mächtiger sind alscron. Beispielsweise kann man erkennen, welche Jobs nicht ausgeführt wurden, weil die Maschine ausgeschaltet war, oder Jobs nach dem Booten unter bestimmten Bedingungen verzögert ausführen.Service-Units erlauben eine feingranulare Kontrolle von Aufgaben und eine Einschränkung von Berechtigungen; mit
systemctl editkann man Override-Konfigurationen anlegen, ohne die Originalkonfiguration anzufassen. Der Einstieg ist etwas lästig, aber wenn man komplexe Dinge tun will, gibt es ohnehin kein Werkzeug, bei dem man nie in die Dokumentation schauen muss.Das Problem war die Haltung der Maintainer. Dinge, die gut funktionierten, wurden scheinbar unbekümmert kaputtgemacht, ohne angemessene Korrekturen bereitzustellen. Wenn man durch systemd keine Schmerzen gespürt hat, ist man vielleicht spät dazugestoßen, oder die eigenen Bedürfnisse überschnitten sich zufällig mit denen der Kern-Maintainer.
execzu ersetzen.Ein Programm, das zu 100 % exakt das tut, was PID 1 tun muss, und sonst nichts, kann viel kleiner sein. Wenn man darauf systemd startet, führt ein Problem in systemd nicht sofort zu einer Kernel Panic.
Quelle: https://ewontfix.com/14/
cronzu vergessen, ist schwer nachvollziehbar. Es hat 50 Jahre lang gut funktioniert, und plötzlich soll es furchtbar falsch sein und selbstverständlich durch systemd ersetzt werden.fstabvergisst und systemd-Mounts verwendet, können die Automount-Regeln komplex sein, und selbst wenn man sie 1:1 an die Dokumentation anpasst, funktionieren sie manchmal einfach nicht, sodass Dateisysteme nicht rechtzeitig gemountet werden.Für Distributionen oder Upstreams macht es das Leben sehr viel leichter, fügt dafür aber in der untersten Systemschicht immer mehr Komplexität hinzu. Je nach Sichtweise kann man Dinge wie
journalctl,timedatectl, die dbus-Abhängigkeit oder entsprechende Alternativen als nicht vereinbar mit der Unix-Philosophie ansehen.Wenn es lediglich darum geht, Prozesse zu koordinieren, sie in der richtigen Reihenfolge auszuführen und automatische Aktivierung sicherzustellen, halte ich es für ein angemesseneres Werkzeug als k8s oder Docker.
Ich betreibe mein Homelab seit einiger Zeit mit podman-systemd, also Quadlet, und jedes Mal, wenn ich mir eine neue k8s-Variante angesehen habe, war sie den zusätzlichen Aufwand nicht wert. Es reicht völlig, in den alten Ansible-Playbooks Images vorab zu pullen und Unit-Dateien an die richtige Stelle zu legen.
Auch den gesamten Stack meines Voron-3D-Druckers lasse ich mit podman-systemd laufen, sodass ich alle Komponenten auf einmal aktualisieren und zurückrollen kann. Allerdings prüfe ich inzwischen auch einen Ansatz, bei dem mit
mkosiundsystemd-sysupdatekomplette Disk-Images auf einmal aktualisiert und zurückgerollt werden.Das Hauptproblem ist, dass die Leute meist nur
docker-compose-Dateien ausliefern, die man dann in systemd-Units umwandeln muss, und dass manche Docker-Images bei Benutzer- und Rechtekonfigurationen eine für Podman unnötige Komplexität mitbringen. Besonders wenn ein Container die Ausführung als root verweigert oder auf einen anderen Benutzer wechselt, braucht man mitunter lästigeuserns-ID-Mappings.Insgesamt ist es aber deutlich weniger komplex als jede k8s- oder k8s-Varianten-Konfiguration. Mir gefällt auch, dass alles sowohl in systemd als auch in journald integriert ist und nicht auf zwei Stellen aufgeteilt wird.
Man legt einfach nur die Units ab; das ist sehr stabil und simpel.
compose-Dateien in Quadlet-Dateien kann manpodletverwenden: https://github.com/containers/podletEs ersetzt aber nicht die Orchestrierungs- und Scheduling-Abstraktion über mehrere Nodes hinweg, die k8s bietet. Es fehlt der Teil: „Hier sind Maschinen, die Podman-systemd-Dateien ausführen können, und hier ist die Spezifikation, die ich ausführen möchte; bitte platziere sie passend.“
podman run-Befehl starten, prüfen, ob er richtig läuft, dann mitpodleteine grundlegende Container-Datei erzeugen und diese anpassen, indem Volumes und Netzwerke in andere Quadlet-Dateien ausgelagert werden – fertig.Das Projekt
podman-composescheint ebenfalls weiterhin aktiv gepflegt zu werden und kann eine gute Alternative zudocker-composesein. Die Integration von Podman und systemd ist aber so zufriedenstellend.Der nächste Schritt, um das noch weiter zu vereinfachen, ist, Container innerhalb von systemd mit Quadlet zu verwalten. Details gibt es unter https://www.redhat.com/en/blog/quadlet-podman.
docker composeauf rootless Podman Quadlet umgestellt; die Migration war mühsam, aber mit dem Ergebnis bin ich sehr zufrieden.Ich habe skate gebaut: https://github.com/skateco/skate. Im Grunde ist es genau für diesen Zweck gedacht, unterstützt aber mehrere Hosts und auch k8s-Manifeste. Intern nutzt es Podman und systemd.
Allerdings finde ich, dass k8s bei API und User Experience furchtbar ist. Die Docker-Compose-Spezifikation ist deutlich nutzerfreundlicher, daher experimentiere ich derzeit mit
docker-composefür mehrere Hosts: https://github.com/psviderski/uncloudIch bin wieder dazu zurückgekehrt, alles als deb-Pakete zu bündeln und direkt mit systemd auf EC2-Instanzen auszuführen; Container nutze ich nicht mehr. Die Instanzen laufen in einer Auto Scaling Group mit angebundenem ALB, und beim Booten installiert ein einfaches
ansible-pulldas deb.Das ist ziemlich roh, aber ich bin die endlosen HCL-Blöcke mit YAML in JSON leid. Inzwischen möchte ich nur noch ungefähr Ansible-YAML anfassen.
apt full-upgradeaus und startet nur die laufenden Prozesse neu – dann ist man geschützt.Man muss nichts neu bauen und auch nicht herausfinden, wie man eine Library aktualisiert, die tief in einem Container vergraben ist, den man vielleicht selbst gebaut hat oder vielleicht auch nicht.
Dank cgroup-Unterstützung eignet es sich auch gut, mehrere Dienste auf einem einzigen VPS laufen zu lassen.
Der Beitrag ist über ein Jahr alt; inzwischen gibt es mit ParticleOS sogar eine offizielle OS-Distribution von systemd für unveränderliche Workflows.
https://github.com/systemd/particleos
https://news.ycombinator.com/item?id=43649088
systemd-kernelzu ersetzen, dann wäre es komplett.Beim Lesen wirkt es so, als ließe sich all das durch den Befehl
docker composeund etwas wie Caddy, das automatisch Zertifikate holt, ersetzen.Wenn man nur eine
compose.yamlhat, reicht im Grunde eine Zeile:docker compose up -d --pull always. Für die CI-Konfiguration genügt auchscp compose.yaml user@remote-host:~/gefolgt vonssh user@remote-host 'docker compose up -d --pull always'.Der Vorteil ist, dass es einfach ist und auch auf der Entwicklungsmaschine funktioniert. Wenn das Nebenziel natürlich ist, etwas Interessantes auszuprobieren und dabei zu lernen, sind Quadlet, k8s und systemd ebenfalls gute Optionen.
docker context create --docker 'host=ssh://user@remote-host' remote-hostausführen.Danach kann man
docker -c remote-host compose -f compose.yaml up -d --pull alwaysverwenden und muss die Datei nicht kopieren. Wenn man außerdem die Benutzerinformationen in~/.ssh/confighinterlegt, muss man bei SSH-Aufrufen keinuser@mehr angeben, was es im Team einfacher macht, Dokumentation oder Befehle zu kopieren und zu verwenden.DOCKER_HOSTsetzen. Allerdings sollte man beachten, dass für die Interpolation in dercompose-Datei lokale Umgebungsvariablen verwendet werden.Weil ich finde, dass Deployments auf einen einzelnen Server nicht so kompliziert sein sollten, habe ich ein Tool gebaut, das so deployt, wie ich es möchte: https://harbormaster.readthedocs.io/
Harbormaster findet Repositories anhand einer YAML-Datei, klont und aktualisiert sie regelmäßig und führt dann die darin enthaltenen Docker-Compose-Dateien aus. Der gesamte Zustand liegt ebenfalls in einem einzigen Verzeichnis, was Backups einfach macht.
Wenn man nur einen einzelnen Server braucht, ist es unter den Container-Orchestrierungs-Tools, die ich bisher gesehen habe, das einfachste und beste. Mir gefällt, dass die gesamte Konfiguration im Repository deklariert ist, der gesamte Zustand in einem Verzeichnis liegt und alles einfach Compose-Dateien sind.
Beim Lesen der Kommentare hier fühle ich mich alt. Nutzt inzwischen niemand mehr einfach nur ssh und nginx?
Alles in eine Box stopfen, diese Box aggressiv sichern, fertig. Für den Heimgebrauch braucht man wirklich kein Microservice-Management.