Über unsMediaKontaktImpressum
Fabian Kramm 14. Juli 2020

GitOps und Kubernetes: ein neuer Stern am Cloud-Himmel

GitOps ist nicht umsonst ein zur Zeit sehr gefragtes Thema, denn es bietet enorme Möglichkeiten. Das Entfallen von komplexen CI/CD-Pipelines, Entwicklerfreundlichkeit und automatisch integrierte Berechtigungsprozesse für das Deployment sind nur einige Beispiele. Vor allem Kubernetes, der heilige Gral der Cloud-Welt, bietet sich für die Implementierung dieses neuen Paradigmas an und verspricht eine einfache Integration. Dieser Artikel zeigt, wie einfach die Integration von GitOps in Kubernetes wirklich ist und welche möglichen Probleme auf dem Weg zum GitOps-Superstar noch bestehen, und hält daneben auch eine Beispiel-Implementierung von GitOps in einem Kubernetes-Cluster parat.

Was ist GitOps?

GitOps wurde ursprünglich von Alexis Richardson von Weaveworks geprägt und hat vor allem in der letzten Zeit viel an Popularität hinzugewonnen [1]. Die Grundidee von GitOps ist, Git als die einzig verlässliche Datenquelle (Single Source of Truth) in den Mittelpunkt zu stellen, die immer ein komplettes Abbild des gewünschten Zustandes eines Systems enthält. Das Abbild dieses Systems ist deklarativ in Konfigurationsdateien gespeichert und kann, wie sonstiger Quellcode auch, somit in Git versioniert werden. Implementiert wird GitOps üblicherweise mit Hilfe von Tools, die das deklarative Abbild aus Git mit dem eigentlichen System kontinuierlich spiegeln. Somit ist sichergestellt, dass das System zu jeder Zeit dieselbe Konfiguration enthält wie Git und umgekehrt.   

GitOps ist eine logische Erweiterung zur Idee von Infrastructure-as-code, die es ermöglicht, Infrastruktur mit Hilfe von Code, vorrangig in Public Clouds, zu definieren. Architektonisch ermöglicht es GitOps, die kontinuierliche Integration (CI) einer Anwendung von ihrem eigentlichen Deployment-Prozess zu trennen. Das ist möglich, weil der Deployment-Prozess nicht mehr direkt im Git-Repository mittels einer Pipeline ausgeführt wird, sondern durch einen entfernten Watcher im Zielsystem, der Änderungen im Git-Repository asynchron bearbeitet. Damit ist es z. B. nicht mehr nötig, Zugangsdaten zum Produktivsystem in einer CI/CD-Pipeline zu speichern, was die Sicherheit erhöht. Außerdem ist es möglich, mehrere Zielsysteme zu definieren, ohne Änderungen am eigentlichen Git-Repository oder der CI/CD-Pipeline vornehmen zu müssen.

Die Verwendung von Git bringt automatisch eine Reihe weiterer Vorteile mit sich, wie z. B. integrierte Zugangskontrolle, Genehmigungsprozesse und schnelle Systemwiederherstellung, da der komplette Systemzustand versioniert wurde.

Ein weiterer großer Vorteil von GitOps ergibt sich dann auf den zweiten Blick: die Nähe zum Entwickler. Denn Git gilt mittlerweile oftmals als Basiswissen und viele Entwickler arbeiten damit bereits täglich. GitOps erlaubt es nun jedem, der Änderungen am Versions-Kontrollsystem vornehmen darf, automatisch auch Änderungen am Zielsystem vorzunehmen, und die oft mühseligen Zwischenschritte entfallen und werden wegautomatisiert. Das spart Aufwand auf beiden Seiten: Der Entwickler bekommt ein ihm bekanntes Tool an die Hand und die IT-Operationen-Abteilung verbringt weniger Zeit mit dem Erstellen von Deployment Dashboards und komplexen CI/CD-Pipelines.

Kubernetes ist überall

GitOps klingt also vielversprechend, allerdings gibt es die Grundvoraussetzung, dass das Zielsystem deklarativ konfigurierbar ist und der Sollzustand mit Konfigurationsdateien abgebildet werden kann. Ein deklarativ konfigurierbares System zeichnet sich vor allem dadurch aus, dass ein zu lösendes Problem in einer bestimmten Form beschrieben wird, aber der eigentliche Berechnungsablauf, um dieses Problem zu lösen, vom System selbst übernommen wird. Ein zurzeit sehr populäres System, das diesem Schema folgt, ist Kubernetes.  

