Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Heroku CI/CD Review Apps auf Google Cloud Platform nachbauen

By Mike SparrAug 26, 20207 min read

Diese Seite ist auch in English, Español, Français, Italiano, 日本語 und Português verfügbar.

Eine beliebte Funktion von Heroku ist die Lösung Review Apps. Sie erzeugt während eines Pull Requests (PR) eine temporäre Umgebung samt App-Instanz und räumt diese nach dem Merge des PR wieder ab.

Inspiriert von diesem Konzept und einem aktuellen Kundengespräch bei DoiT International habe ich mir vorgenommen, dieses Verhalten auf der Google Cloud Platform (GCP) mit einem cloud-native Ansatz und gängigen Open-Source-Tools nachzubauen.

Developer Experience (20-Minuten-Demo)

Wenn Sie sich an die GitOps-Prinzipien halten, muss sich Ihr Entwicklungsteam nur noch ums Coden kümmern. Sobald jemand einen PR erstellt, steht innerhalb von Sekunden bis Minuten eine review-fertige Version des aktuellen Codes online bereit.

Weitere Commits aktualisieren die Review App so lange, bis Reviewer und Tester zufrieden sind und den PR freigeben bzw. mergen. Sobald die App in eine höhere Umgebung übernommen wurde, wird die Review App entfernt – und das Spiel beginnt für jedes Feature von vorn.

Demo der Heroku-artigen Review App und GitOps-CI/CD-Pipeline (20 Minuten)

YouTube-Demo-Video ansehen

Beteiligte Komponenten

  • Github – Versionskontrolle
  • Kustomize – Kubernetes-natives Konfigurationsmanagement
  • Argo CD – deklaratives GitOps CD für Kubernetes
  • Kong Ingress Controller – API-Gateway
  • Google Kubernetes Engine (GKE) – Managed Kubernetes
  • Google Cloud Build – CI-Server
  • Google Container Registry (GCR) – private Container-Image-Registry
  • Google Secret Manager – zentrales Secrets-Management
  • Google Cloud DNS – API-fähiger DNS-Dienst (optional)

Architektur

Die Kernfunktion von Review Apps: Sobald ein Entwickler in der Versionskontrolle einen Pull Request (PR) öffnet, baut die Deployment-Pipeline eine Kopie der App und stellt sie in einer isolierten Umgebung unter einer eindeutigen URL zum Review bereit.

Entwickler-PR erzeugt Review App

Darüber hinaus wird die Anwendung nach dem Merge des PR in die Produktion übernommen und die Review App wieder abgeräumt.

Reviewer-/Admin-Merge übernimmt in die Produktion und löscht die Review App

TL;DR

Damit alles wie gezeigt funktioniert, sind folgende Schritte nötig:

  1. Separate App- und Config-Source-Repos auf Github anlegen
  2. Google APIs aktivieren sowie GKE-Cluster und Argo CD bootstrappen
  3. Kong API Gateway (Ingress Controller) über das Config-Repo installieren
  4. DNS-A-Record auf die externe IP von kong-proxy setzen
  5. Cloud Build mit Ihrem Github-Repository verbinden
  6. Privaten Schlüssel erzeugen und im Google Secret Manager hinterlegen
  7. Public Key zum Github-Config-Repo hinzufügen
  8. 3 Cloud-Build-Trigger anlegen (push, PR, merge)
  9. Cloud-Build-Service-Account für den Zugriff auf Secrets autorisieren
  10. Cloud-Build-Konfigurationsdateien zum App-Repo hinzufügen
  11. Kubernetes-Manifeste und Kustomize-Overlays zum Config-Repo hinzufügen

Github-Source-Repositorys anlegen

Die folgenden Repositorys sind funktionierende Beispiele – die einzelnen Aufbauschritte erkläre ich in den nachfolgenden Abschnitten.

  • Demo App – Dockerfile und Cloud-Build-CI-Skripte
  • Demo App Config – Setup-Skripte und Kubernetes-Manifeste für Argo CD

APIs aktivieren, GKE und Argo CD bootstrappen

Im folgenden Skript habe ich die Google-Cloud-Service-APIs aktiviert und einen Kubernetes-Cluster hochgefahren.

In einem früheren Artikel habe ich das App-of-Apps-Pattern vorgestellt, das auch das Argo-Dev-Team bei Intuit einsetzt. Beim Design dieser Lösung passt das dynamische Erzeugen und Entfernen einer Application perfekt zu unserem Use Case, Review Apps zu erstellen und wieder zu verwerfen.

