Git-hog Day

6 min read• By Stephane Segning Lambou
Blog
GitOps ist kein simpler Deploy-Button: Reconciler setzen manuelle Hotfixes gnadenlos zurück. Warum Git die einzige Wahrheit ist und wie man nächtliche Incidents im Cluster meistert.

Was jeder zu „wissen“ glaubt: GitOps bedeutet einfach nur „Deployen über Git statt von meinem Laptop aus“. Und Self-Healing ist großartig – es sorgt dafür, dass der Cluster immer genau dem entspricht, was ich will.

Was tatsächlich passiert: Der Cluster hat plötzlich einen eigenen Willen. Wer im Notfall einen Hotfix manuell auf Production einspielt, erlebt, wie ein unermüdlicher Roboter die Änderung wenige Minuten später klammheimlich rückgängig macht – ohne Nachfrage, ohne Warnung. Und „was ich will“ ist dummerweise über zwei verschiedene Repositories verteilt, sodass sich ein halbfertiges Release ganz von allein zurückrollt. Patchen. Revertieren. Wiederholen.

Teil einer kleinen Reihe für alle, die zusehen, wie KI die Welt übernimmt, während das eigene Deployment-System anfängt, ihre Hotfixes zu fressen. Der Titel ist eine Anspielung auf Groundhog Day (Und täglich grüßt das Murmeltier) mit Bill Murray – der Film, in dem er immer wieder am Anfang desselben Tages aufwacht, bis er seine Lektion gelernt hat. Ihr werdet gleich sehen, warum.

Der Glaube: Git ist nur ein schickerer Deploy-Button

Die meisten lernen GitOps als „kubectl apply, aber aus der CI“ kennen. Man mergt eine Änderung, eine Pipeline rollt sie aus, fertig. Dasselbe mentale Modell wie bei jedem Deployment bisher – Git dient lediglich als Startrampe.

flowchart LR
G[Merge to Git] --> CI[Pipeline pushes it] --> P[Production]
style P fill:#cfe8ff,stroke:#3b82f6
Cover Gitops

In diesem Modell ist Production etwas, wohin man Änderungen pusht. Man selbst ist der aktive Part; der Cluster ist ein passives Ziel, das tut, was man ihm sagt, und dann abwartet.

Echtes GitOps kehrt dieses Prinzip komplett um – und genau in dieser Umkehrung liegt der Knackpunkt. Der Cluster ist kein Ziel, auf das man pusht, sondern ein eigenständiger Agent: Er vergleicht sich kontinuierlich mit dem Git-Repository und bügelt jede gefundene Abweichung gnadenlos aus, für immer. Das klingt fantastisch – bis zu dem Moment, an dem man selbst die Abweichung darstellt.

Die Realität: Ein Roboter, der deine Änderungen seelenruhig in Dauerschleife zurücksetzt

Man stelle sich einen echten Incident um 2 Uhr nachts vor: Irgendwo brennt es lichterloh, der Fix besteht aus einem einzigen Feld, und für einen kompletten PR-Review-Merge-Zyklus fehlt schlicht die Zeit. Also macht man, was jeder Engineer schon einmal getan hat: Man patcht Production direkt von Hand. Es funktioniert. Das Feuer ist gelöscht. Man legt sich wieder schlafen.

Ein paar Minuten später wacht der Reconciler auf, bemerkt, dass Production nicht mehr mit Git übereinstimmt, und setzt – ohne Rückfrage, Warnung oder zeitnah sichtbare Logs – den Fehler wieder zurück. Der Alarm schlägt erneut an. Man patcht wieder. Der Roboter revertiert wieder.

flowchart TD
Fix["🔧 You hand-patch prod (fire out)"] --> Sync{Reconciler: does live match Git?}
Sync -->|"no — your patch isn't in Git"| Revert["↩️ Reverts to Git (bug returns)"]
Revert --> Alert["🔔 Alert fires again"]
Alert --> Fix
style Revert fill:#fee2e2,stroke:#ef4444
style Fix fill:#fde68a,stroke:#f59e0b
Image 2

Patchen. Revertieren. Wiederholen. Man wird zu Bill Murray, die Zeitschleife heißt Self-Healing, und es gibt keinen Prompt, kein Approval-Gate, kein „Sind Sie sicher?“. Das System funktioniert nicht fehlerhaft – es tut haargenau das, wofür es gebaut wurde. Seine Aufgabe lautet: „Der Cluster muss Git entsprechen.“ Da der Hotfix schlicht nicht in Git steht, ist aus Sicht des Roboters der Fix der Bug und der Bug die Single Source of Truth.