Kubernetes ist eine Open-Source-Plattform zur Verwaltung von containerbasierten Anwendungen, die von Google 2014 ins Leben gerufen wurde und auf den langjährigen Erfahrungen im Bereich der Ausführung von Produktions-Workloads in großem Maßstab bei Google basiert [2]. Kubernetes selbst ist cloud-agnostisch, d. h. es kann in nahezu jeder beliebigen Public Cloud, sowie in privaten Rechennetzwerken betrieben werden und lässt sich sogar auf dem heimischen Laptop installieren. Dies, gepaart mit der mittlerweile enormen Funktionsdichte und weitflächigen Adaption, hat Kubernetes zu enormer Popularität verholfen, weswegen es im Bereich der Containerorchestrierung mittlerweile quasi alternativlos geworden ist. 

In Kubernetes wird typischerweise deklarativ im YAML-Format der Sollzustand eines Systems in so genannten Kubernetes-Ressourcen beschrieben. Diese Ressourcen bilden das Kernstück von Kubernetes und werden in etcd, dem Speicherbackend, persistiert. Die wichtigsten Ressourcen sind Nodes, Pods und Services:

Nodes beschreiben in Kubernetes Arbeitsmaschinen und können je nach Cluster entweder physische Maschinen oder VMs sein. Ohne Nodes kann ein Kubernetes-Cluster keine Arbeitslasten bereitstellen und ist handlungsunfähig. Eine Beispiel-Node könnte z. B. so aussehen:

apiVersion: v1
kind: Node
metadata:
    name: docker-desktop
status:
    addresses:
    - address: 192.168.65.3
      type: InternalIP
    - address: docker-desktop
      type: Hostname
    allocatable:
      cpu: "4"
      ephemeral-storage: "56453061334"
      hugepages-1Gi: "0"
      hugepages-2Mi: "0"
      memory: 3932656Ki
      pods: "110"

Pods beschreiben Arbeitslasten in Kubernetes und definieren, welche Container-Images ausgeführt werden sollen. Ein Pod kann aus einem oder mehreren Containern bestehen, die sich Ressourcen wie Speicher und Netzwerk teilen können. Pods werden immer genau einer Node zugewiesen und dann dort ausgeführt. Das passiert entweder automatisch von Kubernetes oder manuell. Pods werden innerhalb von Kubernetes als "Vieh" angesehen und können jederzeit von Kubernetes beendet oder neu gestartet werden, um sie z. B. auf eine andere Node zu verschieben. Ein einfacher Pod, der einen nginx-Container auf einer Node startet, sieht so aus:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx

Services beschreiben, wie Pods miteinander kommunizieren können und leiten eingehenden Traffic an die jeweiligen Pod Ports weiter. Services sind vonnöten, weil Pods beliebig neugestartet oder umgeschichtet werden können und somit keinen festen Endpunkt für Traffic darstellen. Services haben eine feste IP-Adresse innerhalb des Clusters und, sofern Cluster DNS verfügbar ist, auch einen festen Hostname.

Kubernetes bietet noch viele weitere Ressourcen und es ist möglich, auch eigene Ressourcen zu definieren, die die Clusterfunktionalität erweitern. 

GitOps und Kubernetes: ein Selbstläufer?

