GitOps geht auch ohne Kubernetes – alternative Betriebsumgebungen

Seite 2: Implementierung

Inhaltsverzeichnis

Anhand der vier GitOps-Prinzipien sind die Kernfunktionen eines GitOps-Operators nun identifiziert:

  • Deklarativ
  • Versioniert und unveränderlich
  • Pull-basiert
  • Kontinuierlicher Abgleich

Das Umsetzen dieser Prinzipien erfordert keine speziellen Tools, allerdings gibt es bereits Systeme, die in der Lage sind, mit Automatisierungsprozessen umzugehen. Mithilfe einer Workflow-Engine, die über Webhooks angesprochen wird, lassen sich beliebige Prozesse wie etwa das Terraform CLI ausführen. Eine Workflow-Engine bildet im Prinzip die Grundform eines CI/CD-Systems. Deswegen erfüllen solche Systeme in der Praxis oft schon alle Anforderungen:

  • Lauschen auf Webhooks für Git-Aktionen
  • Ziehen von Repository-Inhalten
  • Ausführen von Prozessen
  • Rückmelden des Ergebnisses (optional)

Demzufolge ist es vollkommen valide, einen GitOps-Operator mithilfe eines CI/CD-Systems zu implementieren, das innerhalb der Zielumgebung läuft.

Eine weitere Möglichkeit, einen GitOps-Operator zu implementieren, ist der Einsatz spezialisierter Tools wie Atlantis für das Verwalten von Terraform-Ressourcen. Das unter Apache-2.0-Lizenz verfügbare Atlantis ist ein Server, der auf Webhooks reagiert und Terraform-Kommandos daraus liest. Neben Git-Provider-Webhooks lassen sich auch Slack-Webhooks verwenden, mit denen es möglich ist, Deployments nicht durch das Beobachten des Git-Repositories auszulösen, sondern durch Chat-Nachrichten. Das aber entspricht nicht den GitOps-Prinzipien. Chat-Plattform-Webhooks lassen sich besser dafür nutzen, mehr Einblick in das System durch Statusabfragen zu erlangen. Diese Statusabfragen sind im Slack-Kanal leicht für viele Personen einsehbar.

Obwohl Atlantis auf den ersten Blick einfach zu bedienen ist, stellt das Implementieren des kontinuierlichen Abgleichs eine gewisse Hürde dar. Glücklicherweise bietet Atlantis eine API, über die sich der Prozess von außen steuern lässt. Das kann per einfachem Cron-Skript oder über eine zeitgesteuerte Funktion (scheduled function) erfolgen. Im Prinzip lassen sich alle erforderlichen Funktionen eines GitOps-Workflows mit Git, einem Infrastrukturautomatisierungswerkzeug der Wahl und ein wenig Glue-Code implementieren.

GitOps-Tools stehen gelegentlich dafür in der Kritik, dass ihnen essenzielle Features wie zum Beispiel Secrets Management fehlen. Hintergrund dieser Einschätzung ist die Annahme, dass GitOps-Tools per se darauf ausgelegt seien, CI/CD-Systeme zu ersetzen und daher auch die gleichen Funktionen anbieten sollten.

Gerade weil CI/CD-Systeme oftmals Laufzeit-Secrets enthalten, zählen sie mittlerweile zu den kritischen Einfallstoren innerhalb der Software Supply Chain. Ein prominentes Beispiel dafür ist der Vorfall bei Travis CI, bei dem sieben Tage lang alle Secrets offen lagen. Vergleichbare Sicherheitslücken sind auch bei anderen CI/CD-Providern möglich, wie weitere Vorfälle in der Vergangenheit gezeigt haben.

Auch das bereits angesprochene Prinzip des Pull-basierten Workflows von GitOps zeigt, dass Zugänge zur Betriebsumgebung nicht in CI/CD-Systemen abgelegt sein sollten. Deshalb ist es unabhängig von GitOps wichtig, eine Secrets-Management-Strategie zu implementieren, da es sich um einen sensiblen Faktor handelt. Es gibt unterschiedliche Ansätze, Secrets bereitzustellen. Zum einen gibt es Secrets-Vaults wie HashiCorp Vault, die erst in der Zielumgebung benötigte Secrets bereitstellen, basierend auf Berechtigungen und Referenzen. Zum anderen entschlüsseln Tools wie etwa Bitnami Sealed Secrets zuvor verschlüsselte Secrets erst in der Zielumgebung wieder.

Ein entscheidender Vorteil des GitOps-Ansatzes ist, dass sich Rollbacks von Entwicklungsseite so einfach ausführen lassen wie das Kommando git revert. Schlägt jedoch ein Deployment fehl, kann es zu Abweichungen zwischen der Beschreibung des gewünschten Zustands im Environment-Repository und dem aktuellen Zustand der Zielumgebung kommen. Selbst im Kubernetes-Kontext existiert kein automatischer Rollback-Mechanismus. Stattdessen bleibt das fehlerhafte Deployment hängen und startet immer wieder erneut, bis es erfolgreich ist. Das ist eine Design-Entscheidung, die trotz ihrer Einfachheit sehr resilient ist.

Dringend zu empfehlen ist daher, im Falle eines fehlgeschlagenen Deployments einen Alarm auszulösen, damit Entwicklungsteams manuell im Environment-Repository die fehlerhaften Konfigurationen korrigieren können. Dadurch wird der GitOps-Operator befähigt, die Zustandsbeschreibung erneut einzulesen und auszuführen.