Der Weg aus der Schleife ist die eigentliche Lektion: Bei GitOps ändert man nicht Production. Man ändert Git und lässt Production nachziehen. Die Notausgänge lauten: (a) Den Fix als Einzeiler committen, damit der Reconciler für einen arbeitet, oder (b) die Reconciliation explizit pausieren, solange man arbeitet – und daran denken, sie wieder zu aktivieren (eine eigene klassische Fehlerquelle). Es gibt keine dritte Option, bei der man gewinnt, indem man schneller patcht als der Roboter. Der Roboter schläft nie.

🤓 Für die Nerds: Hier greift selfHeal: true, typischerweise kombiniert mit prune: true. Dadurch setzt der Reconciler nicht nur manuelle Edits zurück, sondern löscht im Live-Betrieb auch alles restlos, was nicht in Git deklariert ist. Dieser Trade-off ist beabsichtigt: Man opfert die Möglichkeit, Production mal eben unbemerkt von Hand zu flicken, und bekommt im Gegenzug einen Cluster, der niemals unbemerkt vom deklarierten Zustand abdriften kann. Determinismus, erkauft durch Flexibilität. Lohnt sich – solange jedem diese Spielregeln vor dem 2-Uhr-nachts-Vorfall klar sind und nicht erst mittendrin.

Die Realität, Teil zwei: „Was ich will“ liegt in zwei verschiedenen Repos

Hier kommt die zweite Tücke – und genau die erwischt selbst Teams, die das Prinzip von Self-Healing eigentlich verstanden haben.

Man sollte annehmen, die laufende Version einer App werde in deren eigenem Repository bestimmt. Oft ist das nicht der Fall. Ein verbreitetes Setup trennt das: Das App-Repo enthält den Code und die Helm-Charts, aber ein separates Delivery-Repo enthält die entscheidende Zeile, welche Version tatsächlich live ist – den Versions-Pin. Und der Reconciler überwacht genau diesen Pin.

flowchart LR
subgraph appR[App repo]
Tag["release tag v2 exists here"]
end
subgraph delR[Delivery repo]
Pin["the pin says: deploy v1"]
end
Pin --> Recon[Reconciler] --> Live["Production runs v1"]
Tag -.->|"you cut v2 but forgot the pin"| Oops
style Live fill:#fde68a,stroke:#f59e0b
Image 3

Man rollt also ein Release aus: Man taggt v2 im App-Repo, pusht es und sieht zu, wie es deployed wird. Und dann … rollt es sich ganz von allein wieder auf v1 zurück, und man verbringt eine Stunde mit der Fehlersuche. Die Ursache: Der Tag im App-Repo wurde zwar erhöht, aber der Pin im Delivery-Repo blieb unverändert. Das Self-Healing zieht Production pflichtbewusst auf das zurück, was der Pin vorschreibt – und der steht nun mal auf v1. Das „Release“ war lediglich ein vorübergehender Vorschlag, den der Reconciler höflich abgelehnt hat.

Das ist dieselbe Schleife wie beim Hotfix, nur eine Abstraktionsebene höher. Der Cluster gleicht sich mit dem deklarierten Zustand ab, und die Deklaration, die man vergessen hat zu aktualisieren, behält recht. Ein Release ist nicht fertig, wenn die neue Version läuft; es ist erst fertig, wenn jede einzelne Source of Truth ihr Einverständnis erklärt hat.

Dasselbe System, ehrlich aufgezeichnet

flowchart TB
Truth["The declared state (across all repos)"] --> Recon["Reconciler<br/>(compares + corrects, forever)"]
Recon --> Live[Production]
Live -. "any drift — your patch, a half-done release" .-> Recon
Recon -. "pulled back to match the declaration" .-> Live
style Recon fill:#cfe8ff,stroke:#3b82f6
style Truth fill:#d1fae5,stroke:#10b981
image 4

Production ist lediglich der Schatten des deklarierten Zustands, kein Ort für direkte manuelle Eingriffe. Alles, was an GitOps großartig ist, und alles, was daran überrascht, leitet sich aus dieser einen Tatsache ab.

Schön und gut – aber „Production niemals manuell anfassen“ ist ein Luxus, den man nachts um 3 Uhr selten hat