Kubernetes klingt also wie geschaffen für GitOps, denn der komplette Zustand eines Kubernetes-Clusters kann relativ einfach in Git gespiegelt werden. Kubernetes bietet dazu von Haus aus eine REST API an, mit der man die Ressourcen abfragen und ändern kann.Trotzdem gibt es einige Fallstricke, die bei der Implementierung von GitOps mit Kubernetes beachtet werden sollten:

  • Trennung von Konfiguration und Quellcode: In der Regel macht es Sinn, für den Systemzustand ein eigenes Git-Repository zu erstellen, das diesen spiegelt, ohne Quellcode von Applikationen zu beinhalten. Das reduziert zum Einen die Git-Commit-Historie und es ist einfacher, das System im Fehlerfall zurückzusetzen und verhindert zum anderen, dass das Repository aus allen Nähten platzt. Im Applikationsrepository gibt es dann jeweils eine Pipeline, die die erforderliche Konfiguration in dem zentralen Konfigurationsrepository aktualisiert, sofern sie sich unterscheidet. Somit lässt sich das GitOps-Prinzip auch relativ einfach für mehrere Applikationen innerhalb eines Zielsystems anwenden.
  • Richtung der Synchronisation: Oftmals ist es unerwünscht, dass Änderungen im Zielsystem zurück in das Git-Repository geschrieben werden, weswegen nur eine Richtung der Synchronisation erlaubt ist: von Git ins Zielsystem. Hierbei ist es allerdings möglich, dass der Zustand in Kubernetes sich unmittelbar nach der Synchronisation direkt wieder vom Zustand in Git unterscheidet, z. B. durch Mutating Webhooks, die Kubernetes-Ressourcen bei der Erstellung verändern. Hier ist es also nötig, dass gewisse Änderungen im Zielsystem ignoriert werden und keine erneute Synchronisation ausgelöst wird.
  • Wahl des richtigen Synchronisationstools: Die Implementierung von GitOps mit Kubernetes klingt zunächst einfach und verlockt zu Eigengewächsen. Im Regelfall sollte aber auf eine der bereits bestehenden Lösungen zurückgegriffen werden, denn diese bieten neben nützlichen Zusatzfunktionen auch eine ganze Reihe an Sicherheitseigenschaften, die das System vor Fehlkonfigurationen und Eindringlingen schützt.
  • Sensible Daten: Ein offensichtliches No-Go ist es, Passwörter und Zugangsdaten in Git selbst zu speichern. Wie ist es dann aber möglich, im Kontext von GitOps-Applikationen zur Laufzeit Zugang zu bestimmten Services zu geben, wenn der komplette Zustand in Git gespeichert ist?
    Es gibt mehrere Ansätze, um dieses Problem zu lösen, z. B. mit sogenannten Sealed Secrets [3]. Diese verfolgen die Idee, ein Kubernetes Secret lokal zu verschlüsseln, in Git einzuchecken und dann automatisiert im Zielcluster wieder zu entschlüsseln. Dies bietet eine relativ komfortable Möglichkeit, um sensible Daten trotzdem in Git einzuchecken, allerdings die Daten selbst vor den Augen Dritter zu verstecken.

Argo CD

Mit dem immer stärker werdenden Interesse an GitOps gibt es auch eine ganze Reihe an Tools, die GitOps in Kubernetes implementieren und die Aufgabe der Synchronisation der Ressourcen übernehmen. Eines der populärsten Tools im Bereich GitOps und Kubernetes ist dabei Argo CD. Argo CD ist ein deklaratives Open-Source GitOps-Continuous-Delivery-Tool für Kubernetes. Es ist seit 2018 auf Github verfügbar und wird von Intuit entwickelt [4]. In Argo CD werden einzelne Applikationen definiert, die ein Ursprungsrepository besitzen und in ein Zielsystem synchronisiert werden sollen. Argo CD bietet eine Vielzahl an Funktionen und Integrationen an, mit denen es möglich ist, das Verhalten an die eigenen Bedürfnisse anzupassen. Das Paradigma GitOps steht hier im Vordergrund und Argo CD versucht Best Practices in dem Bereich zu vermitteln, zwingt diese dem Benutzer aber nicht auf.   

Installation

Argo CD wird direkt in das Kubernetes-Cluster via kubectl oder helm als Operator installiert und erstellt eine eigene Kubernetes-Ressource (CRD), mit der man Applikationen definieren kann, die in das Cluster synchronisiert werden sollen. Jegliche Konfiguration wird in Kubernetes-Ressourcen gespeichert, was es ermöglicht, Argo CD selbst mit dem GitOps-Paradigma zu betreiben.

Funktionen

