GitOps-Repository-Strukturen und -Patterns Teil 6: Beispiel-Repositories
In diesem letzten Teil der GitOps-Repository-Strukturen und -Patterns-Serie zeige ich Beispiel-Repositories, die Vorlagen, Ideen und Tipps für eigene Projekte liefern. Dabei zeigen sich einige wiederkehrende Themen, die teils unterschiedlich benannt werden: Strukturen für Anwendungen oder Teams, Strukturen für cluster-weite Ressourcen und Strukturen fürs Bootstrapping.
Die Beispiele zeigen auch, dass grundsätzlich kaum Unterschiede zwischen Argo CD und Flux bei Strukturen notwendig sind. Diese beschränken sich auf Bootstrapping und Linking. Da Kustomize mittels kustomization.yaml sowohl von Argo CD als auch von Flux verstanden wird, stellt es sich als Operator-agnostisches Werkzeug heraus.
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, im vierten Teil Promotion Patterns und im fünften Teil Verdrahtungs-Patterns.
Beispiel 1: Argo CD Autopilot
- Repo pattern: Monorepo
- Operator pattern: „Instance per Cluster“ oder „Hub and Spoke“
- Operator: Argo CD
- Boostrapping:
argocd-autopilot
CLI - Linking:
Application
,ApplicationSet
, Kustomize - Features:
- Automatische Erzeugung der Struktur und YAML via CLI
- Argo CD selbst per GitOps verwalten
- Lösung für cluster-weite Ressourcen
- Quelle: argoproj-labs/argocd-autopilot
Abbildung 1: Repo-Struktur bei argocd-autopilot
Argo CD autopilot ist ein Kommandozeilen-Werkzeug (Command Line Interface, CLI), das die Installation und den Einstieg in Argo CD vereinfachen soll. Dazu bietet es die Möglichkeit, das Bootstrapping von Argo CD im Cluster sowie das Anlegen von Repo-Strukturen durchzuführen.
Das Bootstrapping von Argo CD erfolgt mit einem einzigen Befehl: argocd-autopilot repo bootstrap
. Um mit der daraus resultierenden Struktur auch Anwendungen zu deployen, sind zudem ein AppProject
(Command project create
) und eine Application
(Command app create
) notwendig. Abbildung 1 zeigt die daraus resultierende Repo-Struktur. Diese Struktur ist bei GitHub unter schnatterer/argocd-autopilot-example einsehbar. Die Zusammenhänge werden im Folgenden anhand der Nummern in der Abbildung beschrieben:
- Die
Application
autopilot-bootstrap
verwaltet den Ordnerbootstrap
und bindet damit alle anderenApplication
s in dieser Aufzählung ein. Sie selbst steht nicht unter Versionsverwaltung, sondern wird imperativ beim Bootstrapping an den Cluster übermittelt. - Die
Application argo-cd
verwaltet Argo CD selbst per GitOps. - Dazu enthält sie eine Kustomization, die weitere Ressourcen aus dem Internet einbezieht. Sie verweist direkt auf eine Kustomization im Repo von autopilot, die wiederum alle zur Installation von Argo CD notwendigen Ressourcen aus dem Repo von Argo CD selbst holt. Dabei verweist sie auf den
stable
Branch von Argo CD. - Das
ApplicationSet cluster-resources
referenziert mittels git-Generator für Dateien alle JSON-Dateien unter dem Pfadbootstrap/cluster-resources/
. Damit kann man cluster-weite Ressourcen verwalten, wie beispielsweise Namespaces, die von mehreren Applications genutzt werden. Standardmäßig liegt hier nur die Dateiin-cluster.json
, die Werte für die Variablen name und server enthält. Im Template desApplicationSet
s werden diese Variablen eingesetzt, sodass eineApplication
entsteht, welche die Manifeste unterhalb vonbootstrap/cluster-resources/in-cluster/
referenziert. Dadurch entsteht der Namespaceargocd
in dem Cluster, in dem Argo CD deployt ist. Dies eignet sich für das „Instance per Cluster“ Pattern, ist aber erweiterbar auf weitere Cluster, um das Hub and Spoke Pattern zu implementieren. - Die Application
root
ist dafür zuständig, alleAppProjects
undApplication
s einzubinden, die unterhalb vonprojects/
angelegt werden. Nach dem Ausführen des Commandsbootstrap
ist dieser Ordner noch leer. - Bei jeder Ausführung des
project
Commands werden einAppProject
und zugehörigesApplicationSet
in einer Datei generiert. Diese sind für die Umsetzung verschiedener Environments gedacht. DasApplicationSet
referenziert mittels git-Generator für Dateien alleconfig.json
Dateien, die in Unterordnern des Ordners apps für das jeweilige Environment liegen, beispielsweiseapps/my-app/overlays/staging/config.json
. Allerdings ist der Ordner apps initial leer und es werden zunächst keine Applications generiert. - Durch Ausführung des Commands
app
wird der Ordnerapps
mit der Struktur für eineApplication
in einem Environment befüllt. Dazu gehören die im letzten Punkt beschriebeneconfig.json
, mittels der das im Ordnerprojects
liegendeApplicationSet
eineApplication
erzeugt, die den Ordner selbst deployt, also beispielsweiseapps/my-app/overlays/staging
. Mittels dieses Ordners kann Config deployt werden, die spezifisch für ein Environment ist. - Zusätzlich wird eine
kustomization.yaml
erzeugt, die auf den Ordner base zeigt. Mittels dieses Ordners kann Config deployt werden, die in allen Environments gleich ist. Durch diese Aufteilung wird redundante Config vermieden.
Analog zu 6. bis 8. können weitere Environments hinzugefügt werden. Abbildung 1 zeigt hier stellvertretend einen Unterordner production
im Ordner apps
und eine YAML-Datei in projects
.
Abschließend soll erwähnt werden, dass es Gründe gibt, die zur Vorsicht bei der Verwendung von Autopilot in der Produktion raten. Das Projekt bezeichnet sich selbst nicht als stabil, es liegt noch in einer Version „0.x“ vor. Es ist auch nicht Teil der offiziellen „argoproj“ Organisation bei GitHub, sondern liegt unter „argoproj-labs“. Die Commits kommen hauptsächlich von einem Unternehmen: Codefresh. Es ist also denkbar, dass das Projekt eingestellt wird oder Breaking Changes auftreten. Damit ist eine Verwendung in der Produktion nicht ratsam.
Standardmäßig ist außerdem die Version von Argo CD nicht gepinnt. Stattdessen verweist die kustomization.yaml
(3. in Abbildung 1) schlussendlich auf den stable-Branch
des Argo-CD-Repos. Hier empfehlen wir, per Kustomize eine deterministische Version zu referenzieren. Eine nicht-deterministische Version schreit nach Problemen: Upgrades von Argo CD könnten unbemerkt stattfinden. Wie sieht es bei Breaking Changes in Argo CD aus? Welche Version stellt man im Disaster Recovery Fall wieder her?
Die Repository-Struktur, die der Autopilot erzeugt, ist kompliziert, d.h. schwierig zu verstehen und zu warten. Das Ausmaß an Konzentration, das zum Verständnis von Abbildung 1 und der zugehörigen Beschreibung nötig ist, spricht dabei schon eine deutliche Sprache. Dazu kommen noch weniger offensichtliche Themen: Warum befindet sich die Anwendung autopilot-bootstrap
(1. in Abbildung 1) nicht im GitOps-Repository, sondern nur im Cluster?
Der Ansatz eines ApplicationSet
innerhalb des AppProject
’s YAML, das auf eine config.json
zeigt, ist schwer zu verstehen (4. und 6. in Abbildung 1). Dazu kommt die Mischung von YAML und JSON.
Das cluster-resources
ApplicationSet
ist generell ein gut skalierbarer Ansatz für die Verwaltung mehrerer Cluster über das Hub and Spoke Pattern. Doch auch hier muss JSON geschrieben werden (4. in Abbildung 1).
Der Autopilot modelliert Environments über Argo CD Projects (6. und 7. in Abbildung 1). Wie wäre bei dieser Monorepo-Struktur eine Trennung unterschiedlicher Entwickler-Teams realisierbar? Eine Idee wäre die Verwendung mehrerer Argo CD-Instanzen nach dem „Instance per Cluster“ Pattern. Dabei müsste jedes Team seine Argo CD-Instanz selbst verwalten.
Viele Organisationen lagern solche Aufgaben gerne an Plattform-Teams aus und implementieren ein Repo per Team Pattern. Dies ist mit dem Autopilot nicht intuitiv. Das 2. Beispiel zeigt hierfür eine Alternative auf.
Beispiel 2: GitOps Playground
- Repo pattern: „Repo per team“ gemischt mit „Repo per app“
- Operator pattern: Instance per Cluster („Hub and Spoke“ auch möglich)
- Operator: Argo CD (Flux auch möglich)
- Boostrapping:
helm
,kubectl
- Linking:
Application
- Features:
- Argo CD selbst per GitOps verwalten
- Lösung für cluster-weite Ressourcen
- Mandantentrennung: Zentraler Operator für mehrere Teams, auf einem Cluster mit Namespace-Environments (auch mehrere Cluster möglich)
- Env per app Pattern
- Config Update und Config Replication via CI-Server
- Gemischte repo patterns
- Beispiele für Argo CD und Flux
- Quelle: cloudogu/gitops-playground
Abbildung 2: Zusammenhang der GitOps-Repos im GitOps Playground (Argo CD)
Der GitOps Playground stellt ein OCI-Image bereit, mit dem ein Kubernetes Cluster mit allem provisioniert werden kann, was für den Betrieb mittels GitOps nötig ist und veranschaulicht dies mittels Beispiel-Applikationen. Zu den installierten Tools gehören GitOps-Operator, Git-Server, Monitoring und Secrets Management. Beim GitOps-Operator hat man die Wahl zwischen Argo CD und Flux. Im Folgenden fokussieren wir auf Argo CD, da es (anders als Flux) selbst keine Vorschläge zur Repo-Struktur macht. Außerdem gibt es weniger öffentliche Beispiele für Repo-Strukturen mit Argo CD, die reif für die Produktion sind.
Im GitOps Playground wird Argo CD so installiert, dass es sich selbst per GitOps betreiben kann. Außerdem wird ein „Repo per Team“ Pattern gemischt mit einem „Repo per App“ Pattern umgesetzt. Abbildung 2 zeigt, wie die GitOps-Repos verdrahtet sind.
Der GitOps Playground führt für das Bootstrapping von Argo CD bei der Installation einige imperative Schritte einmalig durch. Dabei werden drei Repos erstellt und initialisiert:
argocd
(Verwaltung und Konfiguration von Argo CD selbst)example-apps
(Beispiel für das GitOps-Repository eines Entwickler-/Applikations-Teams) undcluster-resources
(Beispiel für das GitOps-Repo eines Cluster-Administrators oder eines Infra-/Plattform-Teams)
Argo CD wird einmalig mittels eines Helm-Charts installiert. Hier wird intern helm template
verwendet. Eine Alternative wäre die Verwendung von helm install
oder helm upgrade -i
. Danach sollten allerdings die Secrets, in denen Helm seinen Zustand verwaltet, gelöscht werden. Argo CD nutzt diese nicht, insofern würden sie veralten und nur für Verwirrung sorgen.
Um das Bootstrapping abzuschließen werden außerdem zwei Ressourcen imperativ auf den Cluster angewendet: ein AppProject
namens argocd
und eine Application
namens
bootstrap
. Diese sind ebenfalls im argocd-Repository enthalten.
Von dort aus wird alles über GitOps verwaltet. Im Folgenden werden die Zusammenhänge anhand der Nummern in der Abbildung beschrieben:
- Die
Application
bootstrap
verwaltet den Ordnerapplications
, der auchbootstrap
selbst enthält. Damit können Änderungen anbootstrap
über GitOps vorgenommen werden. Mittelsbootstrap
werden weitere andere Anwendungen deployt (App-of-Apps-Pattern). - Die
Application
argocd
verwaltet den Ordnerargocd
, der die Ressourcen von Argo CD als ein Umbrella Helm Chart enthält. Dabei enthält dievalues.yaml
die eigentlichen Config der Argo CD-Instanz. Zusätzliche Ressourcen (beispielsweise Secrets und Ingresses) können über den Ordnertemplate
deployt werden. Das eigentliche Argo CD-Chart wird in derChart.yaml
deklariert. - Die
Chart.yaml
enthält das Argo CD Helm Chart als Dependency. Sie verweist auf eine deterministische Version des Diagramms (gepinnt perChart.lock
), die aus dem Chart-Repository im Internet gezogen wird. Dieser Mechanismus kann verwendet werden, um Argo CD per GitOps zu aktualisieren. - Die
Application
projects
verwaltet den Ordnerprojects
, der wiederum die folgendenAppProjects
enthält:argocd
, das für das Bootstrapping verwendet wird,- das in Argo CD fest verbaute
default
(dessen Rechte gegenüber dem Standardverhalten beschränkt werden, um die Angriffsfläche zu reduzieren (siehe Argo CD End User Threat Model)), - ein
AppProject
pro Team (zur Implementierung von Least Privilege und Notifications pro Team):cluster-resources
(für Plattform-Admins, benötigt mehr Rechte auf dem Cluster) undexample-apps
(für Entwickler, benötigt weniger Rechte auf dem Cluster)
- Die
Application
cluster-resources
verweist im Repocluster-resources
auf den Ordnerargocd
. Dieses Repo hat die typische Ordnerstruktur eines GitOps-Repos (wird im nächsten Schritt erklärt). Auf diese Weise nutzen Administratoren GitOps auf die gleiche Weise wie ihre „Kunden“ (die Entwickler) und können so besseren Support leisten. - Die
Application
example-apps
verweist im Repoexample-apps
auf den Ordnerargocd
. Wie diecluster-resources
hat es auch die typische Ordnerstruktur eines GitOps-Repos: apps
- enthält die Kubernetes-Ressourcen aller Anwendungen (das eigentliche YAML)argocd
- enthält Argo CDApplication
s, die auf Unterordner von apps verweisen (App Of Apps Pattern)misc
- enthält Kubernetes-Ressourcen, die nicht zu bestimmten Anwendungen gehören (beispielsweise Namespaces und RBAC)- Die
Application
misc
zeigt auf den Ordnermisc
- Die
Application
my-app-staging
verweist auf den Ordnerapps/my-app/staging
innerhalb desselben Repos. Dies bietet eine Ordnerstruktur für die Promotion. DieApplication
s mit dem Präfixmy-app-
implementieren das „Environment per App“ Pattern. Dieses ermöglicht es jeder Anwendung, individuelle Environments zu verwenden, z.B.production
undstaging
oder gar keine. Das eigentliche YAML kann hier entweder manuell oder automatisiert gepusht werden. Der GitOps Playground enthält Beispiele, die das Config Update per CI-Server auf Basis eines App-Repos realisieren. Dieses Vorgehen ist ein Beispiel für die Mischung der „Repo per Team“ und „Repo per App“ Patterns. - Die zugehörige Produktionsumgebung wird über die Anwendung
my-app-production
realisiert, die auf den Ordnerapps/my-app/production
innerhalb desselben Repos verweist. Generell ist es empfehlenswert, alleproduction
-Ordner vor manuellem Zugriff zu schützen, wenn dies seitens des verwendeten SCM möglich ist (beispielsweise mit SCM-Manager). Anstelle der im Diagramm verwendeten unterschiedlichen YAML-Dateien könnten dieseApplication
s auch wie folgt realisiert werden - Zwei
Application
s in derselben YAML - Zwei
Application
s mit dem gleichen Namen in verschiedenen Kubernetes Namespaces. Voraussetzung dafür ist, dass diese Namespaces in Argo CD konfiguriert sind. - Ein
ApplicationSet
, das den git-Generator für Ordner verwendet.
Der GitOps Playground selbst verwendet zur Vereinfachung einen einzelnen Kubernetes-Cluster und implementiert damit das „Instance per Cluster“-Pattern. Die gezeigte Repo-Struktur kann jedoch auch für mehrere Cluster nach dem „Hub and Spoke“ Pattern verwendet werden: Zusätzliche Cluster können entweder in der vaules.yaml
oder als Secrets mittels des templates
Ordners definiert werden.
Beispiel 3: Flux Monorepo
- Repo pattern: Monorepo
- Operator pattern: Instance per Cluster
- Operator: Flux (wäre ähnlich mit Argo CD umsetzbar)
- Boostrapping:
flux
CLI - Linking: Flux
Kustomization
, Kustomize - Features:
- Flux selbst per GitOps verwalten
- Lösung für cluster-weite Ressourcen
- Quelle: fluxcd/flux2-kustomize-helm-example
Abbildung 3: Repo-Struktur von flux2-kustomize-helm-example
Nach diesen nicht trivialen Beispielen im Kontext von Argo CD beginnt unser praktischer Einblick in die Welt von Flux mit einer positiven Überraschung: Hier sind keine Vorüberlegungen oder externe Tools zur Installation notwendig. Das Flux CLI bringt einen bootstrap
Command mit, der das Bootstrapping von Flux im Cluster sowie das Anlegen von Repo-Strukturen durchführt. Zusätzlich bietet Flux offizielle Beispiele, die verschiedene Patterns implementieren. Wir beginnen mit dem Monorepo. Abbildung 3 zeigt die Zusammenhänge. Im Folgenden werden diese anhand der Nummern in der Abbildung beschrieben:
- In den Ordner
flux-system
generiert der Commandflux bootstrap
alle zur Installation von Flux notwendigen Ressourcen, sowie ein Git Repository und eineKustomization
. Zum Bootstrapping wendetflux
diese einmalig imperativ auf den Cluster an. DieKustomization
referenziert dann ihren eigenen Überordner Ordnerproduction
. Ab hier wird alles über GitOps verwaltet. - Die
flux-system
Kustomization deployt zudem eine weitereKustomization
infrastructure
, die auf den gleichnamigen Ordner zeigt. Darüber können cluster-weite Ressourcen wie Ingress Controller und Network Policies deployt werden. - Außerdem deployt
flux-system
dieKustomization
apps
. Diese zeigt auf den Unterordner des jeweiligen Environments unter apps, beispielsweiseapps/production
. - In diesem Ordner liegt eine
kustomization.yaml
, mittels der die Ordner aller Anwendungen eingebunden werden. - Im Ordner jeder Anwendung liegt eine weitere
kustomization.yaml
, die die eigentlichen Ressourcen für jede Anwendung in einem Environment zusammenstellt: Als Grundlage dient, typisch für Kustomize, ein Unterordner vonbase
(beispielsweiseapps/base/app1
). Dieser enthält Config, die in allen Environments gleich ist. Dazu kommt Config, die spezifisch für jedes Environment ist. Diese wird mittels Patches aus dem jeweiligen Ordner des Environments (beispielsweiseapps/production/app1
) über diebase
gelegt.
Analog zum Ordner apps
gibt es im Ordner clusters
ebenfalls je einen Ordner pro Environment. Flux implementiert hier also eine Instance per Cluster Pattern: eine Flux-Instanz pro Environment.
Das öffentliche Beispiel selbst zeigt nur die Verwaltung einer einzelnen Anwendung und es ist nicht offensichtlich, wie weitere hinzugefügt werden. Unsere Erfahrung aus der Praxis ist, dass eine Flux-Instanz meist mehrere Anwendungen verwaltet. Daher zeigt Abbildung 3 eine um die Erkenntnisse aus einem Issue erweiterte Variante, die mehrere Anwendungen unterstützt. Diese Struktur kann auch bei GitHub unter schnatterer/flux2-kustomize-helm-example eingesehen und ausprobiert werden.
Diese Struktur hat den Nachteil, dass alle Anwendungen unter apps von einer einzigen Kustomization
pro Environment deployt werden. Beispielsweise bei der Verwendung der grafische Oberfläche von Weave GitOps werden dann alle darin enthaltenen Ressourcen als eine „App“ auf der Oberfläche angezeigt (siehe Abbildung 4). Dies ist schnell unübersichtlich. Analog zur Verwendung von Application
s bei Argo CD (siehe vorherige Beispiele) ist es auch hier denkbar eine Kustomization
pro Anwendung anzulegen, statt einer einzigen der Kustomization
in der Datei apps.yaml
. Dies bedarf zwar mehr Wartung, sorgt aber für übersichtlichere Strukturen.
Abbildung 4: Mehrere Anwendungen in einer Kustomization (Screenshot Weave GitOps)
Die hier beschriebene Repo-Struktur würde mit wenigen Änderungen auch für Argo CD funktionieren. Statt der Kustomization
s müssten Application
s zum Linking eingesetzt werden. Die kustomization.yaml
s werden von beiden Tools verstanden.
Beispiel 4: Flux repo per team
- Repo pattern: Repo per team
- Operator pattern: Instance per Cluster
- Operator: Flux (prinzipiell auch Argo CD)
- Boostrapping: flux CLI
- Linking: Flux Kustomization, Kustomize
- Features: Wie Beispiel 3
- Quelle: fluxcd/flux2-multi-tenancy
Abbildung 5: Zusammenhang der GitOps-Repos bei flux2-multi-tenancy
Wer für seine Organisation lieber ein Repo pro Team verwenden möchte, findet im Flux Projekt auch dafür ein offizielles Beispiel. Bei Flux wird dieses unter dem Begriff „multi-tenancy“ geführt. Statt dem allgemeineren Begriff „Tenant“ (engl. Mandant) verwenden wir hier den zum Pattern passenden Begriff „Team“.
Einige Punkte sind bereits aus dem vorherigen Beispiel bekannt. Dazu gehören das Bootstrapping mittels des Ordners clusters
und die cluster-weiten Ressourcen im Ordner infrastructure
. Abbildung 5 zeigt die Zusammenhänge. Im Folgenden werden diese anhand der Nummern in der Abbildung beschrieben:
- Die
Kustomization
flux-system
deployt eineKustomization
tenants
, die auf den Ordnertenants/production
zeigt. - In diesem Ordner liegt eine
kustomization.yaml
, mittels der die Ordner aller Teams in einem Environment eingebunden werden, beispielsweisetenants/production/team1
. - Im Ordner jedes Teams liegt eine weitere
kustomization.yaml
, die Ressourcen für jedes Team in einem Environment zusammenstellt. Als Grundlage dient, typisch für Kustomize, ein Unterordner vonbase
(beispielsweisetenants/base/team1
). Dieser enthält Config, die in allen Environments gleich ist. Dazu kommt Config, die spezifisch für jedes Environment ist. Diese wird mittels Patches aus dem jeweiligen Ordner des Environments (beispielsweisetypisch/production/team1
) über diebase
gelegt. - Konkret können sich im Ordner base mehrere Ressourcen befinden, die über noch eine weitere
kustomization.yaml
zusammengefügt werden. - Das Team-Repo wird dabei über die Datei
sync.yaml
eingebunden, in der sich einGit Repository
und eine weitereKustomization
befinden. Spezifisch für jedes Environment ist dann nur noch der Pfad im Team-Repo, der mittels eines Patches aus dem jeweiligen Ordner des Environments darüber gelegt wird, beispielsweisetenants/production/team1/path.yaml
.
Der Aufbau des Team-Repos entspricht dann genau dem des Ordners app
aus dem Beispiel davor. Auch hier haben wir dieses so angepasst, dass es mehrere Anwendungen unterstützt. Diese Struktur kann auch bei GitHub unter schnatterer/flux2-multi-tenancy eingesehen und ausprobiert werden. Wie bei diesem gilt auch hier der Nachteil, dass alle Anwendungen im Team-Repo von einer Kustomization
pro Environment deployt werden und dies unübersichtlich wird.
Beispiel 5: The Path to GitOps
- Repo pattern: Monorepo
- Operator pattern: Instance per Cluster
- Operator: Argo CD (oder Flux)
- Boostrapping:
kubectl
- Linking:
Application
,ApplicationSet
, Kustomize - Features:
- Lösung für cluster-weite Ressourcen
- Env per app Pattern
- Beispiele für Argo CD und Flux
- Quelle: christianh814/example-kubernetes-go-repo
Abbildung 6: Die Repo-Struktur bei example-kubernetes-go-repo
In seinem Buch „The Path to GitOps“ widmet Christian Hernandez, der sich seit Jahren bei Akuity, RedHat und Codefresh mit dem Thema GitOps auseinandersetzt, dem Thema Repo- und Ordnerstrukturen ein Kapitel. Abbildung 6 zeigt sein Beispiel für ein Monorepo. Es ist auch bei GitHub einsehbar, und zwar sowohl für Argo CD als auch für Flux. Die Bezeichnungen der Ordner unterscheiden sich teilweise zwischen Buch und Repo bei GitHub. Dies passt zu einem Tipp aus dem Buch, dass die Namen der Repos nicht wichtig sind, sondern die Konzepte, die diese repräsentieren.
In diesem Beispiel findet sich viel wieder, was bereits in den vorherigen Beispielen bekannt ist:
- Es gibt einen Ordner apps für Anwendungen. Im Repo bei GitHub heißt dieser
tenants
, ist hier also wie in Beispiel 4 auf Teams bezogen. - Für cluster-weite Ressourcen gibt es einen Ordner
cluster-config
, der im Repo bei GitHubcore
heißt. - Im Ordner
bootstrap
ist das Bootstrapping des Operators realisiert. Hier wird Argo CD ähnlich wie bei Autopilot (siehe Beispiel 1) mittels Kustomize direkt aus dem öffentlichen Argo CD-Repo übers Internet installiert.
Um Wiederholungen zu vermeiden, werden die Zusammenhänge der Repo-Struktur an dieser Stelle nicht im Detail beschrieben. Interessant sind jedoch die folgenden Punkte.
- Dieses Repo teilt die Config des Operators in zwei Ordner auf: Den bereits bekannten Ordner
bootstrap
und einen Ordnercomponents
. - Zudem befindet sich die gesamte Struktur in einem Ordner
cluster-XXXX
, was vermuten lässt, dass sich die gesamte Struktur inklusive Argo CD auf einen Cluster bezieht. Hier wird also das Instance per Cluster-Pattern implementiert. - Für die Promotion wird hier eine „Env per app“ Pattern per Kustomize implementiert, siehe Ordner
apps
in Abbildung 6. Dies wird im Buch beschrieben, ist allerdings nicht im GitHub-Repo umgesetzt.
Wie erwähnt, gibt es die gleiche Repo-Struktur auch für Flux. Es ist generell interessant, dass die gleiche Struktur mit kleineren Änderungen sowohl für Argo CD als auch für Flux verwendbar ist. Bei Flux empfiehlt es sich allerdings stattdessen, die Struktur des flux bootstrap
Commands zu verwenden. Da dieser in Flux implementiert ist, kann man sie als Good Practice für Flux ansehen. Er erleichtert das Verständnis und die Wartung, beispielsweise bei Updates von Flux.
Beispiel 6: Environment-Varianten
- Operator: Argo CD (prinzipiell auch Flux)
- Linking: Kustomize
- Features:
- Verschiedene Varianten der Environments einer App
- Promotion durch Kopieren einzelner Dateien
- Quelle: kostis-codefresh/gitops-environment-promotion
Abbildung 7: Die Ordnerstruktur bei gitops-environment-promotion
Dieses letzte Beispiel unterscheidet sich von den bisherigen dahingehend, dass es nicht die Struktur eines ganzen Repos beschreibt, sondern nur die einer einzelnen Anwendung. Es kann daher mit den anderen Beispielen kombiniert werden. Dieses Beispiel fokussiert sich auf die Umsetzung einer großen Anzahl von Environments. Es zeigt, wie verschiedene Environments (integration
, load
, prod
, qa
und staging
), in unterschiedlichen Regionen (asia
, eu
, us
) ausgerollt werden können, ohne dass viel redundanten Config entsteht. Insgesamt entstehen so 11 Environments. In jedem Environment soll zudem zwischen prod
und non-prod
unterschieden werden. Hier zeigt sich, dass Kustomize zur Umsetzung einer so umfangreichen Struktur ohne Redundanzen gut geeignet ist. Obwohl das Beispiel aus dem Umfeld von Argo CD kommt kann es ohne Änderungen auch mit Flux eingesetzt werden, da das Linking ausschließlich per kustomization.yaml
durchgeführt wird.
Abbildung 7 zeigt die Struktur vereinfacht auf fünf Environments. Ausgangspunkt sind die Unterordner eines Environments im Ordner envs
, beispielsweise envs/prod-eu
. Diese Unterordner würde man per Argo CD Application
oder Flux Kustomization
einbinden. In jedem Unterordner liegt eine kustomization.yaml
, die als Grundlage den Ordner base
verwendet, der in allen Environments identische Config enthält. Die Config der Varianten liegt in Unterordnern vonvariants
, beispielsweise eu
und prod
. Dazu kommt die für jedes Environment spezifische Config mittels Patches aus dem jeweiligen Unterordner von env, beispielsweise envs/prod-eu
.
Grundsätzlich könnte dieses Beispiel auch per Helm umgesetzt werden, dies wäre aber umständlicher und es würde die Verwendung von speziellen CRDs, statt universeller kustomization.yaml
, erfordern.
Dieses Beispiel liefert außerdem eine Idee zur Vereinfachung der Promotion: In jedem Ordner befinden sich viele YAML Dateien, eine Datei pro Property. Der Vorteil ist, dass die Promotion dann durch simples Kopieren einer Datei durchgeführt werden kann. Es ist nicht notwendig, Text auszuschneiden und einzufügen, was den Prozess vereinfacht und das Risiko von Fehlern verringert. Außerdem sind die Diffs einfacher zu lesen.
Fazit
Anhand wiederkehrender Elemente bestehender GitOps-Tools beschreibt diese Artikelserie GitOps-Patterns und ordnet sie in die vier Kategorien Operator Deployment, Repository, Promotion und Verdrahtung ein. Die Patterns geben zum Einen einen Überblick über die Möglichkeiten bei Design-Entscheidungen für den GitOps-Prozess und für die Struktur der zugehörigen Repositories und was dabei zu beachten ist. Zum Anderen können sie dazu beitragen, Begriffe für die jeweiligen Patterns zu finden, diese zu vereinheitlichen und die Kommunikation zu erleichtern.
Dieser letzte Teil der Serie beschreibt Beispiele aus der Praxis für die Patterns. Diese liefern Vorlagen, Ideen und Tipps für eigene Projekte. Dabei zeigen sich einige wiederkehrende Themen, die teils unterschiedlich benannt werden: Strukturen für Anwendungen oder Teams, Strukturen für cluster-weite Ressourcen und Strukturen fürs Bootstrapping.
Die Beispiele zeigen auch, dass grundsätzlich kaum Unterschiede zwischen Argo CD und Flux bei Strukturen notwendig sind. Diese beschränken sich auf Bootstrapping und Linking. Da Kustomize mittels kustomization.yaml
sowohl von Argo CD als auch von Flux verstanden wird, stellt es sich als Operator-agnostisches Werkzeug heraus.
Vieles von dem hier beschriebenen lässt sich mit dem in Beispiel 2 gezeigten GitOps Playground einfach ausprobieren.