Determinismus ist herrlich – bis das Gebäude brennt. „Ändere Git, nicht den Cluster“ setzt voraus, dass man Zeit für einen Commit-Review-Merge-Reconcile-Zyklus hat; mitten im Ausfall hat man die nicht. Ein Reconciler, der den eigenen Notfall-Patch bekämpft, schützt das System in diesem Moment nicht – er verlängert den Ausfall.

Die Lösung liegt nicht darin, Self-Healing abzuschaffen, sondern den Notfall-Bypass („Break-Glass“) als erstklassigen, eingeübten Pfad bereitzustellen: Ein einziger Befehl, der die Reconciliation für diese spezifische App pausiert – zuvor im Team trocken geübt, abgesichert durch einen Alarm, der an das spätere Reaktivieren erinnert. GitOps-Purismus ohne schnellen manuellen Override ist keine Disziplin, sondern pure Fragilität. Teams, die Incidents unbeschadet überstehen, nutzen Self-Healing als Standardzustand im Normalbetrieb, haben aber für den Ernstfall immer die Axt hinter Glas griffbereit.

Die Kernaussagen

  1. Der Cluster hat Eigeninitiative: Self-Healing macht jede manuelle Abweichung von Git gnadenlos rückgängig – inklusive Notfall-Hotfixes, vollautomatisch und in Endlosschleife. Dieses Verhalten muss allen klar sein, bevor der Incident eintritt.

  2. Production ändert man nur über Git: Manuelles Patchen ist ein Kampf, den man systembedingt verliert. Den Fix sauber committen (dann arbeitet der Roboter für einen) oder die Reconciliation bewusst pausieren.

  3. Was live ist, kann über mehrere Repos verteilt sein: Hält ein separates Delivery-Repo den Versions-Pin, rollt sich ein Release, das nur in einem Repo angepasst wurde, unweigerlich zurück. Entweder alle Sources of Truth sind aktualisiert, oder es ist schlicht nicht ausgeliefert.

  4. Determinismus ist das Feature, kein Bug: Man gibt die Freiheit des heimlichen manuellen Eingreifens auf und erhält dafür einen Cluster, der stets einer überprüfbaren, versionierten Deklaration entspricht. Ein fairer Deal – solange er von vornherein transparent ist.

  5. Den Notfallhammer bereithalten: Self-Healing ist der richtige Normalzustand, aber Incidents erfordern einen einstudierten Ein-Befehl-Bypass. Dogmatismus ohne manuelle Übersteuerungsmöglichkeiten ist nicht diszipliniert, sondern fragil.

GitOps ist kein schickerer Deploy-Button; man übergibt damit das Steuer an einen unerbittlichen, sturen Roboter, dessen einziger Lebenssinn darin besteht, die Realität mit dem geschriebenen Dokument in Einklang zu bringen. Stimmt das Dokument, hält er die Plattform makellos zusammen. Versucht man jedoch, per Hand gegen ihn zu argumentieren, wacht man jeden Morgen wieder am selben schlechten Tag auf – bis man aufhört, sich ihm in den Weg zu stellen.

Nächste Beiträge

Erste Schritte mit DataSafe: Dateien sicher verschlüsseln, freigeben und versionieren

Erste Schritte mit DataSafe: Dateien sicher verschlüsseln, freigeben und versionieren

Erfahren Sie, wie Sie DataSafe mit Docker einrichten, um Dateiinhalte und -pfade transparent zu verschlüsseln, Dateien sicher zu teilen und Versionen zu verwalten.

Mehr erfahren
Bereitstellung einer Node.js-Anwendung mit Kustomize auf Minikube

Bereitstellung einer Node.js-Anwendung mit Kustomize auf Minikube

Erfahre, wie du eine Node.js-App mit Kustomize auf Minikube bereitstellst. Verwalte Dev-, Staging- und Prod-Umgebungen mühelos ohne komplexe Templates oder doppelte YAML

Mehr erfahren
Keycloak × Stripe: Unsichtbares Marktplatz-Onboarding mit ereignisgesteuerter Architektur aufbauen

Keycloak × Stripe: Unsichtbares Marktplatz-Onboarding mit ereignisgesteuerter Architektur aufbauen

Erfahren Sie, wie Sie ein nahtloses Marktplatz-Onboarding durch die Integration von Keycloak und Stripe Connect mit reaktivem Kotlin und AMQP aufbauen.

Mehr erfahren
© 2026 adorsys. Alle Rechte vorbehalten.
Certificate TopCompany Kununu
Certificate ISO 27001
Certificate ISO 9001