Zwar zählen grafische Benutzungsoberflächen nicht zu den Kernfunktionen von GitOps-Tools, dennoch finden damit ausgestattete Werkzeuge besonders viel Anklang bei Nutzerinnen und Nutzern. Diese Oberflächen locken mit einer anschaulichen Visualisierung der System-Topologie und stellen Knöpfe bereit, um unter anderem ein Deployment manuell anzustoßen. Solche Funktionen lassen sich allerdings auch mit dedizierten Werkzeugen bereitstellen, wobei das manuelle Anstoßen eines Deployments nur einen Git-Commit entfernt ist.

Das Implementieren aller bisher beschriebenen Nice-to-Have-Features sowie weiterer Funktionen kann hilfreich sein, ist aber keineswegs notwendig. Tatsächlich ist es der Unix-Philosophie zufolge oft von Vorteil, solche Aufgaben auf spezialisierte, eigenständige Tools auszulagern. Die Unix-Philosophie propagiert das Entwickeln kleiner, modularer Komponenten, die leicht integrierbar sind und jeweils einen einzigen Zweck erfüllen. Das Motto ist: "Do one thing and do it well."

Bereits ausgereifte Tools für die erweiterten Anforderungen des GitOps-Workflows sollten demnach als eigenständige Komponenten zum Einsatz kommen. Es ist nicht notwendig, dass ein einzelnes GitOps-Tool Aufgaben übernimmt, die nicht zu den Kernfunktionen gehören.

Nachdem der Funktionsumfang des GitOps-Operators geklärt ist, gilt es nun noch, die Betriebsumgebung zu definieren. Sie umfasst alle Komponenten und Anwendungen, die der Operator verwaltet. Handelt es sich um eine einzelne Virtual Machine (VM), lässt sich der Operator als Daemon betreiben. Die Betriebsumgebung kann aber auch als Cluster mehrerer Maschinen vorliegen, in dem der Operator als eine von vielen Workloads läuft. In beiden Fällen benötigt der Operator die Berechtigung, Workloads zu modifizieren, die sich innerhalb der Betriebsumgebung selbst befinden. Oft wird vergessen, dass solch eine Betriebsumgebung aber auch die Gesamtheit aller Ressourcen in einer abgeschlossenen Cloud-Umgebung sein kann. Der Operator kann dabei als Funktion oder als VM innerhalb der Umgebung laufen und Zugriff auf die API des Cloud-Providers haben. In diesem Szenario kann es herausfordernd sein, den Überblick über die verschiedenen Dienste, Ressourcen und Deployments zu behalten, die der Operator verwaltet. Es bietet sich daher an, konkrete Berechtigungsgrenzen festzulegen. Die großen Cloud-Provider arbeiten dazu mit dem Konzept der Landing Zones (AWS, Azure, Google).

Die in Abbildung 4 gezeigten Beispiele für Betriebsumgebungen (VM, Cluster, Cloud Landing Zone) sind im GitOps-Kontext vollkommen valide, denn sie entsprechen der Beschreibung einer Betriebsumgebung (bzw. Laufzeitumgebung) des OpenGitOps-Projekts:

  1. Die Laufzeitumgebungen bestehen aus den zu verwaltenden Ressourcen.
  2. Die Management-Agents laufen innerhalb jeder Laufzeitumgebung.
  3. Es gibt Richtlinien zur Kontrolle des Zugriffs und der Verwaltung von Repos, Deployments und Runtimes.

Beispiele von Betriebsumgebungen: VM, Cluster und Cloud Landing Zone (Abb. 4).

Im Übrigen gehört ein GitOps-konformes Pull-basiertes Deployment für stark abstrahierte Plattformen wie Heroku und Netlify zur Standardfunktionalität. Damit ist also die Betriebsumgebung definiert durch ein Projekt bei einer dieser Plattformen.

GitOps eröffnet eine sichere Möglichkeit, Anwendungen zu deployen, weil der zentrale Build-Server wegfällt, der alle möglichen Applikationen einer gesamten Organisation verwaltet. Sicherheit bietet GitOps dadurch, dass der Operator innerhalb einer spezifischen Betriebsumgebung lebt, in der auch die Anwendungen selbst verwaltet werden. Was darüber hinaus allerdings noch sichergestellt werden muss, ist Isolation.

Um den Operator von Ressourcen zu isolieren, die nicht verwaltet werden sollen, und das System vor Angriffen durch die Manipulationen der Infrastrukturkonfiguration zu schützen, sind zwei Fragen zu beantworten:

  • Soll ein Operator pro Team, Domain oder Applikation zum Einsatz kommen?
  • Gilt es innerhalb dieser Dimensionen noch zusätzlich pro Stage (Dev, Staging, Prod) zu unterscheiden?

Sind diese Fragen beantwortet, geht es darum, die Resource Boundary zu definieren. Sie gibt an, welche Ressourcen der Operator konkret verwalten darf. Eine Applikation, die als Self-contained System (SCS) konzipiert ist, kann aus mehreren Komponenten bestehen, wie etwa Web-Applikationen, Scheduler, Funktionen und S3 Buckets. Doch sollten auch Daten, Netzwerkkonfiguration, Quotas und Berechtigungskonfigurationen (IAM) von der Resource Boundary eingeschlossen werden? Im Hinblick auf die Sicherheit macht es einen großen Unterschied, ob der Operator lediglich die Berechtigungen für ein S3 Bucket setzen darf oder auch in der Lage ist, neue Benutzungskonten zu erstellen. Überlegungen dazu sind aus Sicherheitsgründen essenziell, vor allem, wenn die Betriebsumgebung eine vollständige Cloud-Umgebung ist.

Definition der Resource Boundary: Team, Domain, Applikation (Abb. 5).