Argo CD bietet ein sehr breites Funktionsspektrum:

  • Application Deployment: Es ist möglich, Applikationen mit einer Vielzahl von Tools zu deployen, wie z. B. kubectl, helm, kustomize, ksonnet oder benutzerdefinierten Plugins.
  • Weboberfläche: Argo CD bietet eine Weboberfläche an, die das Konfigurieren von Applikationen vereinfacht.
  • Multi Cluster: Es ist möglich, Applikationen über Clustergrenzen hinweg zu spiegeln.
  • Multi Tenancy: Ein integrierter Dex Server [5] ermöglicht es, dass sich entfernt verwaltete Nutzer bei Argo CD authentifizieren können. Alternativ können auch zusätzliche lokale Nutzer konfiguriert werden.
  • Rechteverwaltung: Es ist möglich, Zugang zu bestimmten Ressourcen innerhalb von Argo CD für Nutzer zu erlauben oder zu verbieten.
  • Benutzerdefinierte Health Checks: Argo CD bietet umfangreiche Möglichkeiten an, den Zustand einer Applikation zu überprüfen und diesen im Falle von Problemen an die Kubernetes-Ressource weiterzugeben. Dabei kann der Nutzer mit Hilfe der Programmiersprache Lua seine eigenen Health Checks implementieren.
  • Benachrichtigungen: Argo CD bietet keine direkte Unterstützung für Benachrichtigungen an, allerdings gibt es Drittanbieter Projekte, die diese Funktionalität ergänzen.
  • Erweiterbarkeit: Argo CD erlaubt es durch seine kubernetes-native Arbeitsweise, Anpassungen direkt an den Kubernetes-Ressourcen selbst vorzunehmen.

Zusätzlich hat man auch die Möglichkeit, Plugins zum Deployen von Applikationen zu definieren, die allerdings zur Laufzeit im Pod verfügbar sein müssen. Benutzerdefinierte Hooks können erstellt werden, die Aufgaben erledigen, falls eine Ressource gespiegelt wird.

Deployment einer WordPress-Beispielanwendung

Wir wollen jetzt eine kleine WordPress-Beispiel-Applikation mittels Argo CD in ein Kubernetes-Cluster deployen. Damit wollen wir zeigen, wie es möglich ist, GitOps im eigenen Kubernetes-Cluster zu implementieren. Dazu benötigen wir zuerst ein funktionsfähiges Kubernetes-Cluster. Es gibt zahlreiche Möglichkeiten ein Kubernetes-Cluster zu erstellen, allerdings reicht es für das Beispiel aus, ein Test-Cluster auf dem lokalen Rechner zu installieren, wie z. B. docker desktop [6] oder minikube [7]. Als nächstes benötigen wir das Kubernetes CLI-Tool kubectl [8], das uns erlaubt, Änderungen am Cluster vorzunehmen. Haben wir beides installiert, überprüfen wir die korrekte Installation mit:

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.3", GitCommit:"2e7996e3e2712684bc73f0dec0200d64eec7fe40", 
GitTreeState:"clean", BuildDate:"2020-05-20T12:52:00Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"16+", GitVersion:"v1.16.6-beta.0", GitCommit:"e7f962ba86f4ce7033828210ca3556393c377bcc", 
GitTreeState:"clean", BuildDate:"2020-01-15T08:18:29Z", GoVersion:"go1.13.5", Compiler:"gc", Platform:"linux/amd64"}

Als nächstes installieren wir Argo CD in das Kubernetes-Cluster:

kubectl create namespace argocd
kubectl apply -n argocd -f raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

Damit werden die Argo-CD-Komponenten in das Cluster installiert, was je nach Internetverbindung eine Weile dauern kann. Den Status von Argo CD können wir mittels kubectl abfragen:

$ kubectl get po -n argocd
NAME                                             READY   STATUS              RESTARTS   AGE
argocd-application-controller-775fcd65b9-9n4bg   0/1     ContainerCreating   0          77s
argocd-dex-server-58dcbb59b5-rfbt2               0/1     Init:0/1            0          77s
argocd-redis-8c568b5db-vwltk                     0/1     ContainerCreating   0          77s
argocd-repo-server-b8f8b66c7-g8nn7               0/1     ContainerCreating   0          77s
argocd-server-6ccf9b54d9-fd8mg                   0/1     ContainerCreating   0          77s