Kong API Gateway (Ingress Controller) installieren

Für Kong legen Sie einfach eine Datei kong.yaml im Ordner /apps des Config-Repos an. Argo CD erkennt und überwacht jedes Repo bzw. jeden Ordner, auf den Sie es verweisen. Ich habe mich für Kong entschieden, weil jeder von mir erstellte Ingress einen Host konfiguriert – ideal, um dynamisch neue Host-URLs für Review Apps zu erzeugen.

Legen Sie die Kong-Konfigurationsdateien im Zielordner ab, dann wird Kong auf Ihrem Kubernetes-Cluster installiert (für weitere gewünschte Apps wiederholen).

Beachten Sie den source.path (kong). Das ist der Ordner im Repo mit den YAML-Manifesten, die Argo CD installiert. Ich habe im Repo eine Datei 01-install.yaml angelegt, die Kongs eigenes Single-Manifest aus dem Ordner /kong des Config-Repos verwendet. (https://bit.ly/k4k8s verweist auf die aktuelle Kong-Konfiguration)

curl https://raw.githubusercontent.com/Kong/kubernetes-ingress-controller/master/deploy/single/all-in-one-dbless.yaml --output kong/01-install.yaml

DNS-A-Record für Kong Proxy anlegen

Nach der Installation auf Ihrem Cluster legt Kong einen externen TCP-Load-Balancer (Service) mit externer IP an.

Kong-Proxy-Load-Balancer-Service auf dem Kubernetes-Cluster

Auf diese IP soll Ihre Domain zeigen – das richten Sie manuell bei Ihrem Provider ein. Für meine erste Demo habe ich einfach den A-Record und ein paar CNAME-Aliase wie unten konfiguriert.

Manuell konfigurierte DNS-Einträge

Alternativ können Sie Ihre Domain über Google Cloud DNS verwalten. Dazu müssten Sie auf Googles Nameserver verweisen und könnten dann dynamisch Review-App-URLs anhand der PR-Nummer erzeugen (ideal). Nach dem Bootstrapping von GKE und Kong richten Sie das mit folgenden Befehlen ein.

Cloud Build mit Github verbinden

Eigentlich kann ich Artikel nicht ausstehen, die einen auf andere Artikel weiterleiten – aber der Kürze halber: Bitte folgen Sie diesen beiden Schritten, um Cloud Build mit Github zu verbinden und einen SSH-Schlüssel im Secret Manager zu hinterlegen. Beides ist in den folgenden zwei Google-Artikeln gut beschrieben:

  1. Cloud Build mit Github verbinden
  2. Schlüssel und Secret für den Zugriff auf private Repos hinzufügen – aktivieren Sie hier die Checkbox "commit" am Config-Repo, damit Ihre App-Build-Pipeline anschließend Änderungen am Tag der Docker-Image-Version committen kann.

3 Cloud-Build-Trigger anlegen

Streng genommen würden für das gewünschte Verhalten nur die PR- und Merge-Trigger samt zugehöriger Konfigurationsdateien ausreichen. In der Praxis wünschen Sie sich aber auch App-Builds und -Deploys für Entwickler – deshalb habe ich einen dritten Push-Trigger auf den Develop-Branch ergänzt.

Cloud-Build-Trigger

Beachten Sie, dass ich in den Konfigurationen unten benutzerdefinierte ENV-Variablen ergänze (jeweils am Seitenende). Damit lassen sich der App-Name aus den Konfigurationsdateien heraus referenzieren und optional stage-abhängige Schritte einbauen.

Der Einfachheit halber habe ich 3 Trigger und 3 separate Konfigurationsdateien angelegt (siehe nächster Abschnitt) – mit diesen Features ließe sich das aber auch zusammenfassen.

Develop-Branch baut/deployed bei jedem Push ein Docker-Image

Pull Request von einem anderen Branch nach master (prod)

Merge des PR in den master-Branch (prod)

Cloud-Build-Konfigurationsdateien zum App-Repo hinzufügen

Der erste Teil der Build-Konfigurationsdateien ist ziemlich einfach: Ein Docker-Image wird gebaut und in die Google Container Registry (GCR) gepusht. Die nachfolgenden Schritte nutzen das Secret aus dem Secret Manager, um das Config-Repo zu klonen, Dateien zu ändern und einen Commit zu pushen. Das stößt Argo CD an, die letzten Änderungen zu synchronisieren und die Apps auf Ihrem GKE-Cluster zu aktualisieren.

In dieser Datei aktualisiert sed -i ... den Image-Tag auf den zuletzt nach GCR gepushten Build.

In der PR-Stage taggen wir die Images mit v$_PR_NUMBER, damit sie bei weiteren Commits während des PR-Reviews aktualisiert werden können (das ändere ich vielleicht noch). Eine weitere Besonderheit: Wir kopieren /templates/demo-app-review.yaml in den Ordner /apps, damit Argo CD den Zielpfad zu überwachen beginnt.

Das Besondere ist hier der Schritt "Removing review app …", in dem wir die Datei mit rm apps/demo-app-review.yaml entfernen. Da wir in unserer Application-Konfiguration autoSync und prune aktiviert haben, erkennt Argo CD das und entfernt die Review App vom GKE-Cluster.

Kubernetes-Manifeste und Kustomize-Overlays hinzufügen

Wir könnten (und sollten) einen eigenen Blogpost allein zu Kustomize und seiner Rolle beim Kubernetes-nativen Konfigurationsmanagement schreiben. Üblicherweise paketieren Sie Apps mit Helm-Charts oder Code-basierten "sonnet"-Tools – ich bevorzuge es, die Sache mit Kustomize schlank und erweiterbar zu halten.

Das Config-Repo ist so organisiert, dass jede App – in unserem Fall /demo-app/base – ihre Manifeste und eine kustomization.yaml enthält.

  • namespace.yaml – eigener Namespace
  • ingress.yaml – Ingress-Konfiguration, die Kong erkennt und für die er eine Route anlegt
  • service.yaml – Netzwerk-"Wrapper" für die Backend-Pods
  • deployment.yaml – Ihre eigentliche App (mit Verweis auf das Image)
  • kustomization.yaml – Kustomize-Konfiguration

Anschließend ergänzen wir Overlays, die unsere Umgebungen abbilden. Diese Konfigurationen ersetzen oder patchen die YAML-Dateien mit umgebungsspezifischen Werten wie App-Namens-Suffix, Namespace oder Ingress-Hostname (für dynamische Review-App-URLs).

  • /overlays/develop – Konfigurationen für die Develop-Umgebung
  • /overlays/review – Konfigurationen für die Review-App-Umgebung
  • /overlays/production – Konfigurationen für die Produktionsumgebung

Sie finden das alles im Beispiel-Github-Config-Repo. Unten sehen Sie eine Beispiel-Overlay-Konfiguration und Patch-Datei, mit der umgebungsspezifische URLs im Ingress erzeugt werden.

Beachten Sie, dass die Eigenschaft patchesStrategicMerge auf eine Datei verweist. Kustomize merged den Inhalt dieser Datei (oder mehrerer Dateien), um Werte wie den unten gezeigten Ingress-Hostnamen zu überschreiben und so eine eigene URL pro Umgebung zu ermöglichen.

Optional: dynamische URLs pro PR

Für meine erste Demo habe ich dieselbe URL verwendet. Wenn Sie aber Cloud DNS einsetzen, ergänzen Sie in Ihrer cloudbuild-pr.yaml einen weiteren Schritt wie unten, um die URLs dynamisch zu machen. Zum Zeitpunkt dieses Artikels habe ich das noch nicht getestet, plane aber, meine Nameserver umzustellen und das ebenfalls auszuprobieren.

Außerdem würden Sie im Konfigurationsskript ein weiteres sed -i ... ergänzen, das bei jedem PR-Deploy die Patch-Datei ingress-host.yaml dynamisch ersetzt.

Werden Sie Teil meines Teams

Steigen Sie bei DoiT International ein und entwickeln Sie Ihre eigenen spannenden Lösungen wie diese – schauen Sie auf unserer Karriereseite vorbei

Auch wenn dieser Beitrag viel Stoff enthält: Der Gesamtprozess ist gar nicht so kompliziert. Mit den geteilten Beispiel-Repos können auch Sie Ihre Engineers entlasten, sodass sie sich weniger um Infrastruktur und mehr um das kümmern können, was sie am besten beherrschen.

Erfolgreiche CI/CD-Build-Pipeline mit GitOps und Heroku-artigen Review Apps während eines PR