Zusammenstellung und Bereitstellung derselben Microservices mit werf und GitLab CI



Vor zwei Jahren haben wir den Artikel " Erstellen von Projekten mit GitLab CI: eine .gitlab-ci.yml für Hunderte von Anwendungen " veröffentlicht. Jetzt werden wir über die Lösung eines ähnlichen Problems sprechen. In .gitlab-ci.yml Material geht es darum, wie Sie CI / CD-Prozesse für eine große Anzahl ähnlicher Anwendungen mit dem Aufkommen von include in .gitlab-ci.yml und dem Aufkommen von werf als Ersatz für dapp erstellen können.

Einführung


In den weiteren Anweisungen im Artikel wird die folgende Situation berücksichtigt:

  • Es gibt eine große Client-Anwendung, die in viele Repositorys unterteilt ist.
  • Jedes Repository ist eine separate Anwendung, die in einem Kubernetes-Cluster ausgeführt werden muss.
  • Als CI-System wird GitLab CI verwendet.
  • Die Bereitstellung (die Infrastruktur, in der der Code bereitgestellt wird) wird in Helmdiagrammen beschrieben.
  • Erstellen Sie Images und stellen Sie sie mit werf in Kubernetes bereit .

Der Einfachheit und Bequemlichkeit halber (und als Hommage an die Mode) werden wir diese Anwendungen weiterhin als Microservices bezeichnen. Alle diese Mikrodienste werden auf dieselbe Weise zusammengestellt, bereitgestellt und gestartet , und bestimmte Einstellungen werden mithilfe von Umgebungsvariablen konfiguriert.

Das Kopieren von .gitlab-ci.yml , werf.yaml und .helm bringt .helm viele Probleme mit sich. Schließlich sollte jede Bearbeitung in CI, der Assemblierungsprozess oder die Beschreibung des Helm-Diagramms zu anderen Repositorys hinzugefügt werden ...

Vorlagen in .gitlab-ci.yml verbinden


Mit dem Aufkommen der include:file Direktive in GitLab CE ( seit Version 11.7 ) wurde es möglich, ein gemeinsames CI zu erstellen. include selbst erschien etwas früher (in 11.4), erlaubte jedoch das Verbinden von Vorlagen nur über öffentliche URLs, was seine Funktionalität etwas einschränkte. Die GitLab-Dokumentation beschreibt alle Funktionen und Verwendungsbeispiele perfekt .

Somit war es möglich, das Kopieren von .gitlab-ci.yml zwischen Repositories zu verweigern und dessen Relevanz zu unterstützen. Hier ist ein Beispiel .gitlab-ci.yml mit include :

 include: - project: 'infra/gitlab-ci' ref: 1.0.0 file: base-gitlab-ci.yaml - project: 'infra/gitlab-ci' ref: 1.0.0 file: cleanup.yaml 

Wir empfehlen dringend, Zweigstellennamen in ref mit Vorsicht zu verwenden . Einschlüsse werden zum Zeitpunkt der Erstellung der Pipeline berechnet, sodass Ihre CI-Änderungen möglicherweise zum ungünstigsten Zeitpunkt automatisch in die Produktionspipeline fallen. Die Verwendung von Tags in ref erleichtert jedoch die Versionierung der Beschreibung von CI / CD-Prozessen. Beim Aktualisieren sieht alles so transparent wie möglich aus und Sie können den Verlauf von Änderungen in Pipeline-Versionen leicht verfolgen, wenn Sie die semantische Versionierung für Tags verwenden.

Verbinden Sie .helm von einem separaten Repository aus


Da diese Microservices auf dieselbe Weise bereitgestellt und ausgeführt werden, ist derselbe Satz von Helmvorlagen erforderlich. Um zu vermeiden, dass das .helm Verzeichnis zwischen Repositorys kopiert wird, haben wir das Repository .helm , in dem Helm-Vorlagen gespeichert und auf dem gewünschten Tag überprüft wurden. Es sah ungefähr so ​​aus:

  - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.example.com/infra/helm.git .helm - cd .helm && git checkout tags/1.0.0 - type multiwerf && source <(multiwerf use 1.0 beta) - type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose) - werf deploy --stages-storage :local 

Es gab auch Variationen mit Git-Submodulen, aber alles scheint eher eine Problemumgehung zu sein ...

Und jetzt, mit der jüngsten werf-Veröffentlichung, hat er die Möglichkeit, Diagramme aus externen Repositories zu verbinden. Die vollständige Unterstützung der Funktionen des Paketmanagers ermöglichte es wiederum, die Abhängigkeiten für die Bereitstellung der Anwendung transparent zu beschreiben.

Reihenfolge der Aktionen


Kommen wir zurück zur Lösung unseres Problems mit Microservices. Lassen Sie uns unser Repository zum Speichern von Helm-Diagrammen erweitern - zum Beispiel ChartMuseum . Es kann problemlos in einem Kubernetes-Cluster bereitgestellt werden:

 helm repo add stable https://kubernetes-charts.storage.googleapis.com helm install stable/chartmuseum --name flant-chartmuseum 

