Nous avons dĂ©jĂ parlĂ© Ă plusieurs reprises de notre outil GitOps , et cette fois, nous aimerions partager notre expĂ©rience de la construction du site avec la documentation du projet lui-mĂȘme â (sa version en russe est â ). Il s'agit d'un site statique ordinaire, cependant, sa construction est intĂ©ressante car elle est rĂ©alisĂ©e en utilisant un nombre dynamique d'artefacts.

Nous ne plongerons pas dans les dĂ©tails de la structure du site : gĂ©nĂ©ration du menu commun pour toutes les versions, pages d'information sur les versions, etc. â mais nous allons plutĂŽt nous concentrer sur les questions et les particularitĂ©s de la construction dynamique et un peu sur les processus connexes CI/CD.
Introduction : comment le site est organisé
Commençons par le fait que la documentation de werf est stockée avec son code. Cela impose certaines exigences au développement, qui dépassent globalement le cadre de cet article, mais nous pouvons au moins dire que :
- Les nouvelles fonctionnalitĂ©s de werf ne doivent pas ĂȘtre publiĂ©es sans mise Ă jour de la documentation et, inversĂ©ment, tout changement dans la documentation implique la sortie d'une nouvelle version de werf ;
- Le projet fait l'objet d'un développement assez intensif : de nouvelles versions peuvent sortir plusieurs fois par jour ;
- Toute opération manuelle de déploiement du site avec une nouvelle version de la documentation est au minimum fastidieuse ;
- Le projet adopte une approche de versioning sémantique , avec 5 canaux de stabilité. Le processus de publication implique le passage successif des versions par les canaux dans l'ordre croissant de stabilité : d'alpha à rock-solid ;
- Le site dispose d'une version en russe, qui « vit et évolue » (c'est-à -dire que son contenu est mis à jour) parallÚlement à la version principale (c'est-à -dire la version anglaise).
Pour cacher Ă l'utilisateur toute cette « cuisine interne », en lui proposant ce qui « fonctionne simplement », nous avons créé un outil sĂ©parĂ© pour installer et mettre Ă jour werf â ce sont des . Il suffit d'indiquer le numĂ©ro de version et le canal de stabilitĂ© que vous ĂȘtes prĂȘt Ă utiliser, et multiwerf vĂ©rifiera s'il existe une nouvelle version sur le canal et la tĂ©lĂ©chargera si nĂ©cessaire.
Dans le menu de sĂ©lection des versions sur le site, les derniĂšres versions de werf sont disponibles dans chaque canal. Par dĂ©faut, Ă l'adresse , s'ouvre la version du canal le plus stable pour la derniĂšre version â elle est Ă©galement indexĂ©e par les moteurs de recherche. La documentation pour le canal est disponible Ă des adresses distinctes (par exemple, pour la version beta 1.0).
En résumé, le site propose les versions suivantes :
- racine (s'ouvre par défaut),
- pour chaque canal actif de mises Ă jour de chaque version (par exemple, ).
Pour gĂ©nĂ©rer une version spĂ©cifique du site, il suffit en gĂ©nĂ©ral de le compiler avec , en exĂ©cutant dans le rĂ©pertoire /docs du dĂ©pĂŽt werf la commande correspondante (jekyll build), aprĂšs s'ĂȘtre prĂ©alablement configurĂ© sur le Git-tag de la version nĂ©cessaire.
Il ne reste plus qu'Ă ajouter que :
- pour la compilation, on utilise l'outil lui-mĂȘme (werf) ;
- les processus CI/CD sont basés sur GitLab CI ;
- et tout cela fonctionne, bien sûr, dans Kubernetes.
Objectifs
Formulons maintenant les tùches en tenant compte de toute cette spécificité :
- AprĂšs le changement de version de werf sur n'importe quel canal de mise Ă jour, la documentation sur le site doit se mettre Ă jour automatiquement..
- Pour le dĂ©veloppement, il doit parfois ĂȘtre possible de consulter les versions prĂ©liminaires du site..
La recompilation du site doit ĂȘtre effectuĂ©e aprĂšs le changement de version sur n'importe quel canal Ă partir des Git-tags correspondants, mais pendant le processus de construction de l'image, nous obtiendrons les particularitĂ©s suivantes :
- Ătant donnĂ© que la liste des versions sur les canaux change, il est nĂ©cessaire de ne recompter que la documentation pour les canaux oĂč la version a changĂ©. Recompiler tout de nouveau n'est pas trĂšs Ă©lĂ©gant.
- L'ensemble des canaux de release peut changer. Ă un moment donnĂ©, par exemple, il peut ne pas y avoir de version sur des canaux plus stables que la release early-access 1.1, mais au fil du temps, elles apparaĂźtront â ne pas changer la construction Ă la main dans ce cas ?
Il en résulte qu'un seul image provenant d'un registre lent peut bloquer le déploiement la construction dépend de données externes changeantes.
Mise en Ćuvre
Choix de l'approche
Comme option, on peut lancer chaque version nécessaire sur un pod séparé dans Kubernetes. Cette option implique un plus grand nombre d'objets dans le cluster, qui augmentera avec le nombre croissant de releases stables de werf. Cela entraßne à son tour une maintenance plus complexe : chaque version a son propre serveur HTTP, avec une charge par faible. Bien sûr, cela entraßne également des coûts en ressources plus élevés.
Nous avons cependant optĂ© pour la compilation de toutes les versions nĂ©cessaires dans une seule image. La static compilĂ©e de toutes les versions du site se trouve dans un conteneur NGINX, et le trafic vers le Deployment correspondant passe par NGINX Ingress. Cette structure simple â application sans Ă©tat â permet une scalabilitĂ© facile du Deployment (en fonction de la charge) grĂące aux moyens de Kubernetes lui-mĂȘme.
Pour ĂȘtre plus prĂ©cis, nous gĂ©nĂ©rons deux images : l'une pour l'environnement de production, l'autre pour l'environnement de dĂ©veloppement. L'image supplĂ©mentaire est utilisĂ©e (lancĂ©e) uniquement dans l'environnement de dĂ©veloppement en parallĂšle avec la principale et contient la version du site issue du commit de rĂ©vision, tandis que le routage entre elles est effectuĂ© Ă l'aide des ressources Ingress.
werf vs git clone et artefacts
Comme mentionné précédemment, pour générer la version statique du site pour une version spécifique de la documentation, il faut effectuer une compilation en basculant vers la balise correspondante du dépÎt. On pourrait également le faire en clonant le dépÎt chaque fois qu'une compilation est effectuée, en choisissant les balises appropriées selon une liste. Cependant, cela est une opération assez gourmande en ressources et nécessite également la rédaction d'instructions non triviales... Un autre inconvénient majeur est que cette approche ne permet pas de mettre quoi que ce soit en cache pendant la compilation.
Ici, nous avons le soutien de l'outil werf qui réalise le caching intelligent et permet d'utiliser . L'utilisation de werf pour ajouter du code provenant du dépÎt accélérera considérablement la compilation, car werf clone essentiellement le dépÎt une fois, puis exécute uniquement fetch si nécessaire. De plus, lors de l'ajout de données depuis le dépÎt, nous pouvons sélectionner uniquement les répertoires nécessaires (dans notre cas, c'est le dossier docs), ce qui réduit considérablement le volume des données ajoutées.
Puisque Jekyll est un outil destinĂ© Ă la compilation de sites statiques et qu'il n'est pas nĂ©cessaire dans l'image finale, il serait logique de rĂ©aliser la compilation dans , et d'importer dans l'image finale seulement le rĂ©sultat de la compilation Ăcrivons werf.yaml.
Donc, nous avons décidé de compiler chaque version dans un artefact werf séparé. Cependant, nous
ne savons pas combien d'artefacts cela fera lors de la compilation , donc nous ne pouvons pas écrire une configuration de compilation fixe (strictement parlant, nous le pouvons, mais ce ne sera pas trÚs efficace).werf permet d'utiliser
des modÚles Go ), ce qui permet dewerf.yamlgénérer la configuration « à la volée » en fonction des données externes (ce qui est nécessaire !). Les données externes dans notre cas sont les informations sur les versions et les releases, sur la base desquelles nous assemblons le nombre nécessaire d'artefacts et obtenons en résultat deux images : werf-doc werf-dev et pour un déploiement sur différents environnements. pour le lancement sur différents contournements.
Les données externes sont transmises via des variables d'environnement. Voici leur composition :
-
PUBLICATIONSâ une chaĂźne contenant la liste des publications et leur version actuelle correspondante de werf, sous la forme d'une liste sĂ©parĂ©e par des espaces avec le format%. Exemple :1.0%v1.0.4-beta.20 -
CANAUXâ une chaĂźne contenant la liste des canaux et leur version actuelle correspondante de werf, sous la forme d'une liste sĂ©parĂ©e par des espaces avec le format%. Exemple :1.0-beta%v1.0.4-beta.20 1.0-alpha%v1.0.5-alpha.22 -
VERSION_DE_BASEâ la version de la publication werf Ă afficher par dĂ©faut sur le site (il n'est pas toujours nĂ©cessaire d'afficher la documentation pour le numĂ©ro de publication le plus Ă©levĂ©). Exemple :v1.0.4-beta.20 -
HASH_DE_REVIEWâ le hash du commit de review Ă partir duquel la version doit ĂȘtre construite pour le pipeline de test.
Ces variables seront peuplées dans le pipeline GitLab CI, et comment cela se fera est expliqué ci-dessous.
Tout d'abord, pour plus de commodité, nous allons définir dans werf.yaml les variables de modÚle Go, en leur attribuant des valeurs provenant des variables d'environnement :
{{ $_ := set . "WerfVersions" (cat (env "CANAUX") (env "PUBLICATIONS") | splitList " ") }}
{{ $Root := . }}
{{ $_ := set . "WerfRootVersion" (env "VERSION_DE_BASE") }}
{{ $_ := set . "WerfReviewCommit" (env "HASH_DE_REVIEW") }} La description de l'artefact pour la compilation de la version statique du site est globalement la mĂȘme pour tous les cas nĂ©cessaires (y compris, la gĂ©nĂ©ration de la version racine et de la version pour le pipeline dev). Nous allons donc le dĂ©placer dans un bloc sĂ©parĂ© Ă l'aide de la fonction define â pour une rĂ©utilisation ultĂ©rieure via include. Le modĂšle recevra les arguments suivants :
-
Versionâ la version gĂ©nĂ©rĂ©e (nom de la balise) ; -
Channelâ le nom du canal de mise Ă jour pour lequel l'artefact est gĂ©nĂ©rĂ© ; -
Commitâ le hash du commit, si l'artefact est gĂ©nĂ©rĂ© pour un commit de review ; - contexte.
Description du modĂšle d'artefact
{{- 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: "Installer les Dépendances"
shell: bundle install
args:
executable: /bin/bash
chdir: /app/docs
beforeSetup:
{{- if .Commit }}
- shell: echo "Revoir 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/fr_site/
- file:
dest: /app/docs/pages_fr/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/_fr_site/{{ if .BaseURL }} --baseurl /{{ .BaseURL }}{{ end }} --config /app/docs/_config.yml,/app/docs/_config_fr.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 }} Le nom de l'artefact doit ĂȘtre unique. Nous pouvons y parvenir, par exemple, en ajoutant le nom du canal (valeur de la variable .Channel) comme suffixe du nom de l'artefact : artifact: doc-{{ .Channel }}. Mais il est important de comprendre que lors de l'importation Ă partir des artefacts, il faudra se rĂ©fĂ©rer Ă ces mĂȘmes noms.
Lors de la description de l'artefact, il existe une fonctionnalité de werf appelée . Le montage en spécifiant le répertoire de service build_dir permet de conserver le cache de Jekyll entre les exécutions du pipeline, ce qui accélÚre considérablement la reconstruction.
Vous avez Ă©galement peut-ĂȘtre remarquĂ© l'utilisation du fichier releases.yml â il s'agit d'un fichier YAML contenant des donnĂ©es sur les versions, demandĂ© lors de (artefact obtenu lors de l'exĂ©cution du pipeline). Il est nĂ©cessaire lors de la compilation du site, mais dans le contexte de cet article, il est intĂ©ressant de noter que son Ă©tat influence la reconstruction d'un seul artefact â l'artefact de la version racine du site (il n'est pas nĂ©cessaire dans d'autres artefacts).
Cela est réalisé à l'aide d'un opérateur conditionnel if dans le modÚle Go et de la construction {{ $Root.Files.Get "releases.yml" | sha256sum }} dans l'étape . Cela fonctionne de la maniÚre suivante : lors de la création de l'artefact pour la version racine (la variable .Channel est égale à root) le hachage du fichier releases.yml influence la signature de toute la phase, car il fait partie du nom de la tùche Ansible (paramÚtre nom). Ainsi, lorsqu'il y a un changement de contenu, fichiers releases.yml l'artefact correspondant sera reconstruit.
Notez également le travail avec le dépÎt externe. Dans l'image de l'artefact du , seul le répertoire est ajouté, /docset selon les paramÚtres passés, les données du tag ou du commit de révision nécessaires sont ajoutées immédiatement.
Pour utiliser le modÚle d'artefact afin de générer la description de l'artefact des versions et des canaux transmis, organisons une boucle sur la variable .WerfVersions dans werf.yaml:
{{ range .WerfVersions -}}
{{ $VersionsDict := splitn "%" 2 . -}}
{{ dict "Version" $VersionsDict._1 "Channel" $VersionsDict._0 "Root" $Root | include "doc_artifact" }}
---
{{ end -}} Comme la boucle gĂ©nĂ©rera plusieurs artefacts (nous l'espĂ©rons), il faut prendre en compte le sĂ©parateur entre eux â la sĂ©quence --- (voir plus sur la syntaxe du fichier de configuration dans ). Comme nous l'avons dĂ©terminĂ© prĂ©cĂ©demment, lors de l'appel du modĂšle dans la boucle, nous passons les paramĂštres de version, l'URL et le contexte racine.
De maniÚre similaire, mais sans boucle, nous appelons le modÚle d'artefact pour les « cas particuliers » : pour la version racine, ainsi que pour la version du commit de révision :
{{ 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 }} Remarque : l'artefact pour le commit de révision ne sera construit que si la variable .WerfReviewCommit.
Les artefacts sont prĂȘts â il est temps de s'occuper de l'importation !
L'image finale, destinĂ©e Ă ĂȘtre exĂ©cutĂ©e dans Kubernetes, est un NGINX standard, auquel est ajoutĂ© un fichier de configuration de serveur nginx.conf et la partie statique de l'artefact. En plus de l'artefact de la version racine du site, nous devons rĂ©pĂ©ter la boucle sur la variable .WerfVersions pour importer les artefacts des versions et des canaux, tout en respectant la rĂšgle de nommage des artefacts que nous avons adoptĂ©e prĂ©cĂ©demment. Puisque chaque artefact conserve les versions du site pour deux langues, nous les importons dans les emplacements prĂ©vus par la configuration.
Description de l'image finale 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 -}}Une image supplĂ©mentaire qui s'exĂ©cute avec l'image principale sur le contour de dĂ©veloppement contient uniquement deux versions du site : la version du commit de rĂ©vision et la version racine du site (oĂč se trouvent les assets communs et, si vous vous en souvenez, les donnĂ©es de version). Ainsi, l'image supplĂ©mentaire diffĂšre de l'image principale uniquement par la section d'importation (et bien sĂ»r, le nom) :
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 }} Comme mentionnĂ© prĂ©cĂ©demment, l'artĂ©fact pour le commit de rĂ©vision ne sera gĂ©nĂ©rĂ© que lors de l'exĂ©cution de la variable d'environnement configurĂ©e. HASH_DE_REVIEW. On aurait pu ne pas gĂ©nĂ©rer l'image werf-dev, s'il n'y a pas de variable d'environnement HASH_DE_REVIEW, mais pour que des images Docker dans werf fonctionne pour l'image werf-dev, nous laisserons celle-ci ĂȘtre construite uniquement avec l'artĂ©fact de la version racine (de toute façon, elle est dĂ©jĂ construite), pour simplifier la structure du pipeline.
La construction est prĂȘte ! Passons au CI/CD et aux dĂ©tails importants.
Le pipeline dans GitLab CI et les particularités de la construction dynamique
Lors du démarrage de la construction, nous devons configurer les variables d'environnement utilisées dans werf.yaml. Cela ne concerne pas la variable REVIEW_SHA, que nous allons configurer lors de l'appel du pipeline à partir du webhook GitHub.
La génération des données externes nécessaires sera effectuée dans un script Bash generate_artifacts, qui générera deux artefacts pour le pipeline GitLab :
- fichier
releases.ymlavec des informations sur les versions, - fichier
common_envs.sh, contenant les variables d'environnement pour l'exportation.
Contenu du fichier generate_artifacts que vous trouverez dans notre . L'obtention des donnĂ©es elle-mĂȘme n'est pas le sujet de l'article, mais le fichier common_envs.sh est important pour nous, car il affecte le fonctionnement de werf. Exemple de son contenu :
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' Vous pouvez utiliser la sortie d'un tel script, par exemple, avec une fonction Bash source.
Et maintenant, la partie la plus intéressante. Pour que la construction et le déploiement de l'application fonctionnent correctement, il est nécessaire de faire en sorte que werf.yaml était identique au moins dans le cadre d'un pipeline. Si cette condition n'est pas remplie, les signatures des étapes, que werf calcule lors de la construction et, par exemple, lors du déploiement, seront différentes. Cela entraßnera une erreur de déploiement, car l'image requise pour le déploiement sera absente.
En d'autres termes, si pendant la construction de l'image du site les informations sur les versions et releases sont identiques, mais qu'au moment du déploiement une nouvelle version sort et que les variables d'environnement prennent d'autres valeurs, alors le déploiement échouera : l'artefact de la nouvelle version n'est pas encore construit.
Si la gĂ©nĂ©ration werf.yaml dĂ©pend de donnĂ©es externes (par exemple, d'une liste de versions actuelles, comme dans notre cas), alors la composition et les valeurs de ces donnĂ©es doivent ĂȘtre fixĂ©es dans le cadre du pipeline. Cela est particuliĂšrement important si les paramĂštres externes changent assez souvent.
Nous allons obtenir et fixer des donnĂ©es externes au cours de la premiĂšre Ă©tape du pipeline dans GitLab (Prebuild) et les transmettre ensuite sous forme de d'artefact GitLab CI. Cela permettra de lancer et de relancer les tĂąches du pipeline (construction, dĂ©ploiement, nettoyage) avec la mĂȘme configuration dans werf.yaml.
Le contenu de l'étape Prebuild fichiers .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 weeksAyant fixĂ© les donnĂ©es externes dans l'artefact, nous pouvons effectuer la construction et le dĂ©ploiement, en utilisant les Ă©tapes standard du pipeline GitLab CI : Build et Deploy. Nous lançons le pipeline via des webhooks Ă partir du dĂ©pĂŽt GitHub de werf (c'est-Ă -dire lors de changements dans le dĂ©pĂŽt GitHub). Les donnĂ©es pour cela peuvent ĂȘtre trouvĂ©es dans les propriĂ©tĂ©s du projet GitLab dans la section CI / CD Settings -> Pipeline triggers, puis nous crĂ©erons dans GitHub un Webhook correspondant (Settings -> Webhooks).
L'étape de construction ressemblera à ceci :
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 ajoutera dans l'Ă©tape de construction deux artefacts de l'Ă©tape Prebuild, donc nous exportons les variables avec les donnĂ©es d'entrĂ©e prĂ©parĂ©es Ă l'aide de la construction source common_envs.sh. Nous lançons lâĂ©tape de construction dans tous les cas, sauf pour le dĂ©marrage du pipeline programmĂ©. Un pipeline sera lancĂ© pour le nettoyage - il n'est pas nĂ©cessaire dâexĂ©cuter la construction dans ce cas.
Ă lâĂ©tape de dĂ©ploiement, nous allons dĂ©crire deux tĂąches - sĂ©parĂ©ment pour le dĂ©ploiement vers les environnements de production et de dĂ©veloppement, en utilisant un modĂšle YAML :
.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
Déployer en Production :
<<: *base_deploy
variables:
WERF_KUBE_CONTEXT: prod
environment:
name: production
url: werf.io
only:
refs:
- master
except:
variables:
- $REVIEW_SHA
refs:
- schedules
Déployer en Test :
<<: *base_deploy
variables:
WERF_KUBE_CONTEXT: dev
environment:
name: test
url: werf.test.flant.com
except:
refs:
- schedules
only:
variables:
- $REVIEW_SHA Les tĂąches diffĂšrent essentiellement par la spĂ©cification du contexte du cluster dans lequel werf doit effectuer le dĂ©ploiement (WERF_KUBE_CONTEXT), et par la dĂ©finition des variables d'environnement pour le contour (environment.name et environment.url), qui sont ensuite utilisĂ©es dans les modĂšles de Helm chart. Nous ne fournirons pas le contenu des modĂšles car il nây a rien dâintĂ©ressant pour le sujet en question, mais vous pouvez les trouver dans .
DerniĂšre touche
Ătant donnĂ© que les versions de werf sortent assez frĂ©quemment, de nouvelles images seront souvent construites, et le registre Docker continuera Ă croĂźtre. Il est donc impĂ©ratif de configurer un nettoyage automatique des images selon des politiques. C'est trĂšs simple Ă mettre en Ćuvre.
Pour cela, il faudra :
- Ajouter une étape de nettoyage dans
.gitlab-ci.yml; - Ajouter l'exécution périodique de la tùche de nettoyage ;
- Configurer une variable d'environnement avec le token d'accÚs en écriture.
Nous ajoutons une étape de nettoyage dans .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
Nous avons dĂ©jĂ vu presque tout cela un peu plus haut - juste pour le nettoyage, il est nĂ©cessaire de se connecter au registre Docker avec un token ayant des droits pour supprimer des images dans le registre Docker (le token gĂ©nĂ©rĂ© automatiquement pour les tĂąches GitLab CI n'a pas ces droits). Il faut obtenir le token Ă lâavance dans GitLab et en spĂ©cifier la valeur dans la variable d'environnement WERF_IMAGES_CLEANUP_PASSWORD du projet (CI/CD Settings -> Variables).
L'ajout de la tĂąche de nettoyage avec le programme requis se fait dans CI/CD ->
Schedules.
Tout : le projet dans Docker Registry ne va plus croßtre constamment à cause des images inutilisées.
En conclusion de la partie pratique, je rappelle que les listings complets de l'article sont disponibles dans :
- ;
- .
Résultat
- Nous avons obtenu une structure de construction logique : un artefact pour une version.
- La construction est universelle et n'exige pas de modifications manuelles lors de la sortie de nouvelles versions de werf : la documentation sur le site est mise Ă jour automatiquement.
- Deux images sont construites pour différents contours.
- Cela fonctionne rapidement, car le caching est utilisé au maximum : lors de la sortie d'une nouvelle version de werf ou d'un appel du webhook GitHub pour le commit de revue, seul l'artefact correspondant à la version modifiée est reconstruit.
- Il n'est pas nécessaire de penser à la suppression des images inutilisées : le nettoyage selon les politiques de werf maintiendra l'ordre dans Docker Registry.
Conclusions
- L'utilisation de werf permet Ă la construction d'ĂȘtre rapide grĂące Ă la mise en cache de la construction elle-mĂȘme ainsi qu'Ă la mise en cache lors du travail avec des dĂ©pĂŽts externes.
- Travailler avec des dépÎts Git externes évite de devoir cloner le dépÎt en entier à chaque fois ou d'inventer la roue avec une logique d'optimisation compliquée. werf utilise le cache et ne clone qu'une seule fois, puis utilise
fetchet uniquement si nécessaire. - La possibilité d'utiliser des modÚles Go dans le fichier de configuration de la construction
werf.yamlpermet de décrire une construction dont le résultat dépend de données externes. - L'utilisation du montage dans werf accélÚre considérablement la construction des artefacts - grùce à un cache qui est commun à tous les pipelines.
- werf permet de configurer facilement le nettoyage, ce qui est particuliĂšrement pertinent lors de constructions dynamiques.
P.S.
Lisez aussi dans notre blog :
- «»;
- «»;
- «»;
- «».
Source : habr.com
