⇒ In der DOAG gibt es seit kurzem eine Cloud Native Community. Diese beschäftigt sich nativ mit Cloud-Themen. Eins davon ist "GitOps". In Teil 1 von 3 wurde auf Methodik und Tooling von GitOps eingegangen, ebenso wurden die vier wesentlichen GitOps-Prinzipien vorgestellt. Im zweiten Teil des vierteiligen GitOps-Beitrags geht es um GitOps und Kubernetes.
--
Dieser mehrteilige Beitrag soll einen Eindruck zu GitOps vermitteln – wo es herkommt, wo es hingeht und was auf dem Weg liegt. Eins vorweg: "Die Cloud", respektive Kubernetes, verzeichnet zwar das erste Auftreten von GitOps, jedoch sind seine Prinzipien und die Einsatzmöglichkeiten universell; sie können – und sollen – damit natürlich nach Möglichkeit überall angewandt werden.
Außerdem sollte GitOps nicht isoliert betrachtet werden. Vielmehr verändern seine Prinzipien die Art und Weise, wie wir professionelle IT betreiben. Es ist das Puzzlestück, das viele 'gehypte' Themen der letzten Jahre erst sinnvoll ermöglicht: autarke Teams, echtes DevOps, ganzheitliches (Software) Engineering inklusive Betrieb aus einer Hand.
Nette Nebeneffekte, die sich einstellen, wenn man GitOps lebt, sind bessere Nachhaltigkeit bei der Arbeit durch die Vermeidung manueller Tätigkeiten und höhere Qualität unserer Systeme.
--
Kubernetes-Beispiel
⇒ Siehe dazu auch Abbildung 2 unten | Werfen wir einen Blick auf ein typisches Kubernetes-Setup mit GitOps in einer Public Cloud. Auf der linken Seite haben wir unsere Geschäftsanwendungen. Deren Quell-Code wird sowieso in Git verwaltet, Änderungen erfolgen nur nach Review und Freigabe durch ein Teammitglied. Die Anwendungen werden nach bester Manier gebaut und getestet, die dafür nötige Continuous-Integration wird natürlich zusammen mit dem Quell-Code versioniert. Mit etwas gutem Willen bekommt man sein Build-System schon ziemlich gut deklarativ hin, meist ist jedoch noch eine Portion Prozessuales dabei, das ist hier allerdings nicht weiter schlimm, da ein Build-Ergebnis nichts ist, was an einen Zustand angeglichen werden muss – gebaut oder nicht gebaut, das ist die einzige Frage. Das entstandene Artefakt, meist ein Container Image, wird in eine Container Registry geladen, damit ist die Anwendungsseite abgeschlossen. In den meisten GitOps-Modellen möchte man eine klare Trennung zwischen Continuous-Integration und Continuous-Delivery, da hiermit das "Pull-Prinzip" erzwungen wird. Mittig definieren wir die gesamte Basis-Infrastruktur. Alles als Code und auch deklarativ.
Je nach Plattform lassen sich die GitOps-Prinzipien im Infrastruktur-Bereich weitestgehend einhalten. Das Wichtigste ist jedoch, dass die automatischen Prozesse nicht umgangen werden. Sobald irgendeine Änderung nicht über die Infrastructure-as-Code Umgebung gemacht wird, riskiert man ein zukünftiges Problem. Die Umgebungen könnten sich voneinander unterscheiden, beim Disaster-Recovery könnte der manuelle Schritt vergessen werden. Durch die fehlende Dokumentation, die man über den Git-Commit bekommen würde, weiß sehr bald niemand mehr, warum oder dass überhaupt eingegriffen wurde. Meistens nutzen wir ja nicht nur eine, sondern viele Umgebungen: zur Entwicklung, für die Qualitätssicherung, zur Abnahme oder Voransicht durch die Fachabteilung und natürlich für die Produktion. Und keiner will, dass sich diese Umgebungen unterscheiden, außer vielleicht durch ihre operativen Daten und ihre Größenordnung. Sicherstellen können wir das wirklich nur, wenn es eine einzige Quelle der Wahrheit gibt, die als Vorlage für alle Umgebungen genutzt wird und jede einzelne Änderung einzig und allein an dieser Quelle der Wahrheit vorgenommen wird.
In diesem Beispiel stellen wir alles an Infrastruktur außerhalb Kubernetes mit Terraform bereit, Kubernetes-Konfigurationen nehmen wir aber bis auf das Bereitstellen von Umgebungsinformationen via ConfigMap oder Secret keine vor. Alles was innerhalb Kubernetes passiert, hat sein eigenes Repository (rechte Seite), das dann wirklich allen GitOps-Prinzipien folgt. Im GitOps-Repository liegen alle unsere Kubernetes Manifeste vor, gegebenenfalls für jede Umgebung ausgeprägt. Das Bild hier ist vollständig. Es gibt kein weiteres Konfigurationsmanagement, alle unsere Anwendungskonfigurationen sind im Git. Als ConfigMaps, Kustomize Values oder auch Secrets. Natürlich speichern wir keine Klartext-Geheimnisse im Git, die werden asymmetrisch verschlüsselt, sodass nur eine Komponente im Kubernetes Cluster selbst sie lesen und entschlüsseln kann – Tools hierfür sind zum Beispiel SealedSecrets, Kamus oder Mozilla SOPS, die Funktionsweise ist bei allen sehr ähnlich.
Jede Änderung, die an der Umgebung gemacht werden soll, muss dem Team als Pull-Request vorgelegt werden, nach erfolgtem Review darf man mergen und die Änderung wird in den Kubernetes Cluster übernommen. Der gewünschte Soll-Zustand kann übrigens auch etwas beschreiben wie: Ich hätte gern stets die neueste Version 2.x meiner Anwendung laufen. Dafür gibt es spezifische Komponenten in den verfügbaren GitOps Tools, die Container-Registries überwachen und, sobald eine entsprechende Version auftaucht, unsere Kubernetes-Manifeste im Git automatisch aktualisieren. Die wohl absolut schönste Variante eines Continuous-Deployment.
Klassisches IaC-Beispiel
⇒ Siehe dazu auch Abbildung 3 unten | Anwendungsbetrieb außerhalb Kubernetes mit GitOps durchzuführen ist momentan weniger verbreitet und benötigt etwas Kreativität, wie an dem vorigen Serverless-Function-Beispiel schon klar wurde. Was aber recht einfach zur erstklassigen GitOps-Implementierung wird, sind klassische Infrastructure-as-Code-Lösungen. Die kommen in der Cloud zwar tendenziell weniger häufig zum Einsatz, haben jedoch auch dort ihre Berechtigung. Übliche Umsetzungen erfüllen schon die meisten GitOps-Prinzipien. Die Deklarationen müssen eigentlich nur via Git verwaltet und verteilt werden. Puppet beispielsweise arbeitet schon nach dem Pull-Prinzip mit einem Agenten auf dem Zielsystem, bei Ansible könnte man die Durchführung nicht zentral, sondern dezentral durchführen, also einen Agenten darauf trimmen, sich ein Git-Repository zu klonen und das Playbook auf den eigenen Host anzuwenden. Wenn man seine Systeme inklusive Fachanwendungen also über eins dieser Systeme beschreiben und konfigurieren kann und noch einen regelmäßigen Abgleich durchführt, lässt sich GitOps auch wunderbar ohne Kubernetes spielen.
Klassische Betriebsmodelle
Dass Teams der Software-Entwicklung und des Betriebs unterschiedliche Werkzeuge und Vorgehensweisen nutzen, war früher kein großes Problem, da die beiden nichts miteinander zu tun hatten.
Mit DevOps kamen Entwicklungs-Kenntnisse in den Betrieb und Betriebs-Kompetenzen in die Entwicklung, bestimmte Werkzeuge wurden von beiden verwendet – dennoch war Tooling meist zweckgebunden. Zum Problem wird das, wenn man autarke Engineering-Teams bildet, die alle Funktionen in sich vereinen. Entweder es gibt dediziertes Personal je Tätigkeit oder die Teammitglieder müssen sich sehr breit aufstellen, um das ganze Spektrum an Werkzeugen und Vorgehensweisen abzudecken. Je mehr unterschiedliche Werkzeuge und Methoden im Einsatz sind, desto stärker leidet die Effizienz.
Zur Reproduzierbarkeit muss nicht viel gesagt werden. In dem Moment, in dem etwas manuell getan wird, im schlimmsten Fall mit der Maus auf einer graphischen Oberfläche, passieren Fehler. Besonders schlimm sind diese während eines Disaster-Recovery, wenn man unter Druck steht und dann die Dokumentation nicht vollständig korrekt oder nicht auf dem letzten Stand ist.
Dokumentation. Unser aller Lieblingsthema. Ja, die ist wichtig. Manchmal ist sie sogar zwingend nötig, wird aber gepflegt, wie bei Dokumentation üblich: unzureichend. Faktisch muss jeder Eingriff in das System, der vielleicht irgendwann mal wiederholt werden muss oder der für eine Analyse später mal relevant sein könnte, niedergeschrieben werden. Und zwar so, dass auch jeder andere als der Autor versteht, was getan wurde, wie es getan wurde und warum. Maximal nervig, und weil es nur durch äußerste Disziplin erreicht werden kann, kaum zu kontrollieren.
Die absolute Strafarbeit ist jedoch das Schreiben von imperativen Deployment-Prozessen. Abhängigkeiten müssen bedacht werden, jederzeit können Fehler auftreten und davon abhängig, wo und gegebenenfalls was der Fehler war, müssen Kompensationen ausgeführt werden, die natürlich auch wieder fehlschlagen können. Man kann nahezu unendlich viel Energie in die perfekte Deployment-Lösung stecken und trotzdem wird immer wieder etwas passieren, das man nicht bedacht hat und das noch nie vorher passiert ist.
⇒ In der letzten Folge von "GitOps: wieso, weshalb, warum" (Teil 3 von 3) am 16. September 2022 geht es um die Benefits von GitOps und die Anwendungsbereiche. Der Autor zieht zudem ein interessantes Fazit.
--
Bild: Gerd Altmann auf Pixabay



