Assemblage dynamique et déploiement d'images Docker avec werf en utilisant l'exemple d'un site de documentation versionné

Nous avons déjà parlé plus d'une fois de notre outil GitOps. cour, et cette fois nous aimerions partager notre expérience dans l'assemblage du site avec la documentation du projet lui-même - werf.io (sa version russe est fr.werf.io). Il s'agit d'un site statique ordinaire, mais son assemblage est intéressant dans la mesure où il est construit à l'aide d'un nombre dynamique d'artefacts.

Assemblage dynamique et déploiement d'images Docker avec werf en utilisant l'exemple d'un site de documentation versionné

Entrez dans les nuances de la structure du site : génération d'un menu commun à toutes les versions, de pages d'informations sur les versions, etc. - nous n'allons pas. Concentrons-nous plutôt sur les problèmes et les fonctionnalités de l'assemblage dynamique et un peu sur les processus CI/CD qui l'accompagnent.

Introduction : comment fonctionne le site

Pour commencer, la documentation Werf est stockée avec son code. Cela impose certaines exigences de développement qui dépassent généralement le cadre de cet article, mais au minimum on peut dire que :

  • Les nouvelles fonctions werf ne doivent pas être publiées sans mise à jour de la documentation et, à l'inverse, toute modification dans la documentation implique la sortie d'une nouvelle version de werf ;
  • Le projet a un développement assez intensif : de nouvelles versions peuvent être publiées plusieurs fois par jour ;
  • Toutes les opérations manuelles pour déployer un site avec une nouvelle version de la documentation sont pour le moins fastidieuses ;
  • Le projet adopte une approche sémantique gestion des versions, avec 5 canaux de stabilité. Le processus de publication implique le passage séquentiel des versions à travers les canaux par ordre de stabilité croissante : d'alpha à solide comme le roc ;
  • Le site dispose d'une version en langue russe, qui « vit et se développe » (c'est-à-dire dont le contenu est mis à jour) parallèlement à la version principale (c'est-à-dire en anglais).

Pour cacher toute cette « cuisine intérieure » à l'utilisateur, en lui offrant quelque chose qui « fonctionne », nous avons fait outil d'installation et de mise à jour Werf séparé - Est multiwerf. Il vous suffit de spécifier le numéro de version et le canal de stabilité que vous êtes prêt à utiliser, et multiwerf vérifiera s'il y a 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 Web, les dernières versions de werf sont disponibles dans chaque canal. Par défaut, par adresse werf.io/documentation la version du canal le plus stable pour la dernière version s'ouvre - elle est également indexée par les moteurs de recherche. La documentation du canal est disponible à des adresses distinctes (par exemple, werf.io/v1.0-beta/documentation pour la version bêta 1.0).

Au total, le site dispose des versions suivantes :

  1. racine (s'ouvre par défaut),
  2. pour chaque canal de mise à jour actif de chaque version (par exemple, werf.io/v1.0-bêta).

Pour générer une version spécifique d'un site, en général, il suffit de le compiler à l'aide de Jekyllen exécutant dans le répertoire /docs commande correspondante du référentiel werf (jekyll build), après être passé à la balise Git de la version requise.

Il ne reste plus qu'à ajouter que :

  • l'utilitaire lui-même (werf) est utilisé pour l'assemblage ;
  • Les processus CI/CD sont construits sur la base de GitLab CI ;
  • et tout cela, bien sûr, fonctionne dans Kubernetes.

Tâches

Formulons maintenant des tâches qui prennent en compte toutes les spécificités décrites :

  1. Après avoir changé la version de Werf sur n'importe quel canal de mise à jour la documentation sur le site doit être automatiquement mise à jour.
  2. Pour le développement, il faut parfois être capable de voir les versions préliminaires du site.

Le site doit être recompilé après avoir changé la version sur n'importe quel canal à partir des balises Git correspondantes, mais dans le processus de construction de l'image, nous obtiendrons les fonctionnalités suivantes :

  • La liste des versions sur les chaînes changeant, il suffit de reconstruire la documentation des chaînes dont la version a changé. Après tout, tout reconstruire n’est pas très agréable.
  • L'ensemble des canaux pour les versions peut changer. À un moment donné, par exemple, il se peut qu'il n'y ait pas de version sur les chaînes plus stable que la version 1.1 à accès anticipé, mais avec le temps, elles apparaîtront - dans ce cas, ne devriez-vous pas modifier l'assemblage manuellement ?

Il s'avère que l'assemblage dépend de la modification des données externes.

exécution

Choisir une approche

Vous pouvez également exécuter chaque version requise en tant que pod distinct dans Kubernetes. Cette option implique un plus grand nombre d'objets dans le cluster, qui augmentera avec l'augmentation du nombre de versions de werf stables. Et cela, à son tour, implique une maintenance plus complexe : chaque version possède son propre serveur HTTP, et avec une petite charge. Bien entendu, cela entraîne également des coûts de ressources plus élevés.

Nous avons pris le même chemin assembler toutes les versions nécessaires dans une seule image. Les statistiques compilées de toutes les versions du site sont situées dans un conteneur avec NGINX, et le trafic vers le déploiement correspondant passe par NGINX Ingress. Une structure simple - une application sans état - vous permet de faire évoluer facilement le déploiement (en fonction de la charge) à l'aide de Kubernetes lui-même.

Pour être plus précis, nous collectons deux images : une pour le circuit de production, la seconde est une image supplémentaire pour le circuit de développement. L'image supplémentaire est utilisée (lancée) uniquement sur le circuit de développement avec l'image principale et contient la version du site issue de la validation de révision, et le routage entre elles est effectué à l'aide des ressources Ingress.

werf vs git clone et artefacts

Comme déjà mentionné, afin de générer des statistiques de site pour une version spécifique de la documentation, vous devez construire en basculant vers la balise de référentiel appropriée. Vous pouvez également le faire en clonant le référentiel à chaque construction, en sélectionnant les balises appropriées dans une liste. Cependant, il s'agit d'une opération assez gourmande en ressources et, de plus, nécessite l'écriture d'instructions non triviales... Un autre inconvénient sérieux est qu'avec cette approche, il n'y a aucun moyen de mettre en cache quelque chose pendant l'assemblage.

Ici, l'utilitaire werf lui-même vient à notre aide, en mettant en œuvre mise en cache intelligente et vous permettant d'utiliser référentiels externes. Utiliser werf pour ajouter du code à partir du référentiel accélérera considérablement la construction, car werf clone essentiellement le référentiel une fois, puis s'exécute seulement fetch si nécessaire. De plus, lors de l'ajout de données du référentiel, nous pouvons sélectionner uniquement les répertoires nécessaires (dans notre cas il s'agit du répertoire docs), ce qui réduira considérablement la quantité de données ajoutées.

Puisque Jekyll est un outil conçu pour compiler des données statiques et qu'il n'est pas nécessaire dans l'image finale, il serait logique de compiler dans artefact de Werf, et dans l'image finale importer uniquement le résultat de la compilation.

Nous écrivons werf.yaml

Nous avons donc décidé de compiler chaque version dans un artefact werf distinct. Cependant, nous nous ne savons pas combien de ces artefacts il y aura lors de l'assemblage, nous ne pouvons donc pas écrire une configuration de build fixe (à proprement parler, nous le pouvons toujours, mais cela ne sera pas entièrement efficace).

werf vous permet d'utiliser Aller aux modèles dans votre fichier de configuration (werf.yaml), ce qui permet générer la configuration à la volée en fonction de données externes (ce dont vous avez besoin !). Les données externes dans notre cas sont des informations sur les versions et les versions, sur la base desquelles nous collectons le nombre requis d'artefacts et obtenons ainsi deux images : werf-doc и werf-dev courir sur des circuits différents.

Les données externes sont transmises via des variables d'environnement. Voici leur composition :

  • RELEASES — une ligne avec une liste de versions et la version actuelle correspondante de werf, sous la forme d'une liste de valeurs séparées par des espaces au format <НОМЕР_РЕЛИЗА>%<НОМЕР_ВЕРСИИ>. Exemple: 1.0%v1.0.4-beta.20
  • CHANNELS — une ligne avec une liste de chaînes et la version actuelle correspondante de werf, sous la forme d'une liste de valeurs séparées par des espaces au format <КАНАЛ>%<НОМЕР_ВЕРСИИ>. Exemple: 1.0-beta%v1.0.4-beta.20 1.0-alpha%v1.0.5-alpha.22
  • ROOT_VERSION — version de werf à afficher par défaut sur le site (il n'est pas toujours nécessaire d'afficher la documentation par numéro de version le plus élevé). Exemple: v1.0.4-beta.20
  • REVIEW_SHA - hachage du commit de révision à partir duquel vous devez créer la version pour la boucle de test.

Ces variables seront renseignées dans le pipeline GitLab CI, et comment exactement est écrit ci-dessous.

Tout d’abord, par commodité, nous définissons dans werf.yaml Accédez aux variables du modèle, en leur attribuant des valeurs à partir des variables d'environnement :

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

La description de l'artefact pour compiler la version statique du site est généralement la même dans tous les cas dont nous avons besoin (y compris la génération de la version racine, ainsi que la version pour le circuit de développement). Par conséquent, nous allons le déplacer dans un bloc séparé à l'aide de la fonction define - pour une réutilisation ultérieure en utilisant include. Nous passerons les arguments suivants au modèle :

  • Version — 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 — hachage de validation, si l'artefact est généré pour une validation de révision ;
  • le 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: "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 }}

Le nom de l'artefact doit être unique. Nous pouvons y parvenir, par exemple, en ajoutant le nom du canal (la valeur de la variable .Channel) comme suffixe au nom de l'artefact : artifact: doc-{{ .Channel }}. Mais vous devez comprendre que lors de l'importation à partir d'artefacts, vous devrez faire référence aux mêmes noms.

Lors de la description d'un artefact, la fonctionnalité werf suivante est utilisée : montage. Montage indiquant le répertoire des services build_dir vous permet de sauvegarder le cache Jekyll entre les exécutions du pipeline, ce qui accélère considérablement le remontage.

Vous avez peut-être également remarqué l'utilisation du fichier releases.yml est un fichier YAML avec les données de version demandées à Github.com (un artefact obtenu lors de l'exécution d'un pipeline). Il est nécessaire lors de la compilation du site, mais dans le cadre de l'article cela nous intéresse car cela dépend de son état réassemblage d'un seul artefact — un artefact de la version racine du site (il n'est pas nécessaire dans les autres artefacts).

Ceci est implémenté à l'aide de l'instruction conditionnelle if Aller aux modèles et aux conceptions {{ $Root.Files.Get "releases.yml" | sha256sum }} sur scène étapes. Cela fonctionne comme suit : lors de la construction d'un artefact pour la version racine (variable .Channel est root) hachage de fichier releases.yml affecte la signature de toute l'étape, puisqu'elle fait partie du nom de la tâche Ansible (paramètre name). Ainsi, lors du changement contenu dossier releases.yml l'artefact correspondant sera remonté.

Veuillez également faire attention à travailler avec un référentiel externe. À l'image d'un artefact de référentiel Werf, seul le répertoire est ajouté /docs, et en fonction des paramètres transmis, les données de la balise ou de la validation de révision requise sont ajoutées immédiatement.

Pour utiliser le modèle d'artefact afin de générer une description de l'artefact des versions transférées des chaînes et des releases, nous organisons une boucle sur la variable .WerfVersions в werf.yaml:

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

Parce que la boucle va générer plusieurs artefacts (on l'espère), il faut prendre en compte le séparateur entre eux - la séquence --- (Pour plus d'informations sur la syntaxe du fichier de configuration, voir documentation). Comme défini précédemment, lors de l'appel d'un modèle en boucle, nous transmettons les paramètres de version, l'URL et le contexte racine.

De la même manière, mais sans boucle, nous appelons le modèle d'artefact pour « cas particuliers » : pour la version racine, ainsi que la version issue 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 }}

Veuillez noter que l'artefact pour la validation de révision ne sera construit que si la variable est définie .WerfReviewCommit.

Les artefacts sont prêts – il est temps de commencer à importer !

L'image finale, conçue pour fonctionner sur Kubernetes, est un NGINX standard avec un fichier de configuration du serveur ajouté nginx.conf et statique des artefacts. En plus de l'artefact de la version racine du site, il faut répéter la boucle sur la variable .WerfVersions pour importer des artefacts des versions de canal et de version + suivez la règle de dénomination des artefacts que nous avons adoptée plus tôt. Puisque chaque artefact stocke des versions du site pour deux langues, nous les importons aux 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 -}}

