GitOps geht auch ohne Kubernetes – alternative Betriebsumgebungen

Im GitOps-Universum ist Kubernetes erfolgreicher Standard: Eine Betriebsumgebung lässt sich jedoch auch transparenter und zuverlässiger konfigurieren.

In Pocket speichern vorlesen Druckansicht 1 Kommentar lesen
Steuerrad vor Wolken

(Bild: iX)

Lesezeit: 20 Min.
Von
  • Anja Kammer
Inhaltsverzeichnis

"GitOps funktioniert nur mit Kubernetes als Betriebsplattform!" Dieses Missverständnis hält sich hartnäckig und ist vermutlich der Grund, weshalb GitOps nicht längst der Standard-Workflow für Software-Delivery-Prozesse ist. Wer GitOps einsetzen möchte, findet nahezu ausschließlich Tooling, das Kubernetes voraussetzt. Im Kern gibt GitOps aber lediglich vor, dass ein Version Control System (VCS) wie Git als Schnittstelle für einen Software-Agent dient, der Deployment- und Betriebsaufgaben innerhalb einer Zielumgebung ausführt.

Anja Kammer

(Bild: 

INNOQ

)

Anja Kammer ist Senior Consultant bei INNOQ und entwickelt hauptsächlich Cloud-native Webanwendungen. Ihre Schwerpunkte liegen in den Bereichen DevOps, Cloud-Infrastruktur und Kubernetes.

iX-tract
  • GitOps-Definition: Ein Software-Agent führt Deployment- und Betriebsaufgaben aus einem Version Control System heraus aus.
  • Im Kubernetes-Universum hat sich GitOps dank umfassenden Toolings als Standard-Workflow für Software-Delivery-Prozesse etabliert.
  • Anhand der vom OpenGitOps-Projekt definierten Prinzipien lässt sich GitOps auch auf andere Betriebsumgebungen übertragen.

Als Weaveworks das GitOps-Konzept populär gemacht hat, war Kubernetes bereits als De-facto-Standard für moderne Betriebsplattformen anerkannt. Es ist eine standardisierte Betriebsumgebung, die eine einfache Verwaltung der Ressourcen über eine API ermöglicht. Daher ist es sinnvoll, neues Tooling auch bevorzugt für Kubernetes zu entwickeln.

Allerdings ist das nicht für jedes Team und jedes Softwaresystem sinnvoll. Ein kleines Team könnte Schwierigkeiten haben, die Komplexität von Kubernetes zu bewältigen und nötiges Know-how aufzubauen. Selbst die bloße Verwendung und Konfiguration eines vom Cloud-Provider betriebenen Kubernetes-Clusters erweist sich in vielen Fällen schon als komplexe Herausforderung. Stattdessen ist es für kleinere Organisationen möglicherweise besser, auf stärker abstrahierte Plattformen wie Heroku zurückzugreifen.

Dasselbe Prinzip lässt sich auf die Größe und Komplexität des zu betreibenden Softwaresystems anwenden. Wenn lediglich eine Handvoll Container deployt werden sollen, übersteigt die Komplexität des Betriebs von Kubernetes den Nutzen. Für große Systemlandschaften andererseits kann es sinnvoller sein, eine eigene Kubernetes-basierte Infrastruktur aufzubauen, da es langfristig kosteneffektiver sein kann, eigene Kompetenz aufzubauen, und mehr Flexibilität bietet.

Heise-Konferenz: CLC 2024

Im November 2024 richten iX und dpunkt.verlag die CLC-Konferenz – Continuous Lifecycle/ContainerConf – im Congress Center Rosengarten in Mannheim aus. Das Event greift seit 2014 alljährlich die wichtigsten Fragestellungen rund um Continuous Integration (CI), Continuous Delivery (CD), Dev(Sec)Ops und GitOps auf, um Antworten, Know-how und Hilfestellung für den Projektalltag zu vermitteln. Vom 12. bis 14. November setzt die CLC dieses Mal auf Themenschwerpunkte zu KI-gestütztem DevOps, Security und FinOps sowie Nachhaltigkeit.

Highlights aus dem Programm

Bis zum 23. September können sich Interessierte zum Frühbucherpreis von 1049 Euro registrieren, Workshops kosten 649 Euro (alle Preise zzgl. MwSt.).

Darüber hinaus gibt es auch Organisationen, die bereits mit ihrer bestehenden Betriebsplattform zufrieden sind oder aufgrund laufender Verträge an eine bestimmte Plattform gebunden sind. Dennoch sollten die Organisationen, die Kubernetes nicht einsetzen können, von den Vorteilen profitieren können, die GitOps bietet:

  • Einfache und schnelle Fehlerbehebung
  • Sichere Deployments
  • Sich selbst dokumentierende Deployments
  • Leichtere Personalbesetzung und schnelleres Onboarding

Abbildung 1 zeigt eine stark vereinfachte Darstellung eines GitOps-Workflows mit Kubernetes. Im Zentrum des Workflow-Modells steht das Repository, das Änderungen an der Anwendung aufzeichnet. Eine Build-Pipeline wird von Aktivitäten im Repository getriggert, die die Anwendung aktualisiert.

In einem GitOps-Workflow mit Kubernetes spielt der GitOps-Operator eine entscheidende Rolle (Abb. 1).

Im Kubernetes-Cluster befinden sich der GitOps-Operator sowie die von ihm gemanagten Applikationen. Die Definition eines Operators im Kubernetes-Universum ist sehr spezifisch. Ein Operator ist speziell darauf ausgelegt, eine Anwendung oder einen Service innerhalb des Clusters zu verwalten und zu betreiben. Ein Operator kann dabei auch komplexe Aufgaben wie die Konfiguration von Load Balancern oder die Integration mit anderen Services übernehmen.

Der Operator hat also die Aufgabe, erst nach dem vollständigen Durchlaufen der Build-Pipeline die Anwendung in die Betriebsumgebung, den Kubernetes-Cluster, zu deployen. Üblicherweise beschreibt dabei der Main-Branch die aktuell deployfähige Softwareversion, alternativ lassen sich Git-Tags verwenden. Einige Komponenten wie die Image-Registry fehlen in der Abbildung, sind aber selbstverständliche Bestandteile des Systems. Das Repository enthält die gesamte Anwendungs- und Infrastrukturkonfiguration, mit deren Hilfe sich eine Anwendung jederzeit von Grund auf deployen und regelmäßig aktualisieren lässt. Der Build-Pipeline fällt dabei ebenfalls die Aufgabe zu, die Infrastrukturkonfiguration zu testen. Auch das Ausführen von Integrationstests ist so leicht umsetzbar. Das Repository kann zudem den eigentlichen Anwendungscode enthalten, um die Umgebungskonfiguration gemeinsam mit der Anwendung selbst zu versionieren.

Die Bezeichnung dieses Repositories kann je nach Präferenz variieren, im Folgenden soll der Begriff Environment-Repository verdeutlichen, dass die enthaltene Anwendungs- und Infrastrukturkonfiguration idealerweise eine vollständige Betriebsumgebung mit all ihren nötigen Komponenten (beispielsweise Web-Worker, Scheduler, Funktionen und Persistenz) abbildet.

Abbildung 2 zeigt einen GitOps-Prozess ohne Kubernetes. Gegenüber Abbildung 1 ändern sich lediglich die Bezeichnungen: Die allgemeine Betriebsumgebung ersetzt den Kubernetes-Cluster. Kubernetes lässt sich auch als eine Betriebsumgebung bezeichnen. Aus dem Operator wird ein generisches GitOps-Tool, meint aber im Prinzip dasselbe. Abbildung 2 spiegelt damit wider, dass die Konzepte aus dem Kubernetes-Universum auf andere Betriebsumgebungen übertragbar sind. Zu den beiden essenziellen Komponenten Operator und Betriebsumgebung folgen in den nächsten Abschnitten detaillierte Definitionen.

GitOps-Workflow ohne Kubernetes: Eine generische Komponente übernimmt die Aufgaben des GitOps-Operators, aus dem Cluster wird eine allgemeine Betriebsumgebung (Abb. 2).