Hier sehen wir die einzelnen Komponenten mit ihrem jeweiligen Status. Die Argo-CD-Komponenten übernehmen dabei folgende Aufgaben:

  • Application Controller: Überwacht die laufenden Applikationen und erkennt Unterschiede zwischen Soll- und Istzustand. Falls konfiguriert, spiegelt der Application Controller automatisch die Anwendung neu, wenn ein Unterschied erkannt wurde.
  • Dex Server: Ein Dex Server [5], der es ermöglicht, sich via Single Sign On bei Argo CD anzumelden.
  • Redis: Ein Wegwerf-Cache für Argo CD.
  • Repo Server: Hält Git Repositories in einem lokalen Cache und generiert die zu deployenden Kubernetes-Manifeste aus den jeweiligen Git Repositories.
  • API Server: Ein gRPC/REST API Server, der die API für Weboberfläche, CLI und CI/CD-Systeme bereitstellt.

Nach einer Weile sollten nun alle Komponenten gestartet sein und den Status 'Running' aufweisen:

$ kubectl get po -n argocd
NAME                                             READY   STATUS    RESTARTS   AGE
argocd-application-controller-775fcd65b9-9n4bg   1/1     Running   0          7m54s
argocd-dex-server-58dcbb59b5-rfbt2               1/1     Running   0          7m54s
argocd-redis-8c568b5db-vwltk                     1/1     Running   0          7m54s
argocd-repo-server-b8f8b66c7-g8nn7               1/1     Running   0          7m54s
argocd-server-6ccf9b54d9-fd8mg                   1/1     Running   0          7m54s

Jetzt leiten wir in einem anderen Terminal den UI Port von Argo CD an unseren lokalen Rechner via kubectl weiter, damit wir darauf in unserem Webbrowser zugreifen können:

$ kubectl port-forward svc/argocd-server -n argocd 8080:443
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080

Im Webbrowser sollte nun Argo CD unter der Adresse `https://localhost:8080` erreichbar sein (unglaubwürdigen Zertifikaten sollte in diesem Fall vertraut werden).

Der Nutzername für die Login-Oberfläche ist admin und das Passwort ist der Pod-Name des Ago CD Servers, der mit dem folgenden Command zurückgegeben werden kann:

$ kubectl get pods -n argocd -l app.kubernetes.io/name=argocd-server -o name | cut -d'/' -f 2
argocd-server-6ccf9b54d9-fd8mg

Nachdem wir erfolgreich eingeloggt sind, wollen wir anschließend eine kleine WordPress-Anwendung erstellen. Dazu erstellen wir zunächst den Applikations-Namespace via kubectl:

$ kubectl create ns wordpress
namespace/wordpress created

Nun klicken wir in der Argo-CD-Weboberfläche auf den Knopf '+ NEW APP' und erstellen eine neue Applikation mit den folgenden Einstellungen, s. Abb. 4:

Wir bestätigen mit 'Create' und sehen im Hauptbildschirm eine neue Applikation, die im Moment den Status 'OutOfSync' aufweist. Nach einem Druck auf den 'Sync'-Knopf, sollte sich der Status der Applikation auf 'Synced' und 'Healthy' ändern:

Argo CD hat nun die WordPress-Applikation für uns in den Kubernetes-Namespace wordpress deployed. Wir können die erfolgreiche WordPress-Installation mittels kubectl lokal überprüfen:

$ kubectl get po -n wordpress
NAME                               READY   STATUS    RESTARTS   AGE
wordpress-966746c95-9rjjg          1/1     Running   0          14s
wordpress-mysql-576984556c-rmr85   1/1     Running   0          14s
$ kubectl port-forward -n wordpress svc/wordpress 8090:80
Forwarding from 127.0.0.1:8090 -> 80
Forwarding from [::1]:8090 -> 80

Im Webbrowser sollte nun unter der Adresse 'http://localhost:8090' eine voll funktionsfähige WordPress-Installation auf uns warten. Um zu zeigen, wie Argo CD reagiert, wenn sich der Zustand im Kubernetes-Cluster unerwartet ändert, löschen wir nun das WordPress-Deployment mit kubectl:

$ kubectl delete deployment wordpress -n wordpress
deployment.apps "wordpress" deleted

Zurück in der Argo-CD-Weboberfläche, sollte der Status der Applikation nun wieder auf 'OutOfSync' gesprungen sein. Durch einen Druck auf den 'Sync'-Knopf, sollte das WordPress-Deployment wiederhergestellt werden. Natürlich können wir in Argo CD auch einstellen, dass bei Änderungen im Cluster oder in Git ein automatischer Sync erfolgen soll. Dazu klicken wir auf die Applikation und drücken auf den 'APP DETAILS'-Knopf am oberen Bildschirmrand. In der Sektion 'Sync Policy' drücken wir auf 'ENABLE AUTO-SYNC', um die automatische Synchronisation einzuschalten. Zusätzlich drücken wir bei der Option 'Self Heal' auf 'ENABLE'.

