Dynamische Assemblierung und Bereitstellung von Docker-Images mit werf anhand der Beispielsite der versionierten Dokumentation

Wir haben bereits mehr als einmal über unser werf GitOps-Tool gesprochen, aber dieses Mal möchten wir die Erfahrung beim Erstellen der Site mit der Projektdokumentation - werf.io (die russische Version ist ru.werf.io ) teilen . Dies ist eine reguläre statische Site, aber ihre Assembly ist interessant, da sie mit einer dynamischen Anzahl von Artefakten erstellt wird.



Gehen Sie auf die Feinheiten der Site-Struktur ein: Generieren eines allgemeinen Menüs für alle Versionen, Seiten mit Informationen zu Releases usw. - werden wir nicht. Stattdessen konzentrieren wir uns auf Probleme und Funktionen der dynamischen Assembly und ein wenig auf die begleitenden CI / CD-Prozesse.

Einführung: Wie ist die Site aufgebaut?


Zu Beginn wird die werf-Dokumentation zusammen mit ihrem Code gespeichert. Dies stellt bestimmte Entwicklungsanforderungen, die im Allgemeinen über den Rahmen dieses Artikels hinausgehen, aber zumindest können wir Folgendes sagen:

  • Neue werf-Funktionen sollten nicht ohne Aktualisierung der Dokumentation freigegeben werden. Umgekehrt implizieren Änderungen in der Dokumentation die Freigabe einer neuen werf-Version.
  • Das Projekt hat eine ziemlich intensive Entwicklung: neue Versionen können mehrmals am Tag erscheinen;
  • Die manuelle Bereitstellung einer Site mit einer neuen Version der Dokumentation ist zumindest mühsam.
  • Das Projekt verfolgte den Ansatz der semantischen Versionierung mit 5 Stabilitätskanälen. Der Freisetzungsprozess beinhaltet den sequentiellen Durchlauf von Versionen durch die Kanäle, um die Stabilität zu erhöhen: von Alpha zu Rock-Solid;
  • Die Site verfügt über eine russischsprachige Version, die parallel zur Hauptversion (dh der englischen Version) "lebt und sich entwickelt" (dh deren Inhalt aktualisiert wird).

Um dem Benutzer diese „innere Küche“ vorenthalten zu können und ihm etwas anzubieten, das „einfach funktioniert“, haben wir ein separates werf-Installations- und Aktualisierungstool erstellt - das ist multiwerf . Es reicht aus, die Release-Nummer und den Stabilitätskanal anzugeben, den Sie verwenden möchten. Multiwerf prüft, ob eine neue Version auf dem Kanal vorhanden ist, und lädt sie gegebenenfalls herunter.

Die neueste Version von werf in jedem Kanal ist im Versionsauswahlmenü auf der Site verfügbar. Standardmäßig wird die Version des stabilsten Kanals für die neueste Version unter werf.io/documentation geöffnet. Sie wird auch von Suchmaschinen indiziert. Die Dokumentation für den Channel ist unter einzelnen Adressen verfügbar (z. B. werf.io/v1.0-beta/documentation für Beta-Release 1.0).

Insgesamt hat die Website die folgenden Versionen:

  1. root (wird standardmäßig geöffnet)
  2. für jeden aktiven Update-Kanal jeder Version (z. B. werf.io/v1.0-beta ).

Um im allgemeinen Fall eine bestimmte Version einer Site zu generieren, genügt es, sie mit Jekyll- Tools zu kompilieren, indem Sie den entsprechenden Befehl ( jekyll build ) im Verzeichnis /docs des Werf-Repositorys ausführen, nachdem Sie zum Git-Tag der erforderlichen Version gewechselt haben.

Es bleibt nur hinzuzufügen, dass:

  • Das Dienstprogramm selbst (werf) wird für die Montage verwendet.
  • CI / CD-Prozesse basieren auf GitLab CI;
  • und das alles funktioniert natürlich in Kubernetes.

Die Aufgaben


Nun formulieren wir Aufgaben, die alle beschriebenen Besonderheiten berücksichtigen:

  1. Nach dem Ändern der werf-Version in einem Update-Kanal sollte die Dokumentation auf der Site automatisch aktualisiert werden .
  2. Für die Entwicklung müssen Sie gelegentlich vorläufige Versionen der Site anzeigen können .