Im Kubernetes-Universum ist das Operator-Konzept klar definiert. Den Operator kennzeichnen folgende Eigenschaften:

  • Überwacht, verwaltet und steuert Ressourcen in einer Betriebsumgebung.
  • Agiert als intelligente Schicht, die diese Aufgaben anhand bestimmter Verhaltensregeln ausführt.
  • Ist ein Stück konfigurierbare Software, programmiert mit diesen Verhaltensregeln.

Ein Operator lässt sich als ein Hintergrundprozess oder Agent betrachten. Ein Daemon ist solch ein Hintergrundprozess, der auf einem Linux-System läuft und bestimmte Aufgaben ausführt, während der Agent eine Softwarekomponente ist, die für das Überwachen, Verwalten oder Steuern eines bestimmten Systems oder Dienstes zuständig ist. Ein Agent lässt sich als eine Art Daemon betrachten, der speziell für die Aufgabe der Verwaltung oder Überwachung entwickelt wurde.

Es gibt die Rolle eines Operators, als menschliches Mitglied einer Operations-Abteilung. Ein menschlicher Operator ist ebenfalls für das Überwachen und Verwalten von Systemen verantwortlich, ob Software oder Hardware. Darum ist es wichtig, bezüglich der Definition von Operatoren nicht dogmatisch zu sein.

GitOps sagt aus, dass ein Versionskontrollsystem wie Git als Schnittstelle für einen Operator dient, der wiederum Deployment- und Betriebsaufgaben innerhalb einer Zielumgebung ausführt. In Anbetracht dieser Konzepte lässt sich GitOps-Tooling, das innerhalb der Zielumgebung läuft, ebenfalls als Operator betrachten – zumal dieser Begriff nicht auf das Kubernetes-Universum beschränkt ist. Daraus lässt sich ableiten, dass Organisationen, die kein Kubernetes-natives GitOps-Tooling etabliert haben, eigene Operatoren bauen können. Dabei ist lediglich zu klären, welche Kernfunktionen implementiert sein müssen.

Viele der vorhandenen Kubernetes-nativen GitOps-Tools haben zahlreiche nützliche Funktionen, die den Betrieb erleichtern. Einige davon sind jedoch für einen GitOps-getriebenen Workflow nicht notwendig. Das OpenGitOps-Projekt hat dazu Prinzipien definiert, aus denen sich die Kernfunktionen eines GitOps-Operators ableiten lassen.

"Bei einem von GitOps verwalteten System sollte der gewünschte Zustand deklarativ ausgedrückt werden." Dieses erste Prinzip setzt eine deklarative Beschreibung des gewünschten Zustands (Desired State) eines von GitOps verwalteten Systems voraus. Diese Zustandsbeschreibung lässt sich mit beliebigen Infrastructure-as-Code-Tools erstellen, die oft auch für Anwendungskonfigurationen zum Einsatz kommen. Das verwendete GitOps-Tool beziehungsweise der Operator muss dann herausfinden, wie sich der vorhandene Zustand des Systems in den gewünschten überführen lässt und diese Transformation vornehmen. Darüber hinaus hängt die Umsetzung dieses Prinzips von der Definition der Infrastruktur- und Anwendungskomponenten ab. Dient beispielsweise Terraform als Deployment- und Provisioning-Tool, gilt das Prinzip bereits als erfüllt.

"Der gewünschte Zustand wird auf eine Weise gespeichert, die Unveränderlichkeit und Versionierung erzwingt und eine vollständige Versionshistorie aufbewahrt." Um beim Terraform-Beispiel zu bleiben: Das zweite Prinzip gilt als erfüllt, wenn die Terraform-Dateien im Environment-Repository abgelegt sind. Dabei ist jedoch das Neuschreiben der Git-Historie zu unterbinden, da sich ansonsten die Commit-Historie manipulieren lässt.

Das ist nicht nur für die Produktivumgebung, sondern auch für Dev- und Test-Umgebungen wichtig und ermöglicht, jederzeit auf frühere Versionen der Zustandsbeschreibung zurückzugreifen. Eine lückenlose und nachvollziehbare Historie ist zwar hübsch, aber man braucht sie bei der täglichen Arbeit nur, um Fehler zu finden oder für Rollbacks.

