Wie wir die kontinuierliche Bereitstellung von Updates für die Kundenplattform implementiert haben

Bei True Engineering haben wir den Prozess der kontinuierlichen Bereitstellung von Updates für die Server des Kunden eingerichtet und möchten diese Erfahrung teilen.

Zunächst haben wir ein Online-System für den Kunden entwickelt und in unserem eigenen Kubernetes-Cluster bereitgestellt. Jetzt ist unsere hoch geladene Lösung auf die Plattform des Kunden umgestiegen, für die wir den vollautomatischen Continuous Deployment-Prozess eingerichtet haben. Dank dessen haben wir die Markteinführungszeit verkürzt - die Bereitstellung von Änderungen an der Produktumgebung.

In diesem Artikel werden alle Phasen des CD-Prozesses (Continuous Deployment) oder die Bereitstellung von Updates für die Kundenplattform beschrieben:

  1. Wie beginnt dieser Prozess?
  2. Synchronisation mit dem Git-Repository des Kunden,
  3. Backend- und Frontend-Assembly
  4. automatische Bereitstellung der Anwendung in einer Testumgebung,
  5. automatische Bereitstellung auf Prod.

Dabei werden wir die Details der Einstellungen teilen.



1. Starten Sie die CD


Die kontinuierliche Bereitstellung beginnt mit der Tatsache, dass der Entwickler die Änderungen im Release-Zweig unseres Git-Repositorys veröffentlicht.

Unsere Anwendung basiert auf einer Microservice-Architektur und alle ihre Komponenten werden in einem Repository gespeichert. Dank dessen werden alle Microservices zusammengebaut und installiert, auch wenn sich einer von ihnen geändert hat.

Wir haben die Arbeit in einem Repository aus mehreren Gründen organisiert:

  • Einfache Entwicklung - Die Anwendung wird aktiv entwickelt, sodass Sie sofort mit dem gesamten Code arbeiten können.
  • Eine einzelne CI / CD-Pipeline, die sicherstellt, dass die Anwendung als einzelnes System alle Tests besteht und an die Produktumgebung des Kunden geliefert wird.
  • Wir schließen Verwirrung in den Versionen aus - wir müssen keine Karte der Microservice-Versionen speichern und unsere Konfiguration für jeden Microservice in Helm-Skripten beschreiben.

2. Synchronisation mit dem Git-Repository des Kundenquellcodes


Die vorgenommenen Änderungen werden automatisch mit dem Git-Repository des Kunden synchronisiert. Dort wird die Assembly der Anwendung konfiguriert, die nach dem Aktualisieren des Zweigs und der Bereitstellung zu prod beginnt. Beide Prozesse finden in ihrer Umgebung über das Git-Repository statt.

Wir können nicht direkt mit dem Repository des Kunden arbeiten, da wir unsere eigenen Entwicklungs- und Testumgebungen benötigen. Wir verwenden unser Git-Repository für diese Zwecke - es wird mit dem Git-Repository synchronisiert. Sobald der Entwickler die Änderungen in der entsprechenden Zweigstelle unseres Repositorys veröffentlicht, sendet GitLab diese Änderungen sofort an den Kunden.



Danach müssen Sie eine Baugruppe erstellen. Es besteht aus mehreren Schritten: Zusammenbau des Backends und des Frontends, Testen und Lieferung an das Produkt.

3. Erstellen Sie das Backend und das Frontend


Backend- und Frontend-Assembly sind zwei parallele Aufgaben, die im GitLab Runner-System ausgeführt werden. Ihre Konfiguration der ursprünglichen Baugruppe befindet sich im selben Repository.

Tutorial zum Schreiben eines YAML-Skripts zum Erstellen in GitLab .

GitLab Runner nimmt den Code aus dem gewünschten Repository auf, sammelt den Befehl zum Erstellen von Java-Anwendungen und sendet ihn an die Docker-Registrierung. Hier sammeln wir das Backend und das Frontend, erhalten Docker-Images, die wir auf Kundenseite in das Repository stellen. Verwenden Sie das Gradle-Plugin, um Doker-Bilder zu verwalten.

Wir synchronisieren die Versionen unserer Bilder mit der Version der Version, die in Docker veröffentlicht wird. Für einen reibungslosen Betrieb haben wir verschiedene Einstellungen vorgenommen:

1. Zwischen Testumgebung und Lebensmittelbehältern werden keine wieder zusammengesetzt. Wir haben die Parametrisierung durchgeführt, damit derselbe Container ohne Neuerstellung mit allen Einstellungen, Umgebungsvariablen und Diensten sowohl in der Testumgebung als auch im Produkt funktioniert.

2. Um die Anwendung über Helm zu aktualisieren, müssen Sie ihre Version angeben. Wir haben die Backend-Assembly, das Frontend und das Anwendungsupdate - dies sind drei verschiedene Aufgaben, daher ist es wichtig, überall dieselbe Version der Anwendung zu verwenden. Für diese Aufgabe verwenden wir Daten aus dem Git-Verlauf, da wir eine K8S-Cluster-Konfiguration haben und sich Anwendungen im selben Git-Repository befinden.

Wir erhalten die Anwendungsversion aus den Ergebnissen des Befehls
git describe --tags --abbrev=7 .

4. Automatische Bereitstellung aller Änderungen in einer Testumgebung (UAT)


Der nächste Schritt in diesem Build-Skript besteht darin, den K8S-Cluster automatisch zu aktualisieren. Dies geschieht, sofern die gesamte Anwendung zusammengestellt und alle Artefakte in der Docker-Registrierung veröffentlicht werden. Danach beginnt die Aktualisierung der Testumgebung.

Das Cluster-Update wird mit Helm Update gestartet. Wenn infolgedessen ein Fehler aufgetreten ist, setzt Helm alle Änderungen automatisch und unabhängig zurück. Seine Arbeit muss nicht kontrolliert werden.

Zusammen mit der Baugruppe liefern wir die Konfiguration des K8S-Clusters. Daher besteht der nächste Schritt darin, es zu aktualisieren: configMaps, Bereitstellungen, Dienste, Geheimnisse und alle anderen von uns geänderten K8S-Konfigurationen.

Danach startet Helm das RollOut-Update der Anwendung selbst in einer Testumgebung. Bevor die Anwendung auf dem Produkt bereitgestellt wird. Dies geschieht, damit Benutzer die Geschäftsfunktionen, die wir in der Testumgebung veröffentlicht haben, manuell überprüfen können.

5. Stellen Sie alle Änderungen automatisch an Prod bereit


Um das Update in der Produktumgebung bereitzustellen, müssen Sie nur noch auf eine Schaltfläche in GitLab klicken - und die Container werden sofort an die Produktumgebung geliefert.

Ein und dieselbe Anwendung kann ohne Neuerstellung in verschiedenen Umgebungen funktionieren - Test und Produktion. Wir verwenden dieselben Artefakte, ohne etwas in der Anwendung zu ändern, und stellen die Parameter von außen ein.

Die flexible Parametrisierung der Anwendungseinstellungen hängt von der Umgebung ab, in der diese Anwendung ausgeführt wird. Wir haben alle Umgebungseinstellungen vorgenommen: Alles wird über die K8S-Konfiguration und die Helm-Parameter parametriert. Wenn Helm eine Baugruppe in einer Testumgebung bereitstellt, gelten Testparameter und Produktparameter für die Produktumgebung.

Am schwierigsten war es, alle verwendeten Dienste und Variablen, die von der Umgebung abhängen, zu parametrisieren und in Umgebungsvariablen und eine Beschreibungskonfiguration der Umgebungsparameter für Helm zu übersetzen.

Die Anwendungsparameter verwenden Umgebungsvariablen. Ihre Werte werden in Containern mithilfe der K8S-Konfigurationskarte festgelegt, die mithilfe von Go-Vorlagen erstellt wird. Das Festlegen einer Umgebungsvariablen auf einen Domänennamen kann beispielsweise folgendermaßen erfolgen:

 APP_EXTERNAL_DOMAIN: {{ (pluck .Values.global.env .Values.app.properties.app_external_domain | first) }} 

.Values.global.env - Der Name der Umgebung (Prod, Stage, UAT) wird in dieser Variablen gespeichert.
.Values.app.properties.app_external_domain - In dieser Variablen legen wir in der Datei .Values.yaml die gewünschte Domäne fest

Beim Aktualisieren der Anwendung erstellt Helm die Datei configmap.yaml aus den Vorlagen und füllt den Wert APP_EXTERNAL_DOMAIN mit dem erforderlichen Wert aus, abhängig von der Umgebung, in der die Anwendungsaktualisierung beginnt. Diese Variable ist bereits im Container festgelegt. Der Zugriff darauf erfolgt über die Anwendung. In jeder Umgebung der Anwendung gibt es einen anderen Wert für diese Variable.

Vor relativ kurzer Zeit hat Spring Cloud die K8S-Unterstützung eingeführt, einschließlich der Arbeit mit configMaps: Spring Cloud Kubernetes . Während sich das Projekt aktiv entwickelt und dramatisch verändert, können wir es nicht in der Produktion verwenden. Wir überwachen jedoch aktiv den Zustand und verwenden ihn in DEV-Konfigurationen. Sobald es sich stabilisiert hat, werden wir von der Verwendung von Umgebungsvariablen zu dieser wechseln.

Insgesamt


Continuous Deployment ist also betriebsbereit. Alle Aktualisierungen erfolgen auf Knopfdruck. Die Übermittlung von Änderungen an die Lebensmittelumgebung erfolgt automatisch. Und vor allem stoppen Updates das System nicht.



Zukunftspläne: automatische Basismigration


Wir haben darüber nachgedacht, die Datenbank zu aktualisieren und diese Änderungen rückgängig zu machen. Immerhin funktionieren zwei verschiedene Versionen der Anwendung gleichzeitig: die alte funktioniert und die neue steigt. Und wir werden die alte nur ausschalten, wenn wir davon überzeugt sind, dass die neue Version funktioniert. Die Datenbankmigration sollte die Arbeit mit beiden Versionen der Anwendung ermöglichen.

Daher können wir nicht einfach den Namen der Spalte oder anderer Daten ändern. Wir können jedoch eine neue Spalte erstellen, die Daten aus der alten Spalte in diese Spalte kopieren und Trigger schreiben, die beim Aktualisieren der Daten gleichzeitig kopiert und in einer anderen Spalte aktualisiert werden. Und nach der erfolgreichen Bereitstellung der neuen Version der Anwendung können wir nach der Unterstützung nach dem Start die alte Spalte und den nicht mehr benötigten Auslöser löschen.

Wenn die neue Version der Anwendung nicht ordnungsgemäß funktioniert, können wir auf die vorherige Version zurücksetzen, einschließlich der vorherigen Version der Datenbank. Mit einem Wort, unsere Änderungen ermöglichen die gleichzeitige Arbeit mit mehreren Versionen der Anwendung.

Wir planen, die Datenbankmigration durch den K8S-Job zu automatisieren, indem wir ihn in den CD-Prozess einbetten. Und diese Erfahrung werden wir sicherlich auf Habré teilen.

Source: https://habr.com/ru/post/de447812/


All Articles