Wir bei b-nova haben uns dem GitOps-Pattern verschrieben. Dieser Artikel ist ein weiterer Teil einer mehrteiligen Serie über das GitOps-Thema. Falls Sie das GitOps-Pattern noch nicht kennen sollten, schauen Sie sich vielleicht zuerst den ersten Teil GitOps als Devops oder den zweiten Teil über Argo CD an. Kurz zusammengefasst ist die Idee bei GitOps Git als Single-Source-of-Truth für den Applikations-, aber auch Infrastruktur-Code (Infrastructure-as-Code) zu nutzen.
Mit Argo CD eignet sich zum Beispiel ideal, um über Infrastruktur-Repos automatisierte Pipelines in Ihren Kubernetes-Cluster zu integrieren. Dabei wird geprüft, ob der Zielzustand, beschrieben in dem entsprechenden Git-Repo, auf dem Cluster bereits vorhanden ist. Falls nicht, würde Argo CD den Prozess anstossen um diesen Zielzustand auf dem Cluster zu etablieren.
Die Idee GitOps wird mit werf –dem sogenannten ‘Consistent Delivery Tool’ von Flant– noch konsequenter als mit Argo CD umgesetzt. Anstatt nur die Infrastruktur-Codebase als Single-Source-of-Truth zu nutzen, wird bei werf auch die Applikations-Codebase berücksichtigt. Somit ist der ganze Prozess aus GitOps-Sicht deterministisch und idempotent: Der ganze Prozess wird von Git-Repo bis zum laufendem Pod im Kubernetes-Cluster für alle DevOps-Stakeholder noch transparenter.
In diesem Beitrag werden wir uns die Grundfunktionalität, die werf bietet anschauen. Danach werden wir gemeinsam in einem kurzen Handson eine Git-Repo mit werf bauen lassen.
Der Bauplan mit werf
werf ist in Go geschrieben und ist im Grunde ein einfaches CLI-Tool. Es ist genau für einen GitOps-Fall gedacht; nämlich in Zusammenschluss mit Git-Repositories für Applikation und Infrastruktur, einer Docker-Repository und Kubernetes als Platform.
Im folgenden Diagram ist der Aufbau eines GitOps-Patterns mit werf ersichtlich:
werf spielt dabei das Bindeglied zwischen den Git-Repositories (oben), der Docker-Repositories (rechts) und dem Kubernetes-Cluster (unten). werf bietet mit werf converge
, dem Hauptbefehl von werf, die Möglichkeit den Zustand auf der Git-Repo mit dem Zustand der Docker-Repository mit dem laufendem Zustand auf dem Kubernetes-Cluster zu synchronisieren.
In anderen Worten löst werf converge
den Prozess aus, wobei werf prüft ob es für den vorhandenen Code-Zustand in der Git-Repo bereits entsprechende Docker-Images in der Docker-Repository gibt, falls ja, prüft werf ob diese Docker-Images in dieser Form bereits auf dem Kubernetes-Cluster am laufen sind. Falls nicht, veranlasst werf den Bau, den Push in die Docker-Repository, sowie das Ausrollen der neuen Docker-Images. Dieser Prozess wird auf der offiziellen Introduction-Seite noch detaillierter beschrieben.
Somit kümmert sich werf um:
- das Bauen von Docker-Images
- das Ausrollen der Applikation in den Kubernetes-Cluster
- das Sicherstellen, dass die Applikation lauffähig und healthy auf dem Cluster läuft
- falls nötig, das erneute Bauen von Docker-Images, wenn der Code sich geändert hat
- falls nötig, das erneute Ausrollen der Applikation auf den Cluster
- das Aufräumen von obsoleten oder irrelevanten Docker-Images in der Docker-Registry
Die Kernfunktionen die werf nutzt und dem Nutzer bereitstellt sind:
werf build
: Docker-Images bauenwerf publish
: Docker-Images taggen und auf Docker-Repository hochladenwerf publish-and-publish
: Zuerstbuild
, danachpublish
werf deploy
: Zustand von Docker-Images mit Zustand von Kubernetes synchronisierenwerf converge
: Zuerstbuild
, danachpublish
, zuletztdeploy
werf run
: Unit-Testing des gebauten Docker-Imageswerf dismiss
: Applikation im Kubernetes-Cluster terminierenwerf clean
: Ungenutzte Docker-Images aus der Repository löschen
Die wichtigste Funktion ist, wie vorhin bereits beschrieben, werf converge
. Man kann werf jedesmal von Hand oder werf irgendwo automatisiert ausführen lassen. Um dies zu veranschaulichen, werden wir werf im nächsten Schritt zusammen praktisch ausprobieren.
Werf im Einsatz
Um die Kernfunktionalität und das Feeling von werf besser zu verstehen, werden wir jetzt werf aufsetzen und ein Beispiel-GitOps-Pattern mit einer personalisierten Git-Repository durchspielen. Dabei lehnen wir uns an den offiziellen Quickstart von werf an.
Die Idee dabei ist, dass Docker-Images für mehrere Applikationen, die in einer Git-Repo vorhanden und definiert sind, per werf bauen lassen und den lokalen Kubernetes-Cluster damit bespielen. Nach dem Ausrollen der Applikation nehmen wir einen Change an der Codebase einer Applikation vor und schauen, ob und wie werf danach das GitOps-Pattern handiert.
Voraussetzungen
Damit Sie auch mitmachen können, sollten Sie folgende Voraussetzungen im Vorfeld erfüllen:
- Docker installiert und running
- Docker Hub-Account (oder gleichwertige Docker-Repository) vorhanden
- Lokales Minikube installiert und running (siehe hier Minikube Installation)
Git-Repo forken
Unter github.com/b-nova/quickstart-application gibt es eine Quickstart-Applikation-Repo. Am besten forken Sie sich diese Git-Repo in Ihr persönliches Repo. Anschliessend klonen Sie sich die geforkte Repo auf ihren Rechner (hier exemplarisch mit der Repo von b-nova):
|
|
Architektur der Applikation im Git-Repo
Die obige Git-Repository beinhaltet 5 Komponenten, davon 3 Applikationen (vothing-app, result-app und worker) und zwei Persisiterungseinheiten (redis und db). Mit der Gesamtapplikation lassen sich Abstimmungen vornehmen, wobei voting-app als Eingabe-UI der einzelnen Abstimmungen und result-app als Darstellungs-UI der Abstimmungsresultate dient. Das folgende Schema zeigt dies auf:
Für uns interessanter ist die Folder-Struktur. Unter den jeweiligen Sub-Foldern result/..
, vote/..
und worker/..
liegt jeweils ein Dockerfile, die die entsprechende Applikation als Container beschreibt. Unter .helm/..
liegen Helm-Charts, die die Cluster-Konfiguration von Kubernetes beschreiben. Auf Root-Ebene liegt noch die zentrale werf.yaml
, die werf die GitOps-relevanten Informationen zukommen lässt. Hier die werf.yaml von unserer Quickstart-Applikation Git-Repository:
|
|
Die werf.yaml ist sehr einfach gehalten und gänzlich selbsterklärend. Installieren wir nun als Nächstes werf.
werf installieren
werf hat ein flexibles Installationstool, das es Ihnen erlaubt die richtige werf-Binary für Ihr Zielsystem zu ziehen. Das heisst multiwerf, und so geht es:
|
|
Einfach ausführen und schon kann man mit werf version
prüfen, ob man die letzte Version aufrufen kann.
Falls alles funktioniert hat, sind wir bereit werf auf unsere Applikationen loszulassen.
werf converge
Bevor wir hier weitermachen, vergewissern Sie sich, dass Minikube bei Ihnen lokal läuft und einsatzbereit ist. Falls nicht, versuchen Sie es wie folgt. Wichtig ist docker als Treiber anzugeben.
|
|
Wechseln Sie nun in die Repository.
|
|
Und nun führen Sie werf converge
aus. Dabei geben wir mit dem --repo
-Flag unsere Docker-Repository (ich nutze hier meine), mit der werf die zu bauenden Docker-Images synchronisierne soll. Und mit dem --repo-docker-hub-token
-Flag geben wir einen Security-Token mit, dass die Docker-Registry weiss wer wir sind.
|
|
Der Output von werf converge
seht in etwa so aus:
Man sieht dabei, dass das Ausrollen der Docker-Images auf den Cluster mit jeweils einer Replicas erfolgreich am laufen ist.
Die zwei Frontends, voting-app und results-app kann man unter folgenden Endpunkten
http://127.0.0.1:51226/ und http://127.0.0.1:51329/ aufrufen. Falls die Ports anders sein sollten, kann man per minikube service
die entsprechenden Endpunkte ausfindig gemacht werden:
|
|
|
|
Die UIs sollten so aussehen. Links die Result-App, rechts die Vote-App.
Jetzt ist es interessant zu wissen, wie sich werf verhält wenn man was in der Repository anpasst und werf converge
nochmals ausführt. Dafür können Sie beispielsweise den Titel ‘Cats vs Dogs!’ der Result-App in der result/views/index.html
austauschen:
|
|
Pushen Sie anschliessend den Change in die Repo und lassen Sie werf converge
nochmals laufen. Sie werden sehen, dass die Docker-Images neu gebaut werden, mit einem neuen Tag in die Docker-Registry hochgeladen werden, und das Frontend den neuen Titel tatsächlich ausgibt, sobald das Ausrollen in den Minikube-Cluster erfolgt ist.
Fazit
werf ist ein kleines, aber feines CLI-Tool um einfach und schnell ein GitOps-Pattern in Ihrem Kubernetes-Cluster einzuführen. Dabei wird nicht nur der Infrastruktur-Code, sondern auch der Applikationscode berücksichtigt. Dies ermöglicht ein ganzeinheitliches GitOps-Pattern, das von der Wiege zur Senke das Paradigma zulässt.
Falls Ihnen der Beitrag zu werf gefallen hat, lassen Sie es uns wissen und verpassen Sie es nicht Dmitry Stolyarov, Entwickler von werf und CEO von Flant, persönlich in seinem CNCF Webinar zu Delivering cloud-native apps to Kubernetes using werf zuzuhören.
Wir bei b-nova sind begeistert von GitOps und würden auch Ihnen gerne unterstützen Ihr GitOps-Pattern beispielsweise mit werf zum Erfolg zu verhelfen.