Costruzione e deployment dinamico delle immagini Docker con werf utilizzando un sito di documentazione versionata

Abbiamo già parlato diverse volte del nostro strumento GitOps werf, e questa volta vorremmo condividere l'esperienza di costruzione di un sito con la documentazione del progetto — werf.io (la sua versione in russo è — ru.werf.io). Si tratta di un normale sito statico, ma la sua costruzione è interessante perché è realizzata utilizzando un numero dinamico di artefatti.

Costruzione e deployment dinamico delle immagini Docker con werf utilizzando un sito di documentazione versionata

Non approfondiremo i dettagli della struttura del sito: generazione del menu generale per tutte le versioni, pagine con informazioni sulle versioni, ecc. — ma ci concentreremo invece su domande e particolarità della costruzione dinamica e un po' sui processi associati di CI/CD.

Introduzione: come è strutturato il sito

Cominciamo col dire che la documentazione di werf è conservata insieme al suo codice. Questo pone determinati requisiti per lo sviluppo, che in generale vanno oltre l'ambito di questo articolo, ma possiamo almeno affermare che:

  • Le nuove funzionalità di werf non devono essere rilasciate senza un aggiornamento della documentazione e, viceversa, qualsiasi modifica alla documentazione implica il rilascio di una nuova versione di werf;
  • Il progetto è in costante sviluppo: nuove versioni possono essere rilasciate più volte al giorno;
  • Qualsiasi operazione manuale per il deployment del sito con una nuova versione della documentazione è quantomeno noiosa;
  • Nel progetto è adottato un approccio semantico versioning, con 5 canali di stabilità. Il processo di rilascio prevede un passaggio sequenziale delle versioni attraverso i canali in ordine crescente di stabilità: da alpha a rock-solid;
  • Il sito ha una versione in lingua russa, che "vive e si sviluppa" (cioè il cui contenuto viene aggiornato) parallelamente alla versione principale (cioè quella in lingua inglese).

Per nascondere all'utente tutta questa "cucina interna", offrendo ciò che "funziona semplicemente", abbiamo creato uno strumento separato per l'installazione e l'aggiornamento di werf — rappresenta multiwerf. È sufficiente specificare il numero di versione e il canale di stabilità che si è pronti a usare, e multiwerf verificherà se c'è una nuova versione disponibile sul canale e la scaricherà se necessario.

Nel menu di selezione delle versioni sul sito sono disponibili le ultime versioni di werf in ciascun canale. Di default, all'indirizzo werf.io/documentation viene aperta la versione del canale più stabile per l'ultimo rilascio — questa viene indicizzata dai motori di ricerca. La documentazione per il canale è disponibile a indirizzi separati (ad esempio, werf.io/v1.0-beta/documentation per il rilascio beta 1.0).

Pertanto, il sito offre le seguenti versioni:

  1. radice (aperta per impostazione predefinita),
  2. per ogni canale attivo di aggiornamenti per ogni rilascio (ad esempio, werf.io/v1.0-beta).

Per generare una versione specifica del sito, in generale è sufficiente eseguire la sua compilazione utilizzando Jekyll, eseguendo la relativa comando nella cartella /docs del repository werf (jekyll build), prima di passare al tag Git della versione necessaria.

Rimane solo da aggiungere che:

  • per la compilazione viene utilizzato lo strumento stesso (werf);
  • i processi CI/CD sono costruiti sulla base di GitLab CI;
  • e tutto ciò, naturalmente, funziona su Kubernetes.

Attività

Ora formuliamo compiti che tengano conto di tutta questa specificità:

  1. Dopo aver cambiato la versione di werf su qualsiasi canale di aggiornamenti la documentazione sul sito deve aggiornarsi automaticamente..
  2. Per lo sviluppo, è necessario avere la possibilità di visualizzare occasionalmente le versioni preliminari del sito..

La ricompilazione del sito deve essere eseguita dopo il cambio di versione su qualunque canale dei corrispondenti tag di Git, ma nel processo di costruzione dell'immagine ne avremo le seguenti peculiarità:

  • Poiché l'elenco delle versioni sui canali cambia, è necessario ricompilare solo la documentazione per i canali in cui è cambiata la versione. Ricompilare tutto da capo non è molto elegante.
  • L'insieme dei canali per le release può variare. In un certo momento, ad esempio, potrebbe non esserci una versione nei canali che siano più stabili della release early-access 1.1, ma nel tempo appariranno—non è il caso di cambiare manualmente la costruzione in tal caso?