Wir löschen nun erneut das WordPress-Deployment mit kubectl und sehen, dass Argo CD das Deployment unmittelbar erneut erstellt und der Stand aus Git in das Kubernetes-Cluster synchronisiert wird.

Andere Tools

Neben Argo CD gibt es noch eine Reihe an anderen Tools, die GitOps für Kubernetes implementieren:

  • Flux ist ein GitOps-Operator für Kubernetes, der automatisiert überprüft, ob die Konfiguration eines Kubernetes-Clusters der in einem Git-Repository entspricht, und synchronisiert diese. Flux ist Open-Source-Software, Sandbox-Projekt der CNCF (Cloud Native Computing Foundation) und unter der Apache-2.0-Lizenz auf Github frei verfügbar. Flux ist auf Einfachheit getrimmt und verzichtet dadurch auf einige Funktionen, wie z. B. die Synchronisation in mehrere Cluster oder Multi-Tenancy. Zusätzlich synchronisiert Flux immer nur ein Git-Repository pro Installation gleichzeitig und wird direkt in das Kubernetes-Cluster installiert. Neben Argo CD ist Flux das populärste Projekt im Bereich GitOps und wird aktiv von der Community weiterentwickelt.
  • Jenkins X ist im Vergleich zu Flux und Argo CD eine Komplettlösung für CI/CD mit integrierter Unterstützung für GitOps. Jenkins X unterscheidet sich deutlich von den Vorgängerversionen und baut nun intern auf Tekton auf, das ein Projekt zur Definition von CI/CD-Pipelines in Kubernetes ist. Wie Flux und Argo CD ist Jenkins X quelloffen auf Github verfügbar. Jenkins X selbst wird seit Anfang 2018 von Cloudbees entwickelt. Neben GitOps-Funktionalitäten umfasst Jenkins X auch große andere Teile des Entwicklungsprozesses wie die Build- und Testphasen einer typischen CI-Pipeline und das Speichern von Container-Images.
  • Viele andere Tools mit denen es möglich ist, GitOps in Kubernetes in Teilen oder als Ganzes zu implementieren, wie z. B. GitKube [9], Terragrunt [10], kiosk [11] und Helm Operator [12].

Fazit

GitOps ist ein viel verspechendes neues Paradigma in der Container-Welt, das in der Lage ist, CI/CD-Prozesse zu vereinfachen und Entwicklern sowie Administratoren Arbeit zu ersparen. GitOps ist dabei eine logische Erweiterung zur Idee von Infrastructure-as-code und stellt Git als zentrale, einzig verlässliche Datenquelle in den Mittelpunkt. Durch die einfache Synchronisation von Konfiguration zwischen Git und Zielsystem entfallen zum Teil komplexe CI/CD-Pipelines und Berechtigungsprozesse automatisch.

Wichtigste Grundvorraussetzung von GitOps ist ein deklarativ konfigurierbares Zielsystem, ohne welches der Einsatz nur stark begrenzt möglich ist. Kubernetes erfüllt diese Voraussetzung, allerdings ist die Implementierung kein Selbstläufer und eine kontinuierliche Überwachung sowie Wartung des Systems ist vonnöten.  

Im Kubernetes-Ökosystem gibt es bereits einige Open-Source-Tools, die den Löwenanteil der Arbeit übernehmen und mit vielen Zusatzfunktionen bestückt sind. In Zukunft kann man sicherlich noch mehr Funktionalität und Reife erwarten. In Anbetracht der Tatsache, dass GitOps aber noch ein vergleichbar junges Thema ist, sind diese Hilfswerkzeuge schon sehr gut benutzbar.

Autor

Fabian Kramm

Fabian Kramm ist Mitgründer der DevSpace Technologies Inc. und seit Jahren aktiv im Cloud-native-Umfeld. Er ist Open-Source-Software-Enthusiast und hat einen Master im Bereich Wirtschaftsinformatik.
>> Weiterlesen
Das könnte Sie auch interessieren
Kommentare (0)

Neuen Kommentar schreiben