Die erneute Kompilierung der Site muss durchgeführt werden, nachdem die Version auf einem Kanal von den entsprechenden Git-Tags geändert wurde. Beim Erstellen des Images werden jedoch die folgenden Funktionen bereitgestellt:

  • Da sich die Liste der Versionen in den Kanälen ändert, muss die Dokumentation nur für die Kanäle neu zusammengestellt werden, in denen sich die Version geändert hat. Immerhin ist es nicht sehr schön, alles wieder zusammenzusetzen.
  • Die Anzahl der Kanäle für Veröffentlichungen kann variieren. Zu einem bestimmten Zeitpunkt ist die Version auf den Channels möglicherweise nicht stabiler als die Version 1.1 für den frühen Zugriff. Mit der Zeit werden sie jedoch angezeigt. Ändern Sie in diesem Fall die Assembly nicht manuell.

Es stellt sich heraus, dass die Assembly von der Änderung externer Daten abhängt .

Implementierung


Wahl des Ansatzes


Alternativ können Sie jede erforderliche Version mit einem separaten Pod in Kubernetes ausführen. Diese Option impliziert eine größere Anzahl von Objekten im Cluster, die mit zunehmender Anzahl stabiler werf-Releases zunehmen wird. Dies wiederum impliziert einen komplexeren Service: Jede Version hat einen eigenen HTTP-Server und eine geringe Auslastung. Dies ist natürlich mit höheren Kosten für Ressourcen verbunden.

Wir sind den Weg gegangen, alle notwendigen Versionen in einem Image zusammenzufassen . Die kompilierte Statistik aller Versionen der Site befindet sich in einem Container mit NGINX, und der Datenverkehr zur entsprechenden Bereitstellung erfolgt über NGINX Ingress. Eine einfache Struktur - eine zustandslose Anwendung - erleichtert die Skalierung der Bereitstellung (abhängig von der Auslastung) mithilfe von Kubernetes.

Genauer gesagt, wir sammeln zwei Bilder: eines für die Produktionsschaltung, das andere für die Entwicklungsschaltung. Ein zusätzliches Image wird nur auf dem Entwicklungs-Circuit zusammen mit dem Haupt-Image verwendet (gestartet) und enthält die Site-Version aus dem Überprüfungs-Commit. Das Routing zwischen diesen Images wird mithilfe von Ingress-Ressourcen durchgeführt.

werf vs git Klon und Artefakte


Wie bereits erwähnt, müssen Sie zum Generieren von Websitestatiken für eine bestimmte Version der Dokumentation auf das entsprechende Repository-Tag wechseln. Sie können dies auch tun, indem Sie das Repository jedes Mal während der Assembly klonen und die entsprechenden Tags aus der Liste auswählen. Dies ist jedoch ein ziemlich ressourcenintensiver Vorgang und erfordert darüber hinaus das Schreiben von nicht trivialen Anweisungen ... Ein weiteres schwerwiegendes Minus - bei diesem Ansatz ist es nicht möglich, während der Montage etwas zwischenzuspeichern.

Hier hilft uns das Dienstprogramm werf, das Smart Caching implementiert und die Verwendung externer Repositorys ermöglicht . Die Verwendung von werf zum Hinzufügen von Code aus dem Repository beschleunigt den Build erheblich werf klont das Repository im Wesentlichen einmal und fetch dann nur bei Bedarf. Außerdem können wir beim Hinzufügen von Daten aus dem Repository nur die erforderlichen Verzeichnisse auswählen (in unserem Fall ist dies das Verzeichnis docs ), wodurch sich die Menge der hinzugefügten Daten erheblich verringert.

Da Jekyll ein Werkzeug zum Kompilieren von Statiken ist und im endgültigen Bild nicht benötigt wird, wäre es logisch, das werf-Artefakt zu kompilieren und nur das Kompilierungsergebnis in das endgültige Bild zu importieren .

Schreiben werf.yaml


Deshalb haben wir beschlossen, jede Version in einem eigenen Werf-Artefakt zu kompilieren. Wir wissen jedoch nicht, wie viele dieser Artefakte während der Montage vorhanden sein werden , daher können wir keine feste Montagekonfiguration schreiben (genau genommen können wir das immer noch, aber es wird nicht vollständig effektiv sein).