Ingress hinzufügen:

 apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/force-ssl-redirect: "false" nginx.ingress.kubernetes.io/proxy-body-size: 10m nginx.ingress.kubernetes.io/ssl-redirect: "false" name: chart-museum spec: rules: - host: flant-chartmuseum.example.net http: paths: - backend: serviceName: flant-chartmuseum servicePort: 8080 path: / status: loadBalancer: {} 

Das flant-chartmuseum für die flant-chartmuseum muss die Umgebungsvariable DISABLE_API in false ändern. Andernfalls (standardmäßig) funktionieren die ChartMuseum-API-Anforderungen nicht und es ist nicht möglich, neue Diagramme zu erstellen.

Nun beschreiben wir das Repository, in dem die gemeinsam genutzten Helmdiagramme gespeichert werden. Die Struktur der Verzeichnisse ist wie folgt:

 . ├── charts │ └── yii2-microservice │ ├── Chart.yaml │ └── templates │ ├── app.yaml └── README.md 

Chart.yaml könnte folgendermaßen aussehen:

 name: yii2-microservice version: 1.0.4 

Das templates sollte alle erforderlichen Kubernetes-Grundelemente enthalten, die zum Bereitstellen der Anwendung im Cluster erforderlich sind. Wie Sie vielleicht bereits vermutet haben, ist der Microservice in diesem Fall eine PHP-Anwendung, die auf dem yii2-Framework basiert. Beschreiben wir die minimale Bereitstellung mit zwei nginx- und php-fpm-Containern, die mit werf erstellt wurden:

 --- apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Values.global.werf.name }} spec: replicas: 1 revisionHistoryLimit: 3 template: metadata: labels: service: {{ .Values.global.werf.name }} spec: imagePullSecrets: - name: registrysecret containers: - name: backend {{ tuple "backend" . | include "werf_container_image" | indent 8 }} command: [ '/usr/sbin/php-fpm7', "-F" ] ports: - containerPort: 9000 protocol: TCP name: http env: {{ tuple "backend" . | include "werf_container_env" | indent 8 }} - name: frontend command: ['/usr/sbin/nginx'] {{ tuple "frontend" . | include "werf_container_image" | indent 8 }} ports: - containerPort: 80 name: http lifecycle: preStop: exec: command: ["/usr/sbin/nginx", "-s", "quit"] env: {{ tuple "frontend" . | include "werf_container_env" | indent 8 }} --- apiVersion: v1 kind: Service metadata: name: {{ .Values.global.werf.name }} spec: selector: service: {{ .Values.global.werf.name }} ports: - name: http port: 80 protocol: TCP 

Die Variable .Values.global.werf.name enthält den Namen des Projekts aus der werf.yaml Datei, mit der Sie die erforderlichen Namen von Diensten und Bereitstellungen werf.yaml können.

Lassen Sie uns die einfachste Automatisierung für Push im ChartMuseum unserer Diagramme vornehmen, wenn Sie sich für den Hauptzweig festlegen. Dazu beschreiben wir .gitlab-ci.yml :

 Build and push to chartmuseum: script: - for i in $(ls charts); do helm package "charts/$i"; done; - for i in $(find . -type f -name "*.tgz" -printf "%f\n"); do curl --data-binary "@$i" http://flant-chartmuseum.example.net/api/charts; done; stage: build environment: name: infra only: - master tags: - my-shell-runner-tag 

Chart.yaml werden versioniert, indem die version in Chart.yaml . Alle neuen Diagramme werden automatisch zum ChartMuseum hinzugefügt.

Wir gehen bis zur Ziellinie! Im Projekt-Repository in .helm/requirements.yaml schreiben .helm/requirements.yaml die Abhängigkeiten für das Diagramm:

 dependencies: - name: yii2-microservice version: "1.0.4" repository: "@flant" 

... und im Verzeichnis mit dem Repository ausführen:

 werf helm repo init werf helm repo add flant http://flant-chartmuseum.example.net werf helm dependency update 

Wir .helm/requirements.lock drin .helm/requirements.lock . werf helm dependency build die Anwendung im Cluster werf helm dependency build , reicht es aus, den werf helm dependency build bevor werf deploy .

Um die Beschreibung der Bereitstellung der Anwendung zu aktualisieren, müssen Sie jetzt die Repositorys mit Microservices durchsuchen und kleine Patches mit Änderungen an den Hashes und Tags in den requirements.yaml und den requirements.lock anwenden. Auf Wunsch kann dieser Vorgang auch über CI automatisiert werden: Wie dies beschrieben wird, haben wir bereits im genannten Artikel beschrieben .

Fazit


Ich hoffe, dass die beschriebene Abfolge von Maßnahmen zur Wartung ähnlicher Anwendungen für Ingenieure mit ähnlichen Problemen hilfreich ist. Gerne teilen wir Ihnen auch weitere praktische Rezepte für die Verwendung von werf mit . Wenn Sie Schwierigkeiten haben, deren Implementierung unüberwindbar oder einfach unverständlich erscheint, können Sie sich daher gerne an Telegram wenden oder hier in den Kommentaren Anfragen für zukünftige Materialien hinterlassen.

PS


Lesen Sie auch in unserem Blog:

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


All Articles