L'image supplémentaire, qui, avec l'image principale, est lancée sur le circuit de développement, ne contient que deux versions du site : la version du commit de révision et la version racine du site (il y a des actifs généraux et, si vous vous en souvenez , publier des données). Ainsi, l'image supplémentaire ne différera de l'image principale que par la section d'importation (et, bien sûr, par 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 indiqué ci-dessus, l'artefact pour la validation de révision sera généré uniquement lorsque la variable d'environnement définie est exécutée. REVIEW_SHA. Il serait possible de ne pas générer du tout l'image werf-dev s'il n'y a pas de variable d'environnement REVIEW_SHA, mais pour nettoyage par politiques Les images Docker dans werf ont fonctionné pour l'image werf-dev, nous la laisserons construite uniquement avec l'artefact de la version racine (elle est déjà construite de toute façon), pour simplifier la structure du pipeline.

L'assemblage est prêt ! Passons au CI/CD et aux nuances importantes.

Pipeline dans GitLab CI et fonctionnalités de construction dynamique

Lors de l'exécution de la build, nous devons définir les variables d'environnement utilisées dans werf.yaml. Cela ne s'applique pas à la variable REVIEW_SHA, que nous définirons lors de l'appel du pipeline depuis le hook GitHub.

Nous générerons les données externes nécessaires dans un script Bash generate_artifacts, qui générera deux artefacts de pipeline GitLab :

  • файл releases.yml avec les données de sortie,
  • файл common_envs.sh, contenant les variables d'environnement à exporter.

Contenu du fichier generate_artifacts vous trouverez dans notre référentiels avec exemples. La réception des données elle-même n'est pas le sujet de l'article, mais le fichier common_envs.sh est important pour nous, parce que le travail du werf en dépend. Un 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, en utilisant la fonction Bash source.

Vient maintenant la partie amusante. Pour que la construction et le déploiement de l'application fonctionnent correctement, il est nécessaire de s'assurer que werf.yaml était le même au moins dans un seul pipeline. Si cette condition n'est pas remplie, alors les signatures des étapes calculées par Werf lors de l'assemblage et, par exemple, du déploiement, seront différentes. Cela entraînera une erreur de déploiement, car... l'image requise pour le déploiement sera manquante.

En d'autres termes, si lors de l'assemblage de l'image du site les informations sur les versions et les versions sont les mêmes, et qu'au moment du déploiement une nouvelle version est publiée et que les variables d'environnement ont des valeurs différentes, alors le déploiement échouera avec une erreur : après tout, l'artefact de la nouvelle version n'a pas encore été construit.

Si génération werf.yaml dépend de données externes (par exemple, une liste des versions actuelles, comme dans notre cas), alors la composition et les valeurs de ces données doivent être enregistrées dans le pipeline. Ceci est particulièrement important si les paramètres externes changent assez souvent.

Nous allons recevoir et enregistrer des données externes à la première étape du pipeline dans GitLab (Pré-construire) et les transmettre ensuite sous la forme Artefact GitLab CI. Cela vous permettra d'exécuter et de redémarrer les tâches de pipeline (construction, déploiement, nettoyage) avec la même configuration dans werf.yaml.

Contenu de la scène Pré-construire dossier .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

Après avoir capturé les données externes dans l'artefact, vous pouvez créer et déployer à l'aide des étapes standard du pipeline GitLab CI : créer et déployer. Nous lançons le pipeline lui-même à l'aide des hooks du référentiel werf GitHub (c'est-à-dire lorsqu'il y a des modifications dans le référentiel sur GitHub). Les données les concernant peuvent être trouvées dans les propriétés du projet GitLab dans la section Paramètres CI/CD -> Déclencheurs de pipeline, puis créez le Webhook correspondant dans GitHub (Paramètres -> 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 deux artefacts de l'étape à l'étape de construction Pré-construire, nous exportons donc des variables avec des données d'entrée préparées en utilisant la construction source common_envs.sh. Nous démarrons la phase de construction dans tous les cas, sauf pour le lancement du pipeline selon un planning. Conformément au calendrier, nous exécuterons un pipeline pour le nettoyage - dans ce cas, il n'est pas nécessaire d'effectuer un assemblage.

Au stade du déploiement, nous décrirons deux tâches - séparément pour le déploiement sur les circuits de production et de développement, à l'aide d'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

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

Les tâches diffèrent essentiellement uniquement par l'indication du contexte de cluster dans lequel werf doit effectuer le déploiement (WERF_KUBE_CONTEXT), et définir les variables d'environnement de boucle (environment.name и environment.url), qui sont ensuite utilisés dans les modèles de graphiques Helm. Nous ne fournirons pas le contenu des modèles, car... il n'y a rien d'intéressant là-bas pour le sujet en question, mais vous pouvez les trouver dans référentiels pour l'article.

Touche finale

Étant donné que les versions werf sont publiées assez souvent, de nouvelles images seront créées fréquemment et le registre Docker grandira constamment. Par conséquent, il est impératif de configurer le nettoyage automatique des images en fonction des politiques. C'est très facile à faire.

Pour mettre en œuvre, vous aurez besoin de :

  • Ajouter une étape de nettoyage à .gitlab-ci.yml;
  • Ajouter l'exécution périodique d'une tâche de nettoyage ;
  • Configurez une variable d'environnement avec un jeton d'accès en écriture.

Ajout d'une étape de nettoyage à .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 - uniquement pour le nettoyer, vous devez d'abord vous connecter au registre Docker avec un jeton qui a le droit de supprimer des images dans le registre Docker (le jeton de tâche GitLab CI émis automatiquement ne le fait pas avoir de tels droits). Le token doit être créé dans GitLab au préalable et sa valeur doit être spécifiée dans la variable d'environnement WERF_IMAGES_CLEANUP_PASSWORD projet (Paramètres CI/CD -> Variables).

L'ajout d'une tâche de nettoyage avec le planning requis se fait dans CI/CD ->
Horaires
.

Ça y est : un projet dans le Docker Registry ne se développera plus constamment à partir d'images inutilisées.

A la fin de la partie pratique, je vous rappelle que les listings complets de l'article sont disponibles dans Git:

Résultat

  1. Nous avons reçu une structure d'assemblage logique : un artefact par version.
  2. L'assemblage est universel et ne nécessite pas de modifications manuelles lors de la sortie de nouvelles versions de werf : la documentation sur le site est automatiquement mise à jour.
  3. Deux images sont assemblées pour des contours différents.
  4. Cela fonctionne rapidement, car La mise en cache est utilisée autant que possible - lorsqu'une nouvelle version de werf est publiée ou qu'un hook GitHub est appelé pour une validation de révision, seul l'artefact correspondant avec la version modifiée est reconstruit.
  5. Pas besoin de penser à supprimer les images inutilisées : le nettoyage conformément aux politiques de Werf maintiendra le registre Docker en ordre.

résultats

  • L'utilisation de werf permet à l'assembly de fonctionner rapidement grâce à la mise en cache de l'assembly lui-même et à la mise en cache lors de l'utilisation de référentiels externes.
  • Travailler avec des référentiels Git externes élimine le besoin de cloner l'intégralité du référentiel à chaque fois ou de réinventer la roue avec une logique d'optimisation délicate. werf utilise un cache et effectue le clonage une seule fois, puis utilise fetch et seulement lorsque cela est nécessaire.
  • Possibilité d'utiliser des modèles Go dans le fichier de configuration de build werf.yaml permet de décrire un assemblage dont le résultat dépend de données externes.
  • L'utilisation de mount dans werf accélère considérablement la collecte des artefacts - grâce au cache, commun à tous les pipelines.
  • werf facilite la configuration du nettoyage, ce qui est particulièrement important lors de la construction dynamique.

PS

A lire aussi sur notre blog :

Source: habr.com

Ajouter un commentaire