Mit werf können Sie Go-Templates in Ihrer Konfigurationsdatei ( werf.yaml ) verwenden. Auf diese Weise können Sie eine Konfiguration "on the fly" in Abhängigkeit von externen Daten erstellen (was Sie benötigen!). Bei externen Daten handelt es sich in unserem Fall um Informationen zu Versionen und Releases, auf deren Grundlage wir die erforderliche Anzahl von Artefakten sammeln und als Ergebnis zwei Bilder erhalten: werf-doc und werf-dev , die auf unterschiedlichen Pfaden ausgeführt werden.

Externe Daten werden über Umgebungsvariablen übergeben. Hier ist ihre Zusammensetzung:

  • RELEASES - eine Zeile mit einer Liste von Releases und der entsprechenden aktuellen Version von werf in Form einer durch ein Leerzeichen getrennten Liste im Format <_>%<_> . Beispiel: 1.0%v1.0.4-beta.20
  • CHANNELS - eine Zeile mit einer Liste von Kanälen und der entsprechenden aktuellen Version von werf in Form einer Liste mit einem Leerzeichen von Werten im Format <>%<_> . Beispiel: 1.0-beta%v1.0.4-beta.20 1.0-alpha%v1.0.5-alpha.22
  • ROOT_VERSION - Die Version der werf-Version, die standardmäßig auf der Site angezeigt wird (es ist nicht immer erforderlich, die Dokumentation für die höchste Versionsnummer anzuzeigen). Beispiel: v1.0.4-beta.20
  • REVIEW_SHA - Hash des Überprüfungs-Commits, aus dem Sie die Version für die REVIEW_SHA müssen.

Diese Variablen werden in der GitLab-CI-Pipeline eingetragen und wie genau dies nachfolgend beschrieben wird.

Zunächst definieren wir der werf.yaml Go-Template-Variablen in werf.yaml indem wir ihnen Werte aus Umgebungsvariablen werf.yaml :

 {{ $_ := set . "WerfVersions" (cat (env "CHANNELS") (env "RELEASES") | splitList " ") }} {{ $Root := . }} {{ $_ := set . "WerfRootVersion" (env "ROOT_VERSION") }} {{ $_ := set . "WerfReviewCommit" (env "REVIEW_SHA") }} 

Die Beschreibung des Artefakts zum Kompilieren der Statik der Site-Version ist im Allgemeinen für alle Fälle gleich (einschließlich der Generierung der Root-Version sowie der Version für die Dev-Schaltung). Daher platzieren wir es mit der Funktion define in einem separaten Block - für die spätere Wiederverwendung mit include . Wir werden die folgenden Argumente an die Vorlage übergeben:

  • Version - generierte Version (Tagname);
  • Channel - Der Name des Aktualisierungskanals, für den das Artefakt generiert wird.
  • Commit - Commit-Hash, wenn ein Artefakt für das Review-Commit generiert wird.
  • Kontext.

Beschreibung der Artefaktvorlage
 {{- define "doc_artifact" -}} {{- $Root := index . "Root" -}} artifact: doc-{{ .Channel }} from: jekyll/builder:3 mount: - from: build_dir to: /usr/local/bundle ansible: install: - shell: | export PATH=/usr/jekyll/bin/:$PATH - name: "Install Dependencies" shell: bundle install args: executable: /bin/bash chdir: /app/docs beforeSetup: {{- if .Commit }} - shell: echo "Review SHA - {{ .Commit }}." {{- end }} {{- if eq .Channel "root" }} - name: "releases.yml HASH: {{ $Root.Files.Get "releases.yml" | sha256sum }}" copy: content: | {{ $Root.Files.Get "releases.yml" | indent 8 }} dest: /app/docs/_data/releases.yml {{- else }} - file: path: /app/docs/_data/releases.yml state: touch {{- end }} - file: path: "{{`{{ item }}`}}" state: directory mode: 0777 with_items: - /app/main_site/ - /app/ru_site/ - file: dest: /app/docs/pages_ru/cli state: link src: /app/docs/pages/cli - shell: | echo -e "werfVersion: {{ .Version }}\nwerfChannel: {{ .Channel }}" > /tmp/_config_additional.yml export PATH=/usr/jekyll/bin/:$PATH {{- if and (ne .Version "review") (ne .Channel "root") }} {{- $_ := set . "BaseURL" ( printf "v%s" .Channel ) }} {{- else if ne .Channel "root" }} {{- $_ := set . "BaseURL" .Channel }} {{- end }} jekyll build -s /app/docs -d /app/_main_site/{{ if .BaseURL }} --baseurl /{{ .BaseURL }}{{ end }} --config /app/docs/_config.yml,/tmp/_config_additional.yml jekyll build -s /app/docs -d /app/_ru_site/{{ if .BaseURL }} --baseurl /{{ .BaseURL }}{{ end }} --config /app/docs/_config.yml,/app/docs/_config_ru.yml,/tmp/_config_additional.yml args: executable: /bin/bash chdir: /app/docs git: - url: https://github.com/flant/werf.git to: /app/ owner: jekyll group: jekyll {{- if .Commit }} commit: {{ .Commit }} {{- else }} tag: {{ .Version }} {{- end }} stageDependencies: install: ['docs/Gemfile','docs/Gemfile.lock'] beforeSetup: '**/*' includePaths: 'docs' excludePaths: '**/*.sh' {{- end }} 

Der Name des Artefakts muss eindeutig sein. Dies können wir beispielsweise erreichen, indem wir den Namen des Kanals (Wert der Variablen .Channel ) als Suffix für den Namen des Artefakts artifact: doc-{{ .Channel }} : artifact: doc-{{ .Channel }} . Sie müssen jedoch wissen, dass Sie beim Importieren aus Artefakten auf dieselben Namen verweisen müssen.

Bei der Beschreibung eines Artefakts wird ein werf-Feature wie mount verwendet . Durch das Mounten mit dem build_dir können Sie den Jekyll-Cache zwischen den Pipeline-Starts speichern, was die build_dir erheblich beschleunigt .

Möglicherweise haben Sie auch die Verwendung der Datei releases.yml bemerkt - dies ist die YAML-Datei mit den von github.com angeforderten Versionsdaten (das durch Ausführen der Pipeline erhaltene Artefakt). Es wird beim Kompilieren der Site benötigt, aber im Kontext des Artikels interessiert uns die Tatsache, dass nur ein Artefakt , das Root- Artefakt der Site-Version , von seinem Status abhängt (in anderen Artefakten wird es nicht benötigt).

Dies wird mithilfe des bedingten Operators für if Vorlagen und der {{ $Root.Files.Get "releases.yml" | sha256sum }} {{ $Root.Files.Get "releases.yml" | sha256sum }} auf der Bühne . Dies funktioniert folgendermaßen: Wenn Sie ein Artefakt für die Stammversion zusammenstellen (die Variable .Channel ist root ), wirkt sich der Hash der Datei releases.yml auf die Signatur der gesamten Phase aus, da er Bestandteil des Namens des Ansible-Jobs ist (Parameter name ). Wenn Sie also den Inhalt der Datei releases.yml ändern, wird das entsprechende Artefakt neu erstellt.

Achten Sie auch auf die Arbeit mit einem externen Repository. Nur das Verzeichnis /docs wird dem Image des Artefakts aus dem Werf-Repository hinzugefügt. Abhängig von den übergebenen Parametern werden die Daten des erforderlichen Tags oder des erforderlichen Überprüfungs-Commits sofort hinzugefügt.

Um mithilfe der Artefaktvorlage eine Artefaktbeschreibung der übertragenen Versionen von Channels und Releases zu generieren, organisieren wir eine Schleife für die Variable .WerfVersions in werf.yaml :

 {{ range .WerfVersions -}} {{ $VersionsDict := splitn "%" 2 . -}} {{ dict "Version" $VersionsDict._1 "Channel" $VersionsDict._0 "Root" $Root | include "doc_artifact" }} --- {{ end -}} 

Weil Die Schleife erzeugt mehrere Artefakte (wir hoffen es). Es ist notwendig, das Trennzeichen zwischen ihnen zu berücksichtigen - die Reihenfolge --- (weitere Informationen zur Syntax der Konfigurationsdatei finden Sie in der Dokumentation ). Wie zuvor festgelegt, übergeben wir beim Aufrufen der Vorlage in einer Schleife die Versionsparameter, die URL und den Stammkontext.

Ähnlich, aber bereits ohne Schleife, rufen wir die Artefaktvorlage für "Sonderfälle" auf: für die Root-Version sowie für die Version aus dem Review-Commit:

 {{ dict "Version" .WerfRootVersion "Channel" "root" "Root" $Root | include "doc_artifact" }} --- {{- if .WerfReviewCommit }} {{ dict "Version" "review" "Channel" "review" "Commit" .WerfReviewCommit "Root" $Root | include "doc_artifact" }} {{- end }} 

