Blogartikel

15.09.2023

Softwarequalität

GitOps-Repository-Strukturen und -Patterns Teil 4: Promotion Patterns

Lernen Sie, welche Möglichkeiten es durch Pattern und Strukturen gibt, Environments (auch als Stages bekannt) mit Ihrem GitOps umzusetzen.

In dieser Artikelserie stelle ich Ihnen unterschiedliche Strukturen und Patterns vor, die Sie nutzen können, um Ihren GitOps-Prozess zu designen. In diesem Teil geht es um Promotion Patterns.

Eine Einführung in die Thematik der GitOps-Repository-Patterns und -Strukturen bekommen Sie im ersten Teil dieser Serie, im zweiten Teil stelle ich Operator-Deployment-Patterns vor, im dritten Teil Repository Patterns und im fünften Teil Verdrahtungs-Patterns. Im sechsten Teil zeige ich unterschiedliche Umsetzungen der Strukturen und Patterns anhand von Beispiel-Repositories.

Die Promotion Patterns beschreiben verschiedene Möglichkeiten, Environments (auch als Stages bekannt, beispielsweise „QA“, „Staging“ und „Production“) mit GitOps umzusetzen. Diesen Prozess bezeichnen wir als Promotion. Manchmal wird dem Begriff Promotion noch ein Wort vorangestellt wie Release, Application, Environment, Workload oder Change. Dieser Artikel verwendet im Folgenden die Begriffe Environment und Promotion.

Bei GitOps wird die Promotion, also der Übergang von einem Environment in das nächste, per Pull Request realisiert.

Branch vs Folder per Environment

Für die Umsetzung lautet die zentrale Frage: Wie werden Environments abgebildet, in Ordnern oder Branches?

Erfahrungsgemäß denken viele Teams (vor allem mit Hintergrund in der Software-Entwicklung) zunächst daran, die Environments durch permanente Branches zu trennen. Wir sprechen hier vom Branch per Environment (auch Environment per Branch) Pattern. Dabei wird die gesamte Config, die sich auf einem Branch befindet, immer auf ein Environment deployt. Die Promotion findet dann durch einen Merge im Git statt. Interessanterweise gibt es nur wenige Erfolgsgeschichten zu diesem Pattern. Ein Beispiel ist Monitoring and Hardening the GitOps Delivery Pipeline with Flux von Florian Heubeck. Hier wird der Vorteil genannt, dass das Erzwingen von Pull Requests auf Branches einfacher ist als auf Ordnern. Dem entgegen stehen viele Berichte, die von diesem Pattern abraten (beispielsweise Pinky Ravi and Scott Rigby in GitOps: Core Concepts & Ways of Structuring Your Repos) oder es sogar als Anti-Pattern bezeichnen (beispielsweise Stop Using Branches for Deploying to Different GitOps Environments von Kostis Kapelonis und Git best practices: Workflows for GitOps deployments von Christian Hernandez).

Diese empfehlen stattdessen das Folder per Environment Pattern (auch „Environment per Folder“ oder mit dem Begriff „Directory“ statt „Folder“). Hier werden die Environments als Ordner auf einem Branch (trunk-based) dargestellt. Für die Promotion werden kurzlebige Branches erzeugt, in denen die Änderungen von einem Environment-Ordner in den nächsten kopiert werden. Diese kurzlebigen Branches enthalten jeweils nur ein Feature und werden mit dem Merge wieder gelöscht. Die Verwendung von Ordnern hat viele Vorteile gegenüber Branches: Da sich Environments nur in wenigen Bereichen unterscheiden, gibt es oft viel Duplizierung. Mit Tools wie Helm und Kustomize kann diese Duplizierung jedoch verhindert werden. Da diese Tools auf Datei-Ebene und nicht auf Branch-Ebene arbeiten, können sie dies nur beim Folder per Environment Pattern tun. Das Branch per Environment Pattern hat daher mehr duplizierten Code. Darüber hinaus sind Commits aufeinander aufbauend. Was, wenn nun ein Feature in das nächste Environment gebracht werden soll, das nicht im neuesten Commit ist?

Hier sind Cherry Picks eine Lösung. Diese sind jedoch nicht immer trivial. Bei Ordnern kann man Dateien einfach kopieren, was deutlich einfacher und weniger fehleranfällig ist. Außerdem besteht die Gefahr von „Drift“ – Branches können auseinanderlaufen, weil Änderungen in einem Hotfix nur in Produktion landen, aber die Merges auf die anderen Environments nicht stattfinden. Hier kann es vorkommen, dass sich beim Git Merge unerwartete (inkonsistente) Zustände ergeben – in Produktion. Ein letztes Argument: Bei Branches steigt die Komplexität mit der Anzahl der Environments, bei Ordnern bleibt sie konstant.

Abschließend ist zur Diskussion der beiden Patterns erwähnenswert, dass sich gewisse Nachteile durch Einstellungen im SCM verhindern lassen: Inkonsistenzen lassen sich bei Branches dadurch verhindern, dass nur Fast-Forward-Merges erlaubt werden. Pull Requests lassen sich durch Folder Protection in manchen SCMs erzwingen. Je nach Umgebung können also manche Argumente nicht zutreffen, was die Entscheidung zwischen Ordnern oder Branches beeinflussen kann.

Preview Environments

Eine andere Art, mit Environments umzugehen sind Preview Environments (auch „ephemeral/dynamic/pull request/test/temporary“ Environments). Hier wird bei der Erstellung eines Pull Request (PR, auch Merge Request) ein Deployment angestoßen, das auf der Config des PR basiert. Nach dem Merge oder Ablehnen des PRs wird das Deployment automatisch wieder gelöscht. Dieses Feature ist bei serverless Platforms as a Service wie Netlify oder Vercel schon seit längerem gängig. Hier werden die Begriffe Preview Deployments oder Deploy Previews verwendet. Bei einem Deployment mittels CI-Server ist vor allem das automatische Löschen schwer umsetzbar. Mit GitOps, konkret beispielsweise bei Argo CD, ist dieser ganze Prozess nun mittels eines eigenen Controllers und zugehöriger CRD ApplicationSet und dessen Pull Request Generator automatisierbar. Dieser erzeugt mittels Templating pro PR eine Application nach einer im ApplicationSet vorgegebenen Vorlage, beispielspielsweise myapp-{ {branch} }-{ {number} }.

Bei Flux (oder zumindest Weave GitOps) könnte dies in Form von GitOps Sets bald ähnlich aussehen. Eine spannende Erkenntnis daraus ist, dass GitOps-Tools Features und Vorteile bieten können, die über die eigentlichen Prinzipien von GitOps hinausgehen. Wir dürfen gespannt sein, was sich noch zeigen wird.

Fazit

Abhängig von der Arbeitsweise Ihrer Teams können Sie das beste Promotion Pattern auswählen, um Environments umzusetzen. Weitere Möglichkeiten bieten die in den anderen Teilen dieser Artikelserie vorgestellten Patterns: Operator Deployment Patterns, Repository Patterns, Verdrahtungs-Patterns und Real-Life-Beispiele.