Eigentlich wollte ich den zehnten LinkedIn-Post schreiben, der dir erklärt, warum Docker Compose die Antwort auf alle deine Lebensfragen ist und Kubernetes im Homelab verboten gehört.
Stattdessen betreibe ich jetzt eine einzelne MicroK8s-Node mit voller GitOps-Infrastruktur: ArgoCD steuert den Cluster, GitHub Actions patchen automatisiert meine Manifeste.
Brauche ich das für ein paar private Container? Nein.
Ist es völlig übertrieben? Auf jeden Fall.
Macht es auf einer Single-Node trotzdem verdammt viel Sinn? Japp.
Dieser bewusste Enterprise-Overkill hat mir in Sachen Kubernetes-Disziplin mehr beigebracht als jedes Standard-Tutorial. Ein Plädoyer gegen den ewigen Minimalismus-Trend und für produktiven Overengineering-Spaß.
Der Stack
Wenn man die Buzzwords weglässt, ist die Pipeline dahinter fast schon erschreckend linear. Der gesamte Kreislauf lässt sich auf einer Serviette skizzieren:
+-------------------+
| Mein Notebook |
+---------+---------+
|
| 1. Git Push (Code / Manifests)
v
+-------------------------------------------------------+
| GitHub Platform |
| |
| +-------------------+ +-------------------+ |
| | App / GitOps |======>| GitHub Actions | |
| | Repositories | 2. | (CI/CD Build) | |
| +---------+---------+ Trigger+---------+---------+ |
| ^ | |
| | | |
| +============================+ |
| 3. Bump Image Tag |
+-------------------------------------------------------+
|
| 4. Poll & Automated Sync
v
+-------------------------------------------------------+
| MicroK8s Node |
| |
| +-------------------+ +-------------------+ |
| | ArgoCD |======>| Deployed Apps | |
| | (GitOps Loop) | 5. | (Pods / State) | |
| +-------------------+ Deploy+---------+---------+ |
+-------------------------------------------------------+
^ ^
: :
:....... Injiziert Secrets ..:
:
+---------+---------+
| Infisical Vault |
| (Secret Central) |
+-------------------+
Und wo kommen die Secrets her? Da klinkt sich Infisical als moderner Vault-Ersatz ein, der sowohl GitHub Actions als auch den Cluster füttert.
Klingt simpel? Ist es im Prinzip auch. Der Teufel (und der Lerneffekt) steckt wie immer im Detail der einzelnen Zahnräder:
- Der Code-Lieferant (GitHub): Hier liegen die App-Repositorys und das zentrale GitOps-Repo mit den Kubernetes-Manifesten. Keine lokalen
kubectl apply-Aktionen mehr vom Notebook aus. Git ist das unbarmherzige Gesetz. - Der Bote (GitHub Actions): Sobald ich Code in einem App-Repo pushe, baut die Action das Image, schiebt es in die Registry und geht danach rüber zum GitOps-Repo, um dort den Image-Tag im Deployment-Manifest anzuheben.
- Der Türsteher (ArgoCD): Er lauert auf dem MicroK8s-Cluster und starrt ununterbrochen auf das GitOps-Repo. Kaum detektiert er den neuen Image-Tag, zieht er den Cluster glatt.
- Die Zentrale für Geheimnisse (Infisical): Secrets im Git-Repo sind bekanntlich die Todsünde des DevSecOps-Engineers. Infisical fungiert hier als Single Source of Truth für alles, was geheim bleiben muss. Es injiziert die Secrets in die GitHub Actions für den Build-Prozess und stellt sie dem Cluster via Operator zur Verfügung.
- Die Arbeiterklasse (MicroK8s): Die schönste Pipeline nützt ja nichts, wenn niemand die Kisten schleppt. MicroK8s ist hier der unaufgeregte Malocher auf der Node. Er nimmt den gesamten Arbeitsauftrag von ArgoCD entgegen, schmeißt die Pods an.
Für mich bleibt am Ende nur noch eins zu tun: Auf meinem Notebook in der IDE meiner Wahl Git Push, und der Rest passiert vollautomatisch im Hintergrund. Komplett overengineered für einen Single-Node-Cluster? Vielleicht. Aber es fühlt sich jedes Mal verdammt gut an, wenn die Sync-Lampe in ArgoCD auf Grün springt.
Warum kein Image Updater im Cluster? - Wenn die Action das Manifest bumpt
Wer GitOps und ArgoCD hört, landet bei der Automatisierung von Image-Updates fast unweigerlich beim ArgoCD Image Updater. Das Tool läuft im Cluster, pollt die Container-Registry und schmeißt das neue Image rein, sobald es da ist. Klingt im ersten Moment verlockend, bricht aber im zweiten Moment ein ungeschriebenes Gesetz.
Ich habe mich bewusst dagegen entschieden und lasse stattdessen meine GitHub Actions das GitOps-Repo patchen. Warum? Aus drei einfachen Gründen:
1. Das Git-Log lügt nicht
Wenn der Image Updater im Cluster arbeitet, mutiert das GitOps-Repository oft zur Black Box. Der Cluster weiß, was läuft, aber mein Git-Verlauf hinkt hinterher oder wird mit kryptischen automatisierten Commits zugemüllt, die man schwer nachvollziehen kann.
Wenn die GitHub Action den Image-Tag im Manifest bumpt, sehe ich bei jedem einzelnen Commit im GitOps-Repo:
- Wer hat es ausgelöst (der Commit der App)?
- Was wurde geändert (exakt der Image-Tag von
v1.2.3aufv1.2.4)? - Wann ist es passiert?
Git bleibt die unumstößliche Single Source of Truth. Wenn ich den Zustand von vor drei Tagen wiederhaben will, mache ich einen git revert und die Welt ist wieder in Ordnung. Try that mit einem In-Cluster Updater.
2. Der Cluster muss die Registry nicht kennen
Damit ein In-Cluster Image Updater weiß, dass ein neues Image existiert, muss er ununterbrochen meine Registry pollen. Das bedeutet: Ich muss Secrets für die Registry in den Cluster legen, Netzwerk-Verbindungen erlauben und dem Cluster eine Aufgabe aufbürden, die eigentlich in die CI/CD-Infrastruktur gehört.
Mein MicroK8s-Cluster hat genau eine Aufgabe: Den Zustand zu halten, den Git ihm vorgibt. Er muss nicht wissen, ob es auf GitHub neue Images gibt. Er wartet einfach, bis ArgoCD ihm sagt: "Hier ist das neue Manifest, zieh glatt."
3. Konstruktive Faulheit schlägt manuelle Arbeit
Sagen wir es, wie es ist: Ich habe das Setup nicht gebaut, um mich wie ein Enterprise-Architekt zu fühlen, sondern weil ich extrem faul bin. Ja, das initiale Aufsetzen der GitHub Action kostet einmalig Hirnschmalz und Nerven. Aber danach? Ist das System eine "Set and Forget"-Maschine.
Ich muss nie wieder manuell ein Manifest anfassen, nie wieder eine Registry pollende Config debuggen und mir bricht das Setup nicht weg, wenn sich im Cluster irgendwas ändert. Einmal richtig investierter Effort bedeutet: Ich pushe Code und kann danach Kaffee trinken gehen, während die Pipeline die Drecksarbeit macht.
Genau die Art von Faulheit die man auch im Job gebrauchen kann. Warum also im Homelab darauf verzichten?
Die Single-Node-Realität: Kein HA, aber maximale Entspannung
Machen wir uns nichts vor: Wer eine Single-Node betreibt, hat kein High Availability (HA). Wenn die Hardware die Grätsche macht oder der Strom weg ist, herrscht erst mal Funkstille. Da hilft auch das beste Kubernetes nichts. Aber die Architektur dahinter bringt zwei massive Vorteile mit, die man selbst mit modernen Podman- oder Docker-Setups nur schwer hinbekommt.
Das Pull-Prinzip: Warum mein Server keine SSH-Keys der CI kennt
Versteh mich nicht falsch: Man kann auch mit Podman (Stichwort: Quadlets und Systemd) oder Docker extrem sauber und deklarativ arbeiten. Man kann sogar CI/CD-Pipelines bauen, die Container remote via SSH-Verbindung auf dem Server verwalten.
Aber genau da liegt das Sicherheitsrisiko: Beim klassischen Push-Prinzip muss meine GitHub Action aktiv eine SSH-Verbindung zu meinem Server im Homelab aufbauen dürfen. Ich muss also hochsensible SSH-Credentials oder Zertifikate als Secrets bei GitHub hinterlegen. Fliegt GitHub oder mein Repository morgen auf, hat ein Angreifer im schlimmsten Fall direkten Zugriff auf meine Hardware im Keller.
Mein ArgoCD-Setup dreht den Spieß um und nutzt das Pull-Prinzip. Der Cluster hockt hinter meiner Firewall und pollt das Git-Repo passiv von innen nach außen. Meine GitHub Actions bauen nur das Image und patchen das Manifest – sie wissen überhaupt nicht, wo mein Server steht, und besitzen keinerlei Zugangsdaten für meine Infrastruktur.
Kontinuierliche Kontrolle statt Einmal-Schuss
Wenn du bei Docker oder Podman einen Container manuell abschießt (podman rm -f app), bleibt er im schlimmsten Fall tot, bis die CI/CD-Pipeline das nächste Mal getriggert wird oder Systemd nachhilft.
ArgoCD läuft als permanenter Reconciliation Loop. Es starrt ununterbrochen auf den IST-Zustand des Clusters und gleicht ihn mit dem SOLL-Zustand im Git ab. Lösche ich manuell einen Pod, merkt ArgoCD das in Sekundenbruchteilen und baut ihn sofort exakt so wieder auf, wie Git es verlangt.
"Backup-Free" für die Infra – S3 für die harten Daten
Auch beim Thema Daten bleiben wir ehrlich: "Backup-Free" bedeutet natürlich nicht, dass ich russisches Roulette mit meinen Daten spiele. Wenn die Node morgen explodiert, sind meine Datenbank-Dumps und PVC-Backups dank automatisierter CronJobs sicher in einem externen S3-Storage geparkt.
Der Clou ist aber: Selbst diese Backup-Infrastruktur ist komplett deklarativ. Wenn ich das System neu aufsetzen muss, installiere ich das OS, werfe MicroK8s an und lasse ArgoCD aufs Repository zeigen. Der Cluster baut sich exakt so wieder auf, wie er vorher war, zieht sich die Backup-Routinen und ist bereit, die Daten wieder einzuspielen. Keine Snowflake-Server, keine manuellen Restore-Skripte auf der Host-Ebene.
Was ich dabei wirklich gelernt habe
Ein Homelab verleitet dazu, schlampig zu werden. Man wirft einen Container an, mappt die Ports auf den Host, und solange die Kiste läuft, hinterfragt man nichts. Mein überzogenes GitOps-Setup hat mich zu einer ganz neuen Disziplin gezwungen. Das sind die drei wichtigsten Learnings, die ich eins zu eins in meinen Job als DevOps-Engineer mitnehmen kann:
1. Das Gesetz der Resource Limits
In der Cloud klickt man sich im Zweifel einfach eine größere Instanz oder lässt den Cluster im Autoscaling-Rausch aufgehen. Wenn du aber nur eine einzige Node im Keller hast, herrscht harte Ressourcen-Knappheit.
Hier lernst du echtes Resource Management. Wenn ein Pod Amok läuft und keine resources.limits gesetzt hat, reißt er dir das gesamte Homelab in den Abgrund. Der OOMKilled (Out Of Memory) Code wird zum guten Bekannten. Ich musste lernen, exakt zu analysieren: Was braucht meine App wirklich an CPU und RAM im Idle, und was unter Last? Diese Präzision verliert man in der Cloud schnell aus den Augen.
2. GitOps-Disziplin (Die Finger bleiben von kubectl weg)
Es ist Samstagabend, 23:00 Uhr, und eine App zickt. Der Impuls ist riesig: Kurz per Terminal auf den Cluster schalten, kubectl edit deployment... eintippen, die Umgebungsvariable live ändern und fertig.
Wenn du GitOps konsequent durchziehst, ist das vorbei. Warum? Weil ArgoCD deine manuelle Änderung fünf Sekunden später sieht, sie als Out of Sync deklariert und gnadenlos mit dem Zustand aus dem Git-Repo überschreibt. Dieses Setup zwingt dich zu der mentalen Härte: Jede Änderung, und sei sie noch so klein, geht über ein Git-Commit. Das tut am Anfang weh, spart dir aber langfristig das typische "Was habe ich da letzte Woche eigentlich live auf dem Server gepatcht?"-Rätselraten.
3. Least Privilege ohne Schmerzen (Weil es im Repo liegt)
Machen wir uns nichts vor: Kubernetes zwingt dich erst mal nicht dazu, ein RBAC-Gott (Role-Based Access Control) zu werden. Du kannst deine Apps auch völlig ohne tiefes Rechtemanagement und dedizierte ServiceAccounts in den Cluster werfen. Es läuft trotzdem.
Der Aha-Moment kommt durch GitOps: Weil du jede Konfiguration deklarativ als Code ablegst, ist es plötzlich erschreckend einfach, Rechte ordentlich einzuschränken. Statt kryptische kubectl-Befehle für ServiceAccounts und RoleBindings auf der Konsole zusammenzufrickeln, schreibst du das YAML einfach direkt neben dein Deployment ins Repository. Du siehst die Berechtigungen deiner App im Git-Verlauf, kannst sie sauber versionieren und stückweise einschränken (Least Privilege), ohne Angst zu haben, dir den Cluster unbemerkt zu zerschießen. GitOps nimmt dem Rechtemanagement die typische Einstiegshürde.
Wo das Setup nicht hingehört
Zum Schluss müssen wir die Kirche im Dorf lassen: Ein Homelab – selbst wenn es auf professioneller Hardware im Serverraum läuft – ist keine Production-Umgebung.
Für produktive Kunden-Anwendungen auf Enterprise-Ebene gelten verständlicherweise andere Regeln. Da geht es um Business-Impact, SLAs und echte Hochverfügbarkeit. Je nachdem, wie kritisch die App ist, plant man da eben mit Multi-Node-Clustern und redundanten Netzanbindungen, damit ein Hardware-Schaden nicht sofort den Betrieb lahmlegt. Da stößt eine Single-Node konzeptionell einfach an ihre Grenzen.
Aber darum geht es hier gar nicht.
Der unschlagbare Wert dieses Setups liegt im Prinzip. Egal, ob am Ende eine einzelne Node für Testzwecke läuft oder ein großer Cluster in der Produktion: Der GitOps-Workflow, die Automatisierung über die GitHub Action, das Secret-Management via Infisical und die ständige Synchronisation durch ArgoCD bleiben exakt gleich.
Wer gelernt hat, eine Single-Node konsequent deklarativ, sicher und aus Git heraus zu füttern, der baut auch in der echten Production-Welt keine unwartbaren "Snowflake-Server", die beim kleinsten Windhauch umfallen.
Vielleicht ist ein Single-Node-GitOps-Setup rein rational gesehen erst mal übertrieben. Aber es ist die beste, sicherste und faulste Spielwiese, die man sich als Engineer bauen kann.