Beachten Sie, dass das Artefakt für das Überprüfungs-Commit nur erfasst wird, wenn die Variable .WerfReviewCommit ist.

Artefakte sind fertig - es ist Zeit zu importieren!

Das endgültige Image, das für die Ausführung in Kubernetes entwickelt wurde, ist ein reguläres NGINX-Image, in dem die nginx.conf und nginx.conf von Artefakten hinzugefügt werden. Zusätzlich zum Artefakt der Root-Version der Site müssen wir die Schleife für die Variable .WerfVersions wiederholen, um Artefakte der Versionen von Channels und Releases zu importieren. + .WerfVersions die zuvor angenommene Benennungsregel für Artefakte. Da jedes Artefakt Versionen der Site für zwei Sprachen speichert, importieren wir sie an den in der Konfiguration angegebenen Stellen.

Beschreibung des endgültigen werf-doc-Image
 image: werf-doc from: nginx:stable-alpine ansible: setup: - name: "Setup /etc/nginx/nginx.conf" copy: content: | {{ .Files.Get ".werf/nginx.conf" | indent 8 }} dest: /etc/nginx/nginx.conf - file: path: "{{`{{ item }}`}}" state: directory mode: 0777 with_items: - /app/main_site/assets - /app/ru_site/assets import: - artifact: doc-root add: /app/_main_site to: /app/main_site before: setup - artifact: doc-root add: /app/_ru_site to: /app/ru_site before: setup {{ range .WerfVersions -}} {{ $VersionsDict := splitn "%" 2 . -}} {{ $Channel := $VersionsDict._0 -}} {{ $Version := $VersionsDict._1 -}} - artifact: doc-{{ $Channel }} add: /app/_main_site to: /app/main_site/v{{ $Channel }} before: setup {{ end -}} {{ range .WerfVersions -}} {{ $VersionsDict := splitn "%" 2 . -}} {{ $Channel := $VersionsDict._0 -}} {{ $Version := $VersionsDict._1 -}} - artifact: doc-{{ $Channel }} add: /app/_ru_site to: /app/ru_site/v{{ $Channel }} before: setup {{ end -}} 

Das zusätzliche Image, das zusammen mit dem Hauptimage auf der Entwickler-Schaltung gestartet wird, enthält nur zwei Versionen der Site: die Version aus dem Review-Commit und die Root-Version der Site (es gibt allgemeine Assets und, wenn Sie sich erinnern, Release-Daten). Daher unterscheidet sich das zusätzliche Bild vom Hauptbild nur im Importbereich (und natürlich im Namen):

 image: werf-dev ... import: - artifact: doc-root add: /app/_main_site to: /app/main_site before: setup - artifact: doc-root add: /app/_ru_site to: /app/ru_site before: setup {{- if .WerfReviewCommit }} - artifact: doc-review add: /app/_main_site to: /app/main_site/review before: setup - artifact: doc-review add: /app/_ru_site to: /app/ru_site/review before: setup {{- end }} 

Wie bereits oben erwähnt, wird das Artefakt für das Überprüfungs-Commit nur generiert, wenn werf mit der Umgebungsvariablen REVIEW_SHA startet. Es wäre möglich, überhaupt kein werf-dev-Image zu generieren, wenn es keine REVIEW_SHA Umgebungsvariable gibt. Damit jedoch die werf-dev- basierte Bereinigung von Richtlinien für Docker-Images für das werf-dev-Image funktioniert, lassen wir es nur mit dem Artefakt der Root-Version (wie auch immer) sammeln bereits montiert), um den Aufbau der Pipeline zu vereinfachen.

Die Montage ist fertig! Wir gehen zu CI / CD und wichtigen Nuancen über.

Pipeline in GitLab CI und Funktionen der dynamischen Assemblierung


Beim Starten der Assembly müssen die in werf.yaml verwendeten Umgebungsvariablen werf.yaml . Dies gilt nicht für die Variable REVIEW_SHA, die wir festlegen, wenn die Pipeline vom GitHub-Hook aufgerufen wird.

Wir werden die erforderlichen externen Daten im Bash-Skript generate_artifacts generate_artifacts , das zwei GitLab-Pipeline-Artefakte generiert:

  • Datei releases.yml mit Versionsdaten,
  • Datei common_envs.sh mit Umgebungsvariablen für den Export.

Den Inhalt der Datei generate_artifacts in unserem Beispielrepository . Das Erhalten von Daten ist nicht Gegenstand des Artikels, aber die Datei common_envs.sh ist wichtig für uns, weil die arbeit von werf hängt davon ab. Ein Beispiel für seinen Inhalt:

 export RELEASES='1.0%v1.0.6-4' export CHANNELS='1.0-alpha%v1.0.7-1 1.0-beta%v1.0.7-1 1.0-ea%v1.0.6-4 1.0-stable%v1.0.6-4 1.0-rock-solid%v1.0.6-4' export ROOT_VERSION='v1.0.6-4' 

Sie können die Ausgabe eines solchen Skripts zum Beispiel mit der source Bash-Funktion verwenden.

Und jetzt zum spaßigen Teil. Damit die Anwendungen zum Erstellen und Bereitstellen ordnungsgemäß funktionieren, müssen Sie werf.yaml für mindestens eine Pipeline auf werf.yaml gleichen werf.yaml . Wenn diese Bedingung nicht erfüllt ist, unterscheiden sich die Signaturen der Stufen, die beim Zusammenbau berechnet werden, und beispielsweise die Bereitstellung. Dies führt zu einem Bereitstellungsfehler Das für die Bereitstellung erforderliche Image fehlt.

Mit anderen Worten: Wenn während der Erstellung des Site-Image die Informationen zu Releases und Versionen eins sind und zum Zeitpunkt der Veröffentlichung eine neue Version veröffentlicht wird und die Umgebungsvariablen unterschiedliche Werte aufweisen, schlägt die Bereitstellung mit einem Fehler fehl: Das Artefakt der neuen Version wurde noch nicht erfasst.

Wenn die Generierung von werf.yaml von externen Daten abhängt (z. B. einer Liste aktueller Versionen, wie in unserem Fall), sollten die Zusammensetzung und die Werte solcher Daten in der Pipeline aufgezeichnet werden. Dies ist besonders wichtig, wenn sich die externen Parameter häufig ändern.

Wir werden externe Daten in der ersten Phase der Pipeline in GitLab ( Prebuild ) empfangen, erfassen und als GitLab-CI-Artefakt weiterleiten . Auf diese Weise können Sie Pipeline-Tasks (Erstellen, Bereitstellen, Bereinigen) mit derselben Konfiguration in werf.yaml starten und neu werf.yaml .

Der Inhalt der Vorbereitungsphase der Datei .gitlab - ci.yml :

 Prebuild: stage: prebuild script: - bash ./generate_artifacts 1> common_envs.sh - cat ./common_envs.sh artifacts: paths: - releases.yml - common_envs.sh expire_in: 2 week 

Durch Erfassen externer Daten in einem Artefakt können Sie mithilfe der Standard-GitLab CI-Pipeline-Phasen erstellen und bereitstellen: Erstellen und Bereitstellen. Wir starten die Pipeline durch Hooks aus dem gerHub-Repository werf (d. H. Beim Ändern des Repositorys auf GitHub). Die Daten für sie können in den Eigenschaften des GitLab-Projekts im Abschnitt CI / CD-Einstellungen -> Pipeline-Trigger abgerufen und anschließend in GitHub der entsprechende Webhook ( Einstellungen -> Webhooks ) erstellt werden.

Die Erstellungsphase sieht folgendermaßen aus:

 Build: stage: build script: - type multiwerf && . $(multiwerf use 1.0 alpha --as-file) - type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose) - source common_envs.sh - werf build-and-publish --stages-storage :local except: refs: - schedules dependencies: - Prebuild 

GitLab fügt der Erstellungsphase zwei Artefakte aus der Prebuild- Phase hinzu, sodass wir die Variablen mit vorbereiteten Eingaben mithilfe des source common_envs.sh . In jedem Fall beginnen wir mit der Montage, mit Ausnahme des termingerechten Starts der Pipeline. Entsprechend dem Zeitplan wird die Pipeline zur Reinigung in Betrieb genommen - wir müssen in diesem Fall nicht bauen.

