Wir haben bereits mehrfach über unser GitOps-Tool berichtet, und diesmal möchten wir unsere Erfahrungen beim Aufbau der Website mit der Dokumentation des Projekts selbst teilen — (die russische Version ist — ). Es handelt sich um eine ganz normale statische Website, deren Aufbau jedoch interessant ist, da er mit einer dynamischen Anzahl von Artefakten erstellt wurde.

Auf die Feinheiten der Website-Struktur, wie die Generierung eines gemeinsamen Menüs für alle Versionen, Seiten mit Informationen zu Releases usw., werden wir nicht eingehen. Stattdessen konzentrieren wir uns auf die Fragen und Besonderheiten der dynamischen Erstellung sowie auf einige begleitende CI/CD-Prozesse.
Einführung: Wie die Website strukturiert ist
Zunächst einmal wird die Dokumentation zu werf zusammen mit seinem Code gespeichert. Dies stellt bestimmte Anforderungen an die Entwicklung, die insgesamt über den Rahmen dieses Artikels hinausgehen, aber mindestens kann gesagt werden, dass:
- Neue Funktionen von werf sollten nicht erscheinen, ohne dass die Dokumentation aktualisiert wird und umgekehrt, jede Änderung in der Dokumentation erfordert die Veröffentlichung einer neuen Version von werf;
- Das Projekt wird intensiv weiterentwickelt: Neue Versionen können mehrmals täglich erscheinen;
- Manuelle Eingriffe bei der Bereitstellung einer Website mit einer neuen Version der Dokumentation sind zumindest mühsam.
- Im Projekt wird ein semantischer Ansatz , mit 5 Stabilitätskanälen, verfolgt. Der Freigabeprozess sieht eine schrittweise Durchlauf von Versionen durch die Kanäle in der Reihenfolge steigender Stabilität vor: von alpha bis rock-solid.
- Die Website hat eine russische Version, die parallel zur Hauptversion (d.h. der englischsprachigen Version) "lebt und sich entwickelt" (d.h. deren Inhalte aktualisiert werden).
Um dem Nutzer all diese "internen Details" zu verbergen und ihm nur das anzubieten, was "einfach funktioniert", haben wir ein separates Werkzeug zur Installation und Aktualisierung von werf — ist geschaffen. Es genügt, die Versionsnummer und den Stabilitätskanal anzugeben, den Sie verwenden möchten, und multiwerf wird überprüfen, ob eine neue Version im Kanal verfügbar ist und diese bei Bedarf herunterladen.
Im Menü zur Auswahl der Versionen auf der Website sind die neuesten Versionen von werf in jedem Kanal verfügbar. Standardmäßig wird unter die Version des stabilsten Kanals für die letzte Veröffentlichung geöffnet — diese wird auch von Suchmaschinen indexiert. Die Dokumentation für den Kanal ist unter separaten Adressen verfügbar (zum Beispiel, für die Beta-Version 1.0).
Insgesamt stehen für die Website folgende Versionen zur Verfügung:
- Root-Version (wird standardmäßig geöffnet),
- für jeden aktiven Update-Kanal jeder Veröffentlichung (z. B. ).
Um eine bestimmte Version der Website zu generieren, genügt es im Allgemeinen, sie mit den Mitteln zu kompilieren , indem Sie im Verzeichnis /docs des werf-Repositories den entsprechenden Befehl ausführen (jekyll build), nachdem Sie auf das benötigte Git-Tag der Version umgeschaltet haben.
Es bleibt nur hinzuzufügen, dass:
- zum Bauen das Dienstprogramm selbst (werf) verwendet wird;
- CI/CD-Prozesse basieren auf GitLab CI;
- und all dies funktioniert natürlich in Kubernetes.
Aufgaben
Jetzt formulieren wir Aufgaben, die alle beschriebenen Spezifikationen berücksichtigen:
- Nach der Änderung der Version von werf in einem beliebigen Update-Kanal sollte die Dokumentation auf der Website automatisch aktualisiert werden.
- Für die Entwicklung muss es manchmal möglich sein, Vorschauversionen der Website anzuzeigen.
Die Website muss nach der Änderung der Version in einem beliebigen Kanal von den entsprechenden Git-Tags neu kompiliert werden, aber im Prozess des Erstellens des Abbilds erhalten wir folgende Besonderheiten:
- Da die Liste der Versionen auf den Kanälen sich ändert, muss die Dokumentation nur für die Kanäle neu erstellt werden, bei denen sich die Version geändert hat. Es wäre nicht ideal, alles von Grund auf neu zu erstellen.
- Die Auswahl an Kanälen für Releases kann variieren. Zu einem bestimmten Zeitpunkt kann es keine Version auf stabileren Kanälen als die early-access 1.1 geben, aber im Laufe der Zeit werden sie verfügbar sein – sollte man in diesem Fall die Builds manuell ändern?
Es stellt sich heraus, dass Der Build hängt von sich ändernden externen Daten ab..
Implementierung
Wahl des Ansatzes.
Als Alternative könnte man jede benötigte Version in einem eigenen Pod auf Kubernetes starten. Diese Option erfordert eine höhere Anzahl von Objekten im Cluster, die parallel zum Anstieg stabiler werf-Releases wachsen wird. Dies zieht wiederum einen höheren Wartungsaufwand nach sich: Jede Version hat ihren eigenen HTTP-Server, der jedoch eine geringe Last hat. Natürlich führt dies auch zu höheren Ressourcenkosten.
Wir haben den Weg eingeschlagen alle benötigten Versionen in einem einzigen Image zu begleiten.. Die kompilierte Statische aller Versionen der Website befindet sich in einem Container mit NGINX, und der Traffic zum entsprechenden Deployment erfolgt über NGINX Ingress. Die einfache Struktur – ein stateless-Anwendung – ermöglicht eine einfache Skalierung des Deployments (je nach Last) mithilfe von Kubernetes selbst.
Genauer gesagt, erstellen wir zwei Images: eines für die Produktionsumgebung und ein zusätzliches für die Entwicklungsumgebung. Das zusätzliche Image wird nur in der Entwicklungsumgebung zusammen mit dem Hauptimage verwendet und enthält die Version der Website aus dem Review-Commit, während das Routing zwischen ihnen über Ingress-Ressourcen erfolgt.
werf vs git clone und Artefakte
Wie bereits erwähnt, um die Statische der Website für eine spezifische Version der Dokumentation zu generieren, muss ein Build erstellt werden, indem auf das entsprechende Tag im Repository gewechselt wird. Man könnte dies auch tun, indem man das Repository bei jedem Build klont und die entsprechenden Tags aus einer Liste auswählt. Dies ist jedoch eine recht ressourcenintensive Operation und erfordert zudem das Schreiben von komplexen Anweisungen... Ein weiterer erheblicher Nachteil ist, dass bei diesem Ansatz keine Möglichkeit besteht, während des Builds etwas zu cachen.
Hier kommt das Tool werf ins Spiel, das intelligentes Caching implementiert und externe Repositories nur fetch . Die Nutzung von werf für das Hinzufügen von Code aus einem Repository beschleunigt den Aufbau erheblich, da werf im Grunde das Repository einmal klont und dann bei Bedarf ausführt. Darüber hinaus können wir beim Hinzufügen von Daten aus dem Repository nur die notwendigen Verzeichnisse auswählen (in unserem Fall ist das das Verzeichnisdocs
), was das Volumen der hinzuzufügenden Daten erheblich reduziert. werf-Artefakt durchzuführen und nur das Kompilierungsergebnis.
in das finale Image
zu importieren. Schreiben wir werf.yamlAlso, wir haben entschieden, dass wir jede Version in einem separaten werf-Artefakt kompilieren werden. Wir
wissen jedoch nicht, wie viele dieser Artefakte beim Aufbau entstehen werden, werf ermöglicht die Nutzung vonwerf.yamlGo-Templates in seiner Konfigurationsdatei ( je nach externen Daten (was benötigt wird!). In unserem Fall sind externe Daten Informationen über Versionen und Releases, auf deren Basis wir die erforderliche Anzahl an Artefakten sammeln und letztendlich zwei Images erhalten: werf-doc und werf-dev zum Start auf unterschiedlichen Umgebungen.
Die externen Daten werden über Umgebungsvariablen übergeben. Diese setzen sich aus folgendem zusammen:
-
RELEASES– eine Zeichenkette mit einer Liste von Releases und der entsprechenden aktuellen Version von werf, in Form einer Liste durch Leerzeichen getrennt im Format%. Beispiel:1.0%v1.0.4-beta.20 -
CHANNELS– eine Zeichenkette mit einer Liste von Kanälen und der entsprechenden aktuellen Version von werf, in Form einer Liste durch Leerzeichen getrennt im Format%. Beispiel:1.0-beta%v1.0.4-beta.20 1.0-alpha%v1.0.5-alpha.22 -
ROOT_VERSION– die Release-Version von werf, die standardmäßig auf der Website angezeigt wird (nicht immer muss die Dokumentation zur höchsten Release-Nummer angezeigt werden). Beispiel:v1.0.4-beta.20 -
REVIEW_SHA– der Hash des Review-Commits, aus dem die Version für die Testumgebung erstellt werden muss.
Diese Variablen werden im GitLab CI-Pipeline gefüllt, und wie genau – wird weiter unten beschrieben.
Zunächst definieren wir der Einfachheit halber in werf.yaml Go-Template-Variablen, denen Werte aus Umgebungsvariablen zugewiesen werden:
{{ $_ := set . "WerfVersions" (cat (env "CHANNELS") (env "RELEASES") | splitList " ") }}
{{ $Root := . }}
{{ $_ := set . "WerfRootVersion" (env "ROOT_VERSION") }}
{{ $_ := set . "WerfReviewCommit" (env "REVIEW_SHA") }} Die Beschreibung des Artefakts zur Kompilierung der statischen Version der Website ist für alle benötigten Fälle weitgehend identisch (einschließlich der Generierung der Root-Version sowie der Version für den Entwicklungs-Workflow). Daher werden wir es in einen separaten Block auslagern, um es später wiederzuverwenden, indem wir definieren — verwenden. includeDem Template werden die folgenden Argumente übergeben:
-
Version— die generierte Version (Tag-Name); -
Kanal— der Name des Update-Kanals, für den das Artefakt generiert wird; -
Commit— der Commit-Hash, sofern das Artefakt für einen Review-Commit erstellt wird; - Kontext.
Beschreibung des Artefakt-Templates
{{- 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: "Abhängigkeiten installieren"
shell: bundle install
args:
executable: /bin/bash
chdir: /app/docs
beforeSetup:
{{- if .Commit }}
- shell: echo "SHA überprüfen - {{ .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 einzigartig sein. Dies können wir erreichen, indem wir beispielsweise den Namen des Kanals (Wert der Variablen .Channel) als Suffix zum Artefaktnamen hinzufügen: artifact: doc-{{ .Channel }}. Es ist jedoch wichtig zu verstehen, dass beim Importieren von Artefakten auf die gleichen Namen verwiesen werden muss.
Bei der Beschreibung des Artefakts wird die Funktion von werf genutzt, die als bezeichnet wird. Die Montage mit dem angegebenen Arbeitsverzeichnis build_dir ermöglicht die Speicherung des Jekyll-Caches zwischen den Pipeline-Läufen, was die Neukompilierung erheblich beschleunigt..
Sie haben vielleicht auch die Verwendung der Datei releases.yml bemerkenswert — dies ist eine YAML-Datei mit Daten über die Releases, die von (Artefakt, das bei der Ausführung der Pipeline entsteht) abgefragt wird. Sie wird benötigt, um die Website zu kompilieren, ist aber im Kontext des Artikels interessant, da ihr Zustand die Neukompilierung nur eines Artefakts bestimmt — das Artefakt der Hauptversion der Website (in anderen Artefakten ist es nicht erforderlich).
Dies wird durch einen bedingten Operator wenn in Go-Templates und die Konstruktion {{ $Root.Files.Get "releases.yml" | sha256sum }} im Schritt . So funktioniert es: Bei der Erstellung des Artefakts für die Hauptversion (Variable .Channel 0,68 Mbit/s. root) wird der Dateihash releases.yml beeinflusst die Signatur der gesamten Phase, da es ein Bestandteil des Namens der Ansible-Aufgabe ist (Parameter name). Daher, wenn sich der Inhalt Datei releases.yml ändert, wird das entsprechende Artefakt neu erstellt.
Bitte beachten Sie auch die Arbeit mit einem externen Repository. Im Artefakt-Image von wird nur das Verzeichnis /docshinzugefügt, wobei je nach übergebenen Parametern Daten des jeweils erforderlichen Tags oder des Review-Commits hinzugefügt werden.
Um die Vorlage des Artefakts zur Generierung der Beschreibung des Artefakts für übergebene Versionen von Kanälen und Releases zu verwenden, organisieren wir eine Schleife über die Variable .WerfVersions in werf.yaml:
{{ range .WerfVersions -}}
{{ $VersionsDict := splitn "%" 2 . -}}
{{ dict "Version" $VersionsDict._1 "Channel" $VersionsDict._0 "Root" $Root | include "doc_artifact" }}
---
{{ end -}} Da die Schleife mehrere Artefakte generieren wird (darauf hoffen wir), muss der Trenner zwischen ihnen berücksichtigt werden — die Sequenz --- (siehe zur Syntax der Konfigurationsdatei ). Wie zuvor festgelegt, übergeben wir beim Aufruf der Vorlage in der Schleife die Parameter Version, URL und den Root-Kontext.
Ähnlich, jedoch ohne Schleife, rufen wir die Vorlage des Artefakts für „Sonderfälle“ auf: für die Root-Version sowie 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 }} Bitte beachten Sie, dass das Artefakt für den Review-Commit nur erstellt wird, wenn die Variable .WerfReviewCommit.
Fertig mit den Artefakten — es ist Zeit für den Import!
Das endgültige Abbild, das für den Einsatz in Kubernetes vorgesehen ist, ist ein reguläres NGINX, das mit einer Serverkonfigurationsdatei ausgestattet ist nginx.conf und statischen Inhalten aus den Artefakten. Neben dem Artefakt der Root-Version der Website müssen wir eine Schleife über die Variable wiederholen .WerfVersions um die Artefakte der Kanal- und Release-Versionen zu importieren + die zuvor festgelegte Benennungsregel der Artefakte einzuhalten. Da jedes Artefakt die Versionen der Website in zwei Sprachen speichert, importieren wir sie an die in der Konfiguration vorgesehenen Stellen.
Beschreibung des endgültigen Abbilds werf-doc
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 dem Dev-Branch gestartet wird, enthält nur zwei Versionen der Website: die Version aus dem Review-Commit und die Root-Version der Website (dort sind die gemeinsamen Assets und, wenn Sie sich erinnern, die Daten zu den Releases). Somit wird sich das zusätzliche Image vom Hauptimage nur durch den Import-Bereich (und natürlich den Namen) unterscheiden.
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 den Review-Commit nur generiert, wenn die entsprechende Umgebungsvariable gesetzt ist. REVIEW_SHAEs wäre sogar möglich, das Image werf-dev gar nicht zu generieren, wenn die Umgebungsvariable nicht gesetzt ist. REVIEW_SHA, aber um von Docker-Images in werf für das werf-dev-Image zu ermöglichen, lassen wir es nur mit dem Artefakt der Hauptversion erstellen (es ist ohnehin bereits gebaut), um die Struktur des Pipelines zu vereinfachen.
Der Build ist fertig! Gehen wir zu CI/CD und wichtigen Details über.
Pipeline in GitLab CI und Besonderheiten des dynamischen Builds
Beim Start des Builds müssen wir die Umgebungsvariablen festlegen, die in werf.yamlverwendet werden. Dies betrifft nicht die Variable REVIEW_SHA, die wir beim Aufruf des Pipelines durch den GitHub-Hook setzen werden.
Die Erstellung der benötigten externen Daten wird in ein Bash-Skript generate_artifacts, das zwei Artefakte für das GitLab-Pipeline generieren wird, ausgelagert:
- eine Datei
releases.ymlmit den Release-Daten, - eine Datei
common_envs.sh, die Umgebungsvariablen für den Export enthalten.
Inhalt der Datei generate_artifacts finden Sie in unserem . Die Datenbeschaffung selbst ist nicht Thema des Artikels, aber die Datei common_envs.sh ist uns wichtig, denn sie beeinflusst die Funktion von werf. Ein Beispiel für ihren 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' Die Ausgabe eines solchen Skripts kann beispielsweise mit einer Bash-Funktion verwendet werden. source.
Und jetzt das Interessanteste. Um sicherzustellen, dass sowohl der Build als auch das Deployment der Anwendung korrekt funktionieren, muss gewährleistet werden, dass werf.yaml war identisch mindestens im Rahmen eines Pipelines. Wenn diese Bedingung nicht erfüllt ist, werden die Signaturen der Phasen, die werf beim Build und beispielsweise beim Deployment berechnet, unterschiedlich sein. Dies führt zu einem Deployment-Fehler, da das für das Deployment erforderliche Image fehlt.
Anders gesagt, wenn während des Builds des Website-Images die Informationen über Releases und Versionen gleich sind, aber beim Deployment eine neue Version herauskommt und die Umgebungsvariablen andere Werte haben, wird das Deployment mit einem Fehler enden: denn das Artefakt der neuen Version wurde noch nicht gebaut.
Wenn die Generierung werf.yaml hängt von externen Daten ab (zum Beispiel von einer Liste aktueller Versionen, wie in unserem Fall), daher müssen die Zusammensetzung und Werte solcher Daten innerhalb des Pipelines festgehalten werden. Dies ist besonders wichtig, wenn sich die externen Parameter recht häufig ändern.
Wir werden externe Daten abrufen und festhalten in der ersten Phase des Pipelines in GitLab (Prebuild) und sie dann als GitLab CI-Artefaktweitergeben. Dies ermöglicht es, die Pipeline-Jobs (Build, Deployment, Cleanup) mit derselben Konfiguration zu starten und neu zu starten in werf.yaml.
Inhalt der Phase Prebuild 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 WochenNachdem die externen Daten in dem Artefakt festgehalten wurden, kann der Build und das Deployment unter Verwendung der Standardphasen der GitLab CI-Pipeline: Build und Deploy durchgeführt werden. Die Pipeline selbst wird über Hooks aus dem GitHub-Repository werf gestartet (d.h. bei Änderungen im Repository auf GitHub). Die Daten dafür können in den Projekteigenschaften von GitLab im Abschnitt CI / CD-Einstellungen -> Pipeline-Triggerentnommen werden, und dann erstellen wir im GitHub den entsprechenden Webhook (Einstellungen -> Webhooks).
Die Build-Phase wird wie folgt aussehen:
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 wird zwei Artefakte aus der Build-Phase hinzufügen. Prebuild, daher exportieren wir die Variablen mit den vorbereiteten Eingabewerten mithilfe der Struktur source common_envs.sh. Wir starten die Build-Phase in allen Fällen, außer beim Ausführen des Pipelines nach Zeitplan. Der Pipeline für die Bereinigung wird nach Zeitplan gestartet — eine Build-Ausführung ist in diesem Fall nicht erforderlich.
In der Deployment-Phase werden wir zwei Aufgaben beschreiben — eine jeweils für das Deployment auf Produktions- und Entwicklungsumgebungen unter Verwendung einer 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
Bereitstellung in der Produktion:
<<: *base_deploy
variables:
WERF_KUBE_CONTEXT: prod
environment:
name: production
url: werf.io
only:
refs:
- master
except:
variables:
- $REVIEW_SHA
refs:
- schedules
Bereitstellung für Tests:
<<: *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 durch die Angabe des Clusterkontexts, in den werf die Bereitstellung durchführen soll (WERF_KUBE_CONTEXT), und durch die Festlegung der Umgebungsvariablen (environment.name und environment.url), die dann in den Helm-Chart-Vorlagen verwendet werden. Wir werden die Inhalte der Vorlagen nicht aufführen, da sie für das behandelte Thema nicht interessant sind, aber Sie können sie im .
Letzter Schliff
Da die Versionen von werf recht häufig erscheinen, werden auch neue Images regelmäßig erstellt, und das Docker-Registry wird ständig wachsen. Daher ist es unbedingt erforderlich, eine automatische Bereinigung der Images nach festgelegten Richtlinien einzurichten. Das ist ganz einfach zu bewerkstelligen.
Für die Umsetzung benötigen Sie:
- Eine Bereinigungsstufe hinzufügen in
.gitlab-ci.yml; - Eine regelmäßige Ausführung des Bereinigungsauftrags hinzufügen;
- Umgebungsvariable mit einem schreibberechtigten Zugriffstoken konfigurieren.
Fügen wir eine Bereinigungsstufe hinzu in .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 alles haben wir bereits etwas weiter oben gesehen – nur für die Bereinigung muss man sich zunächst im Docker Registry mit einem Token authentifizieren, das die Berechtigung zum Löschen von Images im Docker Registry hat (das automatisch ausgegebene Token für GitLab CI-Jobs hat diese Berechtigungen nicht). Das Token muss im Voraus in GitLab erstellt und dessen Wert in der Umgebungsvariable angegeben werden. WERF_IMAGES_CLEANUP_PASSWORD Projekts (CI/CD-Einstellungen -> Variablen).
Das Hinzufügen des Bereinigungsauftrags mit dem erforderlichen Zeitplan erfolgt in CI/CD ->
Zeitpläne.
Fertig: Das Projekt im Docker Registry wird nicht mehr ständig durch nicht verwendete Images wachsen.
Abschließend möchte ich daran erinnern, dass die vollständigen Auflistungen aus dem Artikel verfügbar sind in :
- ;
- .
Ergebnis
- Wir haben eine logische Struktur des Builds erhalten: ein Artefakt pro Version.
- Die Konfiguration ist universell und erfordert keine manuellen Anpassungen bei neuen Versionen von werf: die Dokumentation auf der Website wird automatisch aktualisiert.
- Es werden zwei Images für unterschiedliche Umgebungen erstellt.
- Die Funktionalität ist schnell, da das Caching optimal genutzt wird – beim Erstellen einer neuen Version von werf oder beim Auslösen eines GitHub-Hooks für einen Review-Commit wird nur der entsprechende Artefakt mit der geänderten Version neu erstellt.
- Sie müssen sich keine Gedanken über die Entfernung ungenutzter Images machen: Die Bereinigung gemäß der werf-Richtlinien sorgt für Ordnung im Docker-Registry.
Fazit
- Die Verwendung von werf ermöglicht es, dass der Build schnell arbeitet, dank der Caching-Funktion sowohl für den Build selbst als auch beim Arbeiten mit externen Repositories.
- Die Arbeit mit externen Git-Repositories erspart das vollständige Klonen des Repositories jedes Mal oder das Erfinden komplexer Optimierungslogik. werf verwendet Caching und klont nur einmal, danach nutzt es
fetchund nur bei Bedarf. - Die Möglichkeit, Go-Templates in der Build-Konfigurationsdatei zu verwenden,
werf.yamlermöglicht die Beschreibung eines Builds, dessen Ergebnis von externen Daten abhängt. - Die Verwendung von Montierung in werf beschleunigt den Artefaktsammelprozess erheblich – dank des Caches, der für alle Pipelines gemeinsam ist.
- Mit werf lässt sich die Bereinigung problemlos einrichten, was insbesondere bei dynamischen Builds von Bedeutung ist.
P.S.
Lesen Sie auch in unserem Blog:
- «»;
- «»;
- «»;
- «».
Quelle: habr.com