"Software-Agents ziehen die Beschreibung des gewünschten Zustands automatisch aus der Quelle." Während traditionelle CI/CD-Systeme (Continuous Integration / Continuous Delivery) einem Push-basierten Workflow folgen, bei dem der Deployment-Prozess Zugriff auf die Zielumgebung über ein Token, einen Schlüssel oder ein Zertifikat erhält, sieht das dritte Prinzip des OpenGitOps-Projekts ein Pull-basiertes Deployment vor, also das Ziehen der Konfiguration. Push-basierte Workflows gelten als vulnerabel, denn sobald das CI/CD-System kompromittiert ist, lässt sich der Zugriff zur Zielumgebung ausnutzen. In der Regel verwalten zentrale Build-Server alle Secrets und Schlüssel für Anwendungen und Systeme eines gesamten Unternehmens. Wenn Angreifende in den Build-Server eindringen und diese Schlüssel und Secrets auslesen, können sie somit alle Systeme des Unternehmens kompromittieren. Im Vergleich dazu stellt der Pull-basierte Ansatz von GitOps sicher, dass der Operator den Deployment-Prozess ausschließlich innerhalb der Zielumgebung ausführt. Das trägt zu erhöhter Sicherheit bei, da die Zielumgebung, beispielsweise die Produktionsumgebung, typischerweise besser geschützt ist als ein Build-Server, auf dem alle Secrets liegen. Abbildung 3 macht deutlich, dass es sich bei diesem Ansatz im Prinzip um das Verlagern der Deployment-Pipeline in die Zielumgebung handelt.

Pull-basiertes Deployment hebt die Deployment-Pipeline in die Zielumgebung (Abb. 3).

Ein Pull-basierter Workflow lässt sich auf zwei Arten implementieren: mit Polling und Webhooks. Beim Polling holt der Operator im Takt weniger Minuten den Inhalt des Repositories mit der Zustandsbeschreibung ab. Mit Webhooks schickt der Git-Provider (GitHub, GitLab etc.) eine Meldung an den Operator, sobald es im Repository eine Änderung gibt. Der Operator holt sich bei dieser Variante sofort nach dieser Meldung die Zustandsbeschreibung ab und passt gegebenenfalls die Zielumgebung an. Das hat den Vorteil, dass Entwicklungsteams bei einem Deployment nicht auf die Ausführung des nächsten Zyklus warten müssen, sondern innerhalb weniger Sekunden die Anpassung durch den Operator stattfindet. Oft kommen beide Varianten, Polling und das Reagieren auf Webhooks, zum Einsatz. Das hat etwas mit dem nächsten Prinzip zu tun, dem kontinuierlichen Abgleich.

"Software-Agents beobachten kontinuierlich den aktuellen Systemzustand und versuchen, den gewünschten Zustand herzustellen." Der kontinuierliche Abgleich (Reconciliation Loop) stellt den anspruchsvollsten Teil des GitOps-Workflows dar. Hierbei geht es nicht nur darum, die Umgebung bei jeder Konfigurationsänderung entsprechend anzupassen, sondern auch, zu jeder Zeit den gewünschten Zustand zu erhalten. Konfigurationsänderungen, die manuell oder versehentlich passiert sind, werden so in einem regelmäßigen Zyklus wieder zurückgesetzt.

Es ist daher üblich, Personen oder Prozessen nicht zu erlauben, Ressourcen in der Betriebsumgebung zu verändern, die unter der Kontrolle des Operators stehen. Ein Nachteil dieser Vorgehensweise ist, dass sich beispielsweise Hotfixes nicht mehr bereitstellen lassen, sollte der Operator ausfallen.

Am Beispiel von Terraform lässt sich dieses Prinzip leicht nachvollziehen. Terraform überschreibt den Zustand der Ressourcen, falls sie nicht der aktuellen Konfiguration entsprechen. Um das zu erreichen, gilt es, regelmäßig einen Ausführungsplan zu erzeugen und bei auftretenden Divergenzen anzuwenden. Zusätzlich lässt sich eine Kopie der zuletzt gezogenen Zustandsbeschreibung für den Operator vorhalten, um die Umgebung jederzeit in den zuletzt bekannten Zustand zurückzuversetzen, auch wenn kein Zugriff auf das Quell-Repository möglich sein sollte.