In der Bereitstellungsphase beschreiben wir zwei Aufgaben - getrennt für die Bereitstellung auf Produktions- und Entwicklungsschaltkreisen unter Verwendung der YAML-Vorlage:

 .base_deploy: &base_deploy stage: deploy script: - type multiwerf && . $(multiwerf use 1.0 alpha --as-file) - type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose) - source common_envs.sh - werf deploy --stages-storage :local dependencies: - Prebuild except: refs: - schedules Deploy to Production: <<: *base_deploy variables: WERF_KUBE_CONTEXT: prod environment: name: production url: werf.io only: refs: - master except: variables: - $REVIEW_SHA refs: - schedules Deploy to Test: <<: *base_deploy variables: WERF_KUBE_CONTEXT: dev environment: name: test url: werf.test.flant.com except: refs: - schedules only: variables: - $REVIEW_SHA 

Die Aufgaben unterscheiden sich im Wesentlichen nur dadurch, dass der Kontext des Clusters angegeben wird, in dem das Deployment ausgeführt werden soll ( WERF_KUBE_CONTEXT ) und die Umgebungsvariablen der Kontur ( environment.name und environment.url ) festgelegt werden, die dann in den Helm-Diagrammvorlagen verwendet werden. Der Inhalt der Vorlagen wird nicht angegeben, weil Es gibt nichts Interessantes für dieses Thema, aber Sie finden sie im Artikel-Repository .

Letzte Berührung


Da die werf-Versionen häufig veröffentlicht werden, werden häufig neue Bilder gesammelt und die Docker-Registrierung wird ständig erweitert. Daher ist es erforderlich, die automatische Bereinigung von Bildern nach Richtlinien zu konfigurieren. Es ist sehr einfach zu machen.

Zur Implementierung benötigen Sie:

  • .gitlab-ci.yml einen Reinigungsschritt zu .gitlab-ci.yml ;
  • Hinzufügen von regelmäßigen Bereinigungsaufgaben;
  • Setzen Sie die Umgebungsvariable mit Schreibzugriffstoken.

Fügen Sie die Bereinigungsstufe zu .gitlab-ci.yml :

 Cleanup: stage: cleanup script: - type multiwerf && . $(multiwerf use 1.0 alpha --as-file) - type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose) - source common_envs.sh - docker login -u nobody -p ${WERF_IMAGES_CLEANUP_PASSWORD} ${WERF_IMAGES_REPO} - werf cleanup --stages-storage :local only: refs: - schedules 

Fast alle von uns haben dies bereits ein wenig höher gesehen - nur zum Reinigen müssen Sie sich zuerst mit einem Token bei der Docker-Registrierung anmelden, das zum Löschen von Bildern in der Docker-Registrierung berechtigt ist (das automatisch ausgegebene GitLab CI-Task-Token verfügt nicht über solche Rechte). Das Token muss zuvor in GitLab eingegeben und sein Wert in der Umgebungsvariablen WERF_IMAGES_CLEANUP_PASSWORD Projekts (CI / CD-Einstellungen -> Variablen) angegeben werden .

Das Hinzufügen einer Reinigungsaufgabe mit dem erforderlichen Zeitplan erfolgt in CI / CD ->
Zeitpläne

Das Projekt in der Docker-Registrierung wächst nicht mehr ständig aus nicht verwendeten Bildern.

Am Ende des praktischen Teils erinnere ich mich, dass die vollständigen Auflistungen des Artikels in Git verfügbar sind:


Ergebnis


  1. Wir haben eine logische Build-Struktur: ein Artefakt pro Version.
  2. Die Assembly ist universell und erfordert keine manuellen Änderungen, wenn neue Versionen von werf veröffentlicht werden: Die Dokumentation auf der Site wird automatisch aktualisiert.
  3. Es werden zwei Bilder für unterschiedliche Konturen gesammelt.
  4. Es funktioniert schnell, weil Caching wird maximal genutzt - Wenn eine neue Version von werf veröffentlicht wird oder ein GitHub-Hook für ein Review-Commit aufgerufen wird, wird nur das entsprechende Artefakt mit einer geänderten Version neu erstellt.
  5. Über das Löschen nicht verwendeter Bilder müssen Sie nicht nachdenken: Die Bereinigung der Werf-Richtlinie behält die Reihenfolge in der Docker-Registrierung bei.

Schlussfolgerungen


  • Mit werf kann die Assembly schnell arbeiten, da sowohl die Assembly selbst als auch das Caching bei der Arbeit mit externen Repositorys zwischengespeichert werden.
  • Git- . werf , fetch .
  • Go- werf.yaml , .
  • werf — , pipeline.
  • werf , .

PS


:

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


All Articles