Ciò significa che la costruzione dipende da dati esterni in continua evoluzione.

Implementazione

Scelta dell'approccio

Come alternativa, è possibile eseguire ciascuna versione necessaria in un pod separato in Kubernetes. Questa opzione implica un numero maggiore di oggetti nel cluster, che aumenterà con l'aumento delle release stabili di werf. Questo, a sua volta, implica una manutenzione più complessa: per ogni versione appare un proprio server HTTP, con carico ridotto. Certo, questo comporta anche maggiori spese in termini di risorse.

Noi abbiamo scelto la via assemblaggio di tutte le versioni necessarie in un'unica immagine. La statica compilata di tutte le versioni del sito si trova nel container con NGINX, e il traffico verso il Deployment corrispondente arriva tramite NGINX Ingress. La struttura semplice — applicazione stateless — consente di scalare facilmente il Deployment (a seconda del carico) utilizzando gli strumenti di Kubernetes.

Per essere più precisi, stiamo assemblando due immagini: una per l'ambiente di produzione e l'altra, aggiuntiva, per l'ambiente di sviluppo. L'immagine aggiuntiva è utilizzata (eseguita) solo nell'ambiente di sviluppo insieme a quella principale e contiene la versione del sito del commit di revisione, mentre l'instradamento tra di esse viene effettuato tramite risorse Ingress.

werf vs git clone e artefatti

Come già accennato, per generare la staticità del sito per una specifica versione della documentazione, è necessario effettuare una build passando al relativo tag del repository. Si potrebbe fare anche clonando il repository ogni volta durante la build, selezionando i tag appropriati da un elenco. Tuttavia, questa è un'operazione piuttosto dispendiosa in termini di risorse e richiede anche la scrittura di istruzioni non banali… Un'altra seria svantaggio è che, con questo approccio, non è possibile memorizzare nulla nella cache durante la build.

Qui ci viene in aiuto l'utilità werf, che implementa il caching intelligente e consente di utilizzare repository esterni. L'uso di werf per aggiungere codice da un repository accelera notevolmente la build, poiché werf effettua di fatto una sola clonazione del repository e poi esegue solo fetch se necessario. Inoltre, quando aggiungiamo dati da un repository, possiamo selezionare solo le directory necessarie (nel nostro caso si tratta della cartella docs), il che riduce notevolmente il volume dei dati aggiunti.

Poiché Jekyll è uno strumento progettato per compilare contenuti statici e non è necessario nell'immagine finale, sarebbe logico eseguire la compilazione in un artefatto werf, e nell'immagine finale importare solo il risultato della compilazione.

Scriviamo werf.yaml

Quindi, abbiamo deciso di compilare ogni versione in un artefatto werf separato. Tuttavia, noi non sappiamo quanti di questi artefatti ci saranno durante la costruzione, quindi non possiamo scrivere una configurazione di costruzione fissa (tecnicamente potremmo, ma non sarebbe molto efficiente).

werf consente di utilizzare modelli Go nel proprio file di configurazione (werf.yaml), e questo offre la possibilità di generare la configurazione «al volo» in base a dati esterni (proprio quello di cui abbiamo bisogno!). I dati esterni nel nostro caso sono le informazioni sulle versioni e sui rilasci, sulla base delle quali costruiamo il numero necessario di artefatti e otteniamo come risultato due immagini: werf-doc e werf-dev per l'esecuzione su diversi ambienti.

I dati esterni vengono trasmessi attraverso le variabili d'ambiente. Ecco il loro contenuto:

  • RELEASES — stringa con l'elenco dei rilasci e la relativa versione attuale di werf, sotto forma di elenco separato da spazi. %. Esempio: 1.0%v1.0.4-beta.20
  • CANALI — una stringa con l'elenco dei canali e la loro versione attuale di werf, in un elenco separato da spazi in formato %. Esempio: 1.0-beta%v1.0.4-beta.20 1.0-alpha%v1.0.5-alpha.22
  • VERSIONE_ROOT — la versione di rilascio di werf da visualizzare per impostazione predefinita sul sito (non è sempre necessario mostrare la documentazione per il numero di rilascio più alto). Esempio: v1.0.4-beta.20
  • REVIEW_SHA — l'hash del commit di revisione da cui assemblare la versione per l'ambiente di test.

Queste variabili saranno popolate nel pipeline di GitLab CI, e come specificato di seguito.

Per comodità, iniziamo definendo werf.yaml le variabili dei template Go, assegnando loro valori dalle variabili di ambiente:

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

La descrizione dell'artefatto per la compilazione della statica della versione del sito è sostanzialmente la stessa per tutti i casi necessari (inclusa la generazione della versione radice e della versione per l'ambiente dev). Pertanto, la estrarremo in un blocco separato utilizzando la funzione definire — per successivo riutilizzo tramite include. Il modello riceverà i seguenti argomenti:

  • Versione — la versione generata (nome del tag);
  • Canale — il nome del canale di aggiornamenti per cui viene generato l'artefatto;
  • Commit — l'hash del commit, se l'artefatto è generato per un commit di revisione;
  • conto.

Descrizione del modello dell'artefatto

{{- 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: "Installa Dipendenze"
    shell: bundle install
    args:
      executable: /bin/bash
      chdir: /app/docs
  beforeSetup:
{{- if .Commit }}
  - shell: echo "Revisione 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 }}

Il nome dell'artefatto deve essere unico. Possiamo ottenerlo, ad esempio, aggiungendo il nome del canale (il valore della variabile .Channel) come suffisso del nome dell'artefatto: artifact: doc-{{ .Channel }}. Ma è importante capire che durante l'importazione dagli artefatti sarà necessario riferirsi a nomi identici.

Nella descrizione dell'artefatto si utilizza una funzionalità di werf chiamata mounting. Il montaggio specificando la directory di servizio build_dir permette di mantenere la cache di Jekyll tra le esecuzioni della pipeline, il che accelera significativamente la ricompilazione..

Potresti anche aver notato l'uso del file releases.yml — questo è un file YAML contenente dati sulle release, richiesto da github.com (l'artefatto ottenuto durante l'esecuzione della pipeline). È necessario durante la compilazione del sito, ma nel contesto dell'articolo ci interessa perché il suo stato influisce su la ricompilazione di un singolo artefatto — l'artefatto della versione principale del sito (non è necessario negli altri artefatti).

Questo è realizzato tramite un operatore condizionale in etcdhelper, che non modificherà il servizio kube-dns. modelli Go e la costruzione {{ $Root.Files.Get "releases.yml" | sha256sum }} nella fase stadio. Funziona nel seguente modo: durante la costruzione dell'artefatto per la versione principale (variabile .Channel 0,68 Mbit/s. Le cose vanno ancora peggio a Bamfurlong (contea di Gloucestershire) — lì la velocità media di internet è root) l'hash del file releases.yml influisce sulla firma dell'intero stadio, poiché è una componente del nome del compito Ansible (parametro name). Pertanto, quando si modifica il contenuto file releases.yml l'artefatto corrispondente sarà ricostruito.

Si noti anche il lavoro con il repository esterno. Nell'immagine dell'artefatto di repository werf, viene aggiunta solo la cartella /docs, con dati che vengono aggiunti immediatamente in base ai parametri forniti, necessari per il tag o il commit di revisione.

Per utilizzare il modello dell'artefatto per generare la descrizione degli artefatti delle versioni dei canali e dei rilasci forniti, organizziamo un ciclo sulla variabile .WerfVersions in werf.yaml:

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

Dato che il ciclo genererà più artefatti (si spera), è necessario considerare il separatore tra di essi — la sequenza --- (per ulteriori informazioni sulla sintassi del file di configurazione, vedere il documentazione). Come già stabilito, durante la chiamata del modello nel ciclo si passano i parametri della versione, dell'URL e del contesto radice.

Analogamente, ma senza ciclo, chiamiamo il modello dell'artefatto per «casi speciali»: per la versione radice, così come per la versione del commit di revisione:

{{ 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 }}

Si prega di notare che l'artefatto per il commit di revisione verrà creato solo se la variabile .WerfReviewCommit.

Gli artefatti sono pronti — è ora di occuparsi dell'importazione!

L'immagine finale, destinata all'esecuzione su Kubernetes, è un normale NGINX con un file di configurazione del server aggiunto nginx.conf e la staticità dagli artefatti. Oltre all'artefatto della versione radice del sito, dobbiamo ripetere il ciclo sulla variabile .WerfVersions per importare gli artefatti delle versioni dei canali e delle release + rispettare la regola di denominazione degli artefatti che abbiamo stabilito in precedenza. Poiché ogni artefatto contiene versioni del sito per due lingue, li importeremo nei luoghi previsti dalla configurazione.

Descrizione dell'immagine finale di werf-doc

immagine: werf-doc
provenienza: nginx:stable-alpine
ansible:
  setup:
  - name: "Configura /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 -}}

Un'immagine aggiuntiva, che viene eseguita insieme a quella principale nel circuito di sviluppo, contiene solo due versioni del sito: la versione dal commit di revisione e la versione principale del sito (lì ci sono le risorse comuni e, se ricordi, i dati sulle release). Pertanto, l'immagine aggiuntiva si differenzierà solo per la sezione di importazione (e, ovviamente, per il nome):

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

Come già notato in precedenza, l'ar­tefatto per il review commit verrà generato solo quando viene impostata la variabile d'ambiente REVIEW_SHA. In effetti, non sarebbe necessario generare l'immagine werf-dev se non ci fosse una variabile d'ambiente REVIEW_SHA, ma per fare in modo che la pulizia delle politiche delle immagini Docker in werf funzioni per l'immagine werf-dev, lo lasceremo costruire solo con l'ar­tefatto della versione principale (del resto è già stato costruito), per semplificare la struttura del pipeline.

La costruzione è pronta! Passiamo al CI/CD e ai dettagli importanti.

Il pipeline in GitLab CI e le caratteristiche della costruzione dinamica

All'avvio della costruzione, dobbiamo impostare le variabili d'ambiente utilizzate in werf.yaml. Questo non riguarda la variabile REVIEW_SHA, che imposteremo quando chiameremo il pipeline dall'hook di GitHub.

La generazione dei necessari dati esterni sarà spostata in uno script Bash generate_artifacts, che genererà due artefatti per il pipeline di GitLab:

  • file releases.yml con i dati delle versioni,
  • file common_envs.sh, contenente variabili d'ambiente per l'esportazione.

Il contenuto del file generate_artifacts lo troverete nel nostro repository di esempi. L'ottenimento dei dati non è l'oggetto dell'articolo, ma il file common_envs.sh è importante per noi, poiché da esso dipende il funzionamento di werf. Un esempio del suo contenuto:

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'

È possibile utilizzare l'output di questo script, ad esempio, con una funzione Bash source.

E ora la parte più interessante. Affinché sia la build che il deployment dell'applicazione funzionino correttamente, è necessario assicurarsi che werf.yaml sia uguale almeno all'interno di un pipeline. Se questa condizione non è soddisfatta, le firme delle fasi che werf calcola durante la build e, ad esempio, il deployment saranno diverse. Ciò porterà a un errore di deployment, poiché l'immagine necessaria per il deployment sarà assente.

In altre parole, se durante la creazione dell'immagine del sito le informazioni sui rilasci e le versioni saranno una, e nel momento del deployment verrà rilasciata una nuova versione con variabili d'ambiente aventi valori diversi, il deployment terminerà con un errore: poiché l'artefatto della nuova versione non è stato ancora creato.

Se la generazione werf.yaml dipende da dati esterni (ad esempio, un elenco delle versioni attuali, come nel nostro caso), quindi la composizione e i valori di tali dati devono essere registrati all'interno del pipeline. Questo è particolarmente importante se i parametri esterni cambiano abbastanza frequentemente.

Noi riceveremo e registreremo dati esterni nella prima fase del pipeline in GitLab (Prebuild) e li passeremo ulteriormente come artefatto GitLab CI. Questo consentirà di eseguire e riavviare i compiti del pipeline (build, deploy, cleanup) con la stessa configurazione in werf.yaml.

Contenuto della fase Prebuild file .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 weeks

Registrando i dati esterni nell'artefatto, è possibile eseguire la build e il deploy utilizzando le fasi standard del pipeline GitLab CI: Build e Deploy. Il pipeline stesso viene avviato tramite hooks dal repository GitHub werf (cioè, quando ci sono modifiche nel repository su GitHub). I dati per questi possono essere presi nelle proprietà del progetto GitLab nella sezione CI / CD Settings -> Pipeline triggers, e poi creeremo in GitHub il corrispondente Webhook (Settings -> Webhooks).

La fase di build apparirà come segue:

Costruire:
  fase: build
  script:
    - tipo multiwerf && . $(multiwerf use 1.0 alpha --as-file)
    - tipo werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
    - source common_envs.sh
    - werf build-and-publish --stages-storage :local
  eccetto:
    refs:
      - schedules
  dipendenze:
    - Prebuild

GitLab aggiungerà due artefatti alla fase di build dalla fase Prebuild, quindi esportiamo le variabili con i dati di input preparati utilizzando la costruzione source common_envs.sh. Eseguiamo la fase di build in tutti i casi, tranne quando il pipeline viene avviato secondo il programma. Il pipeline sarà avviato secondo programma per la pulizia — non è necessario eseguire la build in questo caso.

Nella fase di deploy descriveremo due job — uno separato per il deploy su contorni di produzione e di sviluppo, utilizzando un modello 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

Le attività si differenziano principalmente per l'indicazione del contesto del cluster in cui werf deve eseguire il deployment (WERF_KUBE_CONTEXT), e la configurazione delle variabili d'ambiente del contesto (environment.name e environment.url), utilizzate poi nei template del chart Helm. Non approfondiremo il contenuto dei template, poiché non ci sono elementi interessanti per l'argomento in questione, ma puoi trovarli nel repository dell'articolo.

Touch Finale

Poiché le versioni di werf vengono rilasciate piuttosto frequentemente, ci saranno spesso nuovi build e il Docker Registry continuerà a crescere. È quindi fondamentale impostare una pulizia automatica delle immagini secondo le politiche. È un'operazione molto semplice da realizzare.

Per l'implementazione sarà necessario:

  • Aggiungere una fase di pulizia in .gitlab-ci.yml;
  • Impostare l'esecuzione periodica del compito di pulizia;
  • Configurare la variabile d'ambiente con il token di accesso in scrittura.

Aggiungiamo la fase di pulizia 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

Quasi tutto ciò l'abbiamo già visto poco sopra — solo che per la pulizia è necessario autenticarsi preventivamente nel Docker Registry con un token che abbia diritti di cancellazione delle immagini (il token automaticamente fornito dal compito di GitLab CI non ha tali diritti). Il token deve essere creato in anticipo in GitLab e il suo valore deve essere specificato nella variabile d'ambiente WERF_IMAGES_CLEANUP_PASSWORD progetto (Impostazioni CI/CD -> Variabili).

L'aggiunta del compito di pulizia con la programmazione necessaria si svolge in CI/CD ->
Programmazioni
.

Tutto: il progetto nel Docker Registry non crescerà più continuamente a causa di immagini non utilizzate.

In conclusione della parte pratica ricordo che le liste complete dell'articolo sono disponibili in Git:

Risultato

  1. Abbiamo ottenuto una struttura di build logica: un artefatto per ogni versione.
  2. La build è universale e non richiede modifiche manuali con l'uscita di nuove versioni di werf: la documentazione sul sito si aggiorna automaticamente.
  3. Vengono costruite due immagini per diversi ambienti.
  4. Funziona rapidamente, utilizzando al massimo la cache: con il rilascio di una nuova versione di werf o attivando il webhook di GitHub per il commit di revisione, si ricompila solo l'artefatto corrispondente con la versione modificata.
  5. Non è necessario pensare a rimuovere le immagini non utilizzate: la pulizia secondo le politiche di werf mantiene in ordine il Docker Registry.

Conclusioni

  • L'uso di werf consente alla build di funzionare rapidamente grazie alla cache sia della build stessa che alla cache durante il lavoro con i repository esterni.
  • Lavorare con repository Git esterni elimina la necessità di clonare completamente il repository ogni volta o di inventare la logica di ottimizzazione. werf utilizza la cache e clona una sola volta, poi utilizza fetch e solo se necessario.
  • La possibilità di utilizzare i template Go nel file di configurazione della build werf.yaml permette di descrivere una build il cui risultato dipende da dati esterni.
  • L'uso del montaggio in werf accelera significativamente la raccolta degli artefatti, grazie a una cache condivisa tra tutti i pipeline.
  • werf consente una facile configurazione della pulizia, particolarmente utile durante le costruzioni dinamiche.

P.S.

Leggete anche nel nostro blog:

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster