Assemblaggio dinamico e distribuzione di immagini Docker con werf utilizzando l'esempio di un sito di documentazione con versione

Abbiamo già parlato più di una volta del nostro strumento GitOps. werf, e questa volta vorremmo condividere la nostra esperienza nell'assemblare il sito con la documentazione del progetto stesso - werf.io (la sua versione russa è en.werf.io). Questo è un normale sito statico, ma il suo assemblaggio è interessante in quanto è costruito utilizzando un numero dinamico di artefatti.

Assemblaggio dinamico e distribuzione di immagini Docker con werf utilizzando l'esempio di un sito di documentazione con versione

Approfondisci le sfumature della struttura del sito: generazione di un menu comune per tutte le versioni, pagine con informazioni sulle versioni, ecc. - noi non. Concentriamoci invece sui problemi e sulle caratteristiche dell'assemblaggio dinamico e un po' sui processi CI/CD che lo accompagnano.

Introduzione: come funziona il sito

Per cominciare, la documentazione werf viene archiviata insieme al relativo codice. Ciò impone determinati requisiti di sviluppo che generalmente vanno oltre lo scopo di questo articolo, ma come minimo si può dire che:

  • Non dovrebbero essere rilasciate nuove funzioni werf senza aggiornare la documentazione e, viceversa, eventuali modifiche alla documentazione implicano il rilascio di una nuova versione di werf;
  • Il progetto ha uno sviluppo abbastanza intenso: le nuove versioni possono essere rilasciate più volte al giorno;
  • Qualsiasi operazione manuale per distribuire un sito con una nuova versione della documentazione è quantomeno noiosa;
  • Il progetto adotta un approccio semantico controllo delle versioni, con 5 canali di stabilità. Il processo di rilascio prevede il passaggio sequenziale delle versioni attraverso canali in ordine di stabilità crescente: da alfa a solido come una roccia;
  • Il sito ha una versione in lingua russa, che “vive e si sviluppa” (cioè il cui contenuto viene aggiornato) parallelamente alla versione principale (cioè in lingua inglese).

Per nascondere all'utente tutta questa “cucina interiore”, offrendogli qualcosa che “funzioni e basta”, lo abbiamo fatto strumento separato di installazione e aggiornamento werf - E ' multiwerf. Devi solo specificare il numero di versione e il canale di stabilità che sei pronto per l'uso, e multiwerf controllerà se c'è una nuova versione sul canale e la scaricherà se necessario.

Nel menu di selezione della versione sul sito web, in ciascun canale sono disponibili le ultime versioni di werf. Per impostazione predefinita, per indirizzo werf.io/documentation si apre la versione del canale più stabile per l'ultima versione, inoltre è indicizzata dai motori di ricerca. La documentazione per il canale è disponibile a indirizzi separati (ad esempio, werf.io/v1.0-beta/documentation per la versione beta 1.0).

In totale, il sito ha le seguenti versioni disponibili:

  1. root (si apre per impostazione predefinita),
  2. per ciascun canale di aggiornamento attivo di ciascuna release (ad esempio, werf.io/v1.0-beta).

Per generare una versione specifica di un sito, in generale, è sufficiente compilarlo utilizzando Jekylleseguendo nella directory /docs comando corrispondente del repository werf (jekyll build), dopo essere passati al tag Git della versione richiesta.

Non resta che aggiungere che:

  • l'utilità stessa (werf) viene utilizzata per l'assemblaggio;
  • I processi CI/CD sono costruiti sulla base di GitLab CI;
  • e tutto questo, ovviamente, funziona in Kubernetes.

compiti

Ora formuliamo attività che tengano conto di tutte le specifiche descritte:

  1. Dopo aver modificato la versione werf su qualsiasi canale di aggiornamento la documentazione presente sul sito dovrebbe essere aggiornata automaticamente.
  2. Per lo sviluppo devi essere in grado di farlo a volte visualizzare le versioni di anteprima del sito.

Il sito deve essere ricompilato dopo aver modificato la versione su qualsiasi canale dai tag Git corrispondenti, ma nel processo di creazione dell'immagine otterremo le seguenti funzionalità:

  • Poiché l'elenco delle versioni sui canali cambia, è necessario ricostruire solo la documentazione per i canali in cui la versione è cambiata. Dopotutto, ricostruire tutto da capo non è molto bello.
  • L'insieme dei canali per i rilasci potrebbe cambiare. Ad un certo punto, ad esempio, potrebbe non esserci una versione più stabile sui canali rispetto alla versione 1.1 ad accesso anticipato, ma col tempo appariranno: in questo caso, non dovresti modificare manualmente l'assembly?

Si scopre che l'assemblaggio dipende dalla modifica dei dati esterni.

implementazione

Scegliere un approccio

In alternativa, puoi eseguire ciascuna versione richiesta come pod separato in Kubernetes. Questa opzione implica un numero maggiore di oggetti nel cluster, che aumenterà con l'aumento del numero di rilasci werf stabili. E questo, a sua volta, implica una manutenzione più complessa: ogni versione ha il proprio server HTTP e con un carico ridotto. Naturalmente ciò comporta anche maggiori costi in termini di risorse.

Abbiamo fatto la stessa strada assemblando tutte le versioni necessarie in un'unica immagine. Le statistiche compilate di tutte le versioni del sito si trovano in un contenitore con NGINX e il traffico verso il Deployment corrispondente arriva attraverso NGINX Ingress. Una struttura semplice, un'applicazione stateless, consente di scalare facilmente la distribuzione (a seconda del carico) utilizzando Kubernetes stesso.

Per essere più precisi stiamo raccogliendo due immagini: una per il circuito di produzione, la seconda è un'ulteriore per il circuito di dev. L'immagine aggiuntiva viene utilizzata (lanciata) solo sul circuito di sviluppo insieme a quello principale e contiene la versione del sito dal commit di revisione, e il routing tra di loro viene eseguito utilizzando le risorse Ingress.

werf vs git clone e artefatti

Come già accennato, per generare le statistiche del sito per una versione specifica della documentazione, è necessario creare passando al tag del repository appropriato. Puoi anche farlo clonando il repository ogni volta che crei, selezionando i tag appropriati da un elenco. Tuttavia, questa è un'operazione piuttosto dispendiosa in termini di risorse e, inoltre, richiede la scrittura di istruzioni non banali. Un altro grave svantaggio è che con questo approccio non è possibile memorizzare nella cache qualcosa durante l'assemblaggio.

Qui l'utilità werf stessa viene in nostro aiuto, implementando memorizzazione nella cache intelligente e permettendoti di usare repository esterni. L'uso di werf per aggiungere codice dal repository velocizzerà notevolmente la compilazione, perché werf essenzialmente clona il repository una volta e poi lo esegue solo fetch se necessario. Inoltre, quando aggiungiamo dati dal repository, possiamo selezionare solo le directory necessarie (nel nostro caso questa è la directory docs), che ridurrà significativamente la quantità di dati aggiunti.

Poiché Jekyll è uno strumento progettato per compilare dati statici e non è necessario nell'immagine finale, sarebbe logico compilarlo artefatto werfe nell'immagine finale importa solo il risultato della compilazione.

Scriviamo werf.yaml

Quindi, abbiamo deciso di compilare ciascuna versione in un artefatto werf separato. Comunque noi non sappiamo quanti di questi artefatti ci saranno durante il montaggio, quindi non possiamo scrivere una configurazione di build fissa (in senso stretto, possiamo ancora farlo, ma non sarà del tutto efficace).

werf ti consente di utilizzare Vai ai modelli nel file di configurazione (werf.yaml), e questo lo rende possibile generare la configurazione al volo a seconda dei dati esterni (cosa ti serve!). I dati esterni nel nostro caso sono informazioni su versioni e rilasci, sulla base delle quali raccogliamo il numero richiesto di artefatti e di conseguenza otteniamo due immagini: werf-doc и werf-dev per correre su circuiti diversi.

I dati esterni vengono passati attraverso variabili di ambiente. Ecco la loro composizione:

  • RELEASES — una riga con un elenco di versioni e la corrispondente versione corrente di werf, sotto forma di un elenco di valori separati da spazi nel formato <НОМЕР_РЕЛИЗА>%<НОМЕР_ВЕРСИИ>. esempio: 1.0%v1.0.4-beta.20
  • CHANNELS — una riga con un elenco di canali e la corrispondente versione corrente di werf, sotto forma di un elenco di valori separati da spazi nel formato <КАНАЛ>%<НОМЕР_ВЕРСИИ>. esempio: 1.0-beta%v1.0.4-beta.20 1.0-alpha%v1.0.5-alpha.22
  • ROOT_VERSION — versione di rilascio werf da visualizzare per impostazione predefinita sul sito (non è sempre necessario visualizzare la documentazione con il numero di versione più alto). Esempio: v1.0.4-beta.20
  • REVIEW_SHA — hash del commit di revisione da cui è necessario creare la versione per il ciclo di test.

Queste variabili verranno compilate nella pipeline CI di GitLab e come verrà scritto esattamente di seguito.

Innanzitutto, per comodità, definiamo in werf.yaml Vai alle variabili del modello, 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 compilare la versione statica del sito è generalmente la stessa per tutti i casi di cui abbiamo bisogno (inclusa la generazione della versione root, nonché la versione per il circuito di sviluppo). Pertanto, lo sposteremo in un blocco separato utilizzando la funzione define - per il successivo riutilizzo include. Passeremo i seguenti argomenti al template:

  • Version — versione generata (nome del tag);
  • Channel — il nome del canale di aggiornamento per il quale viene generato l'artefatto;
  • Commit — hash del commit, se l'artefatto viene generato per un commit di revisione;
  • contesto.

Descrizione del modello di 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: "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 }}

Il nome dell'artefatto deve essere univoco. Possiamo ottenere questo risultato, ad esempio, aggiungendo il nome del canale (il valore della variabile .Channel) come suffisso al nome del manufatto: artifact: doc-{{ .Channel }}. Ma devi capire che quando importi da artefatti, dovrai fare riferimento agli stessi nomi.

Quando si descrive un artefatto, viene utilizzata la seguente funzionalità werf: montaggio. Montaggio che indica la directory del servizio build_dir ti consente di salvare la cache Jekyll tra le esecuzioni della pipeline, che accelera notevolmente il riassemblaggio.

Potresti anche aver notato l'uso del file releases.yml è un file YAML con i dati di rilascio richiesti github.com (un artefatto ottenuto durante l'esecuzione di una pipeline). È necessario durante la compilazione del sito, ma nel contesto dell'articolo ci interessa perché dipende dal suo stato riassemblaggio di un solo manufatto — un artefatto della versione root del sito (non è necessario in altri artefatti).

Questo viene implementato utilizzando l'istruzione condizionale if Vai a modelli e design {{ $Root.Files.Get "releases.yml" | sha256sum }} in scena fasi. Funziona come segue: quando si crea un artefatto per la versione root (variable .Channel è root) hash del file releases.yml influisce sulla firma dell'intero stage, poiché fa parte del nome del task Ansible (parametro name). Quindi, quando si cambia contenuto файла releases.yml il manufatto corrispondente verrà riassemblato.

Si prega di prestare attenzione anche a lavorare con un repository esterno. Nell'immagine di un artefatto da deposito werf, viene aggiunta solo la directory /docse, a seconda dei parametri passati, i dati del tag richiesto o del commit di revisione vengono aggiunti immediatamente.

Per utilizzare il modello di artefatto per generare una descrizione dell'artefatto delle versioni trasferite di canali e release, organizziamo un loop sulla variabile .WerfVersions в werf.yaml:

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

Perché il ciclo genererà diversi artefatti (lo speriamo), è necessario tenere conto del separatore tra loro: la sequenza --- (Per ulteriori informazioni sulla sintassi del file di configurazione, vedere documentazione). Come definito in precedenza, quando chiamiamo un modello in un ciclo, passiamo i parametri della versione, l'URL e il contesto root.

Allo stesso modo, ma senza loop, chiamiamo il modello dell'artefatto per "casi speciali": per la versione root, così come per la versione dal 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 }}

Tieni presente che l'artefatto per il commit della revisione verrà creato solo se la variabile è impostata .WerfReviewCommit.

Gli artefatti sono pronti: è ora di iniziare l'importazione!

L'immagine finale, progettata per essere eseguita su Kubernetes, è un normale NGINX con l'aggiunta di un file di configurazione del server nginx.conf e statico da artefatti. Oltre all'artefatto della versione root del sito, dobbiamo ripetere il ciclo sulla variabile .WerfVersions per importare gli artefatti del canale e delle versioni di rilascio + seguire la regola di denominazione degli artefatti adottata in precedenza. Poiché ogni artefatto memorizza le versioni del sito per due lingue, le importiamo nei luoghi forniti dalla configurazione.

Descrizione dell'immagine 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'immagine aggiuntiva, che insieme a quella principale viene lanciata sul circuito dev, contiene solo due versioni del sito: la versione da review commit e la versione root del sito (ci sono asset generali e, se ricordate , dati di rilascio). Pertanto, l'immagine aggiuntiva differirà da quella principale solo nella sezione di importazione (e, ovviamente, nel nome):

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

Come notato in precedenza, l'artefatto per il commit della revisione verrà generato solo quando viene eseguita la variabile di ambiente impostata REVIEW_SHA. Sarebbe possibile non generare affatto l'immagine werf-dev se non fosse presente alcuna variabile di ambiente REVIEW_SHA, ma per pulizia secondo politiche Le immagini Docker in werf hanno funzionato per l'immagine werf-dev, lasceremo che venga costruita solo con l'artefatto della versione root (è già costruito comunque), per semplificare la struttura della pipeline.

L'assemblaggio è pronto! Passiamo a CI/CD e alle sfumature importanti.

Pipeline in GitLab CI e funzionalità di build dinamica

Durante l'esecuzione della build dobbiamo impostare le variabili di ambiente utilizzate in werf.yaml. Ciò non si applica alla variabile REVIEW_SHA, che imposteremo quando chiameremo la pipeline dall'hook GitHub.

Genereremo i dati esterni necessari in uno script Bash generate_artifacts, che genererà due artefatti della pipeline GitLab:

  • файл releases.yml con i dati di rilascio,
  • файл common_envs.sh, contenente le variabili d'ambiente da esportare.

Contenuto del file generate_artifacts troverai nel nostro repository con esempi. La ricezione dei dati in sé non è l'oggetto dell'articolo, ma il file common_envs.sh è importante per noi, perché il lavoro del werf dipende da questo. 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 tale script, ad esempio, utilizzando la funzione Bash source.

Ora arriva la parte divertente. Affinché sia ​​la creazione che la distribuzione dell'applicazione funzionino correttamente, è necessario garantirlo werf.yaml E 'stato lo stesso almeno all'interno di una pipeline. Se questa condizione non viene soddisfatta, le segnature delle fasi calcolate da Werf durante l'assemblaggio e, ad esempio, la distribuzione, saranno diverse. Ciò porterà a un errore di distribuzione, perché... mancherà l'immagine richiesta per la distribuzione.

In altre parole, se durante l'assemblaggio dell'immagine del sito le informazioni su release e versioni sono le stesse, e al momento del deploy viene rilasciata una nuova versione e le variabili d'ambiente hanno valori diversi, allora il deploy fallirà con un errore: dopo tutto, l'artefatto della nuova versione non è ancora stato costruito.

Se 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 dovrebbero essere registrati all'interno della pipeline. Ciò è particolarmente importante se i parametri esterni cambiano abbastanza spesso.

Noi ricevere e registrare dati esterni nella prima fase della pipeline in GitLab (Precompilare) e trasmetterli ulteriormente nel modulo Artefatto CI GitLab. Ciò ti consentirà di eseguire e riavviare i processi della pipeline (creazione, distribuzione, pulizia) con la stessa configurazione in werf.yaml.

Contenuto della scena Precompilare файла .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

Dopo aver acquisito i dati esterni nell'artefatto, puoi creare e distribuire utilizzando le fasi standard della pipeline CI GitLab: creazione e distribuzione. Lanciamo la pipeline stessa utilizzando gli hook dal repository werf GitHub (ovvero, quando ci sono modifiche nel repository GitHub). I relativi dati possono essere trovati nelle proprietà del progetto GitLab nella sezione Impostazioni CI/CD -> Trigger pipeline, quindi creare il webhook corrispondente in GitHub (Impostazioni -> Webhook).

La fase di creazione sarà simile alla seguente:

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 aggiungerà due artefatti dalla fase alla fase di compilazione Precompilare, quindi esportiamo le variabili con i dati di input preparati utilizzando il costrutto source common_envs.sh. Iniziamo la fase di costruzione in tutti i casi, ad eccezione del lancio della pipeline secondo un programma. Secondo il programma, eseguiremo una tubazione per la pulizia, in questo caso non sarà necessario eseguire l'assemblaggio.

Nella fase di distribuzione, descriveremo due attività, separatamente per la distribuzione nei circuiti 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

I compiti differiscono essenzialmente solo nell'indicare il contesto del cluster in cui werf dovrebbe eseguire il deploy (WERF_KUBE_CONTEXT) e impostando le variabili di ambiente del ciclo (environment.name и environment.url), che vengono poi utilizzati nei modelli di grafico Helm. Non forniremo il contenuto dei modelli, perché... non c'è niente di interessante lì per l'argomento in questione, ma puoi trovarli in repository per l'articolo.

Tocco finale

Poiché le versioni werf vengono rilasciate abbastanza spesso, nuove immagini verranno create frequentemente e il registro Docker crescerà costantemente. Pertanto, è fondamentale configurare la pulizia automatica delle immagini in base alle policy. È molto facile da fare.

Per implementarlo avrai bisogno di:

  • Aggiungi un passaggio di pulizia a .gitlab-ci.yml;
  • Aggiungere l'esecuzione periodica di un'attività di pulizia;
  • Configura una variabile di ambiente con un token di accesso in scrittura.

Aggiunta di una fase di pulizia a .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

Abbiamo già visto quasi tutto questo un po' più in alto: solo per pulirlo è necessario prima accedere al registro Docker con un token che ha i diritti per eliminare le immagini nel registro Docker (il token dell'attività GitLab CI emesso automaticamente non lo fa hanno tali diritti). Il token deve essere preventivamente creato in GitLab e il suo valore deve essere specificato nella variabile d'ambiente WERF_IMAGES_CLEANUP_PASSWORD progetto (Impostazioni CI/CD -> Variabili).

L'aggiunta di un'attività di pulizia con la pianificazione richiesta è completata CI/CD ->
Orari
.

Questo è tutto: un progetto nel registro Docker non crescerà più costantemente da immagini inutilizzate.

Al termine della parte pratica vi ricordo che l'elenco completo dell'articolo è disponibile in Idiota:

risultato

  1. Abbiamo ricevuto una struttura di assemblaggio logica: un artefatto per versione.
  2. L'assemblaggio è universale e non richiede modifiche manuali quando vengono rilasciate nuove versioni di werf: la documentazione sul sito viene aggiornata automaticamente.
  3. Due immagini vengono assemblate per contorni diversi.
  4. Funziona rapidamente, perché La memorizzazione nella cache viene utilizzata il più possibile: quando viene rilasciata una nuova versione di werf o viene richiesto un hook GitHub per un commit di revisione, viene ricostruito solo l'artefatto corrispondente con la versione modificata.
  5. Non c'è bisogno di pensare a cancellare le immagini inutilizzate: la pulizia secondo le policy werf manterrà in ordine il Docker Registry.

risultati

  • L'utilizzo di werf consente all'assembly di funzionare rapidamente grazie alla memorizzazione nella cache sia dell'assembly stesso che della memorizzazione nella cache quando si lavora con repository esterni.
  • Lavorare con repository Git esterni elimina la necessità di clonare ogni volta l'intero repository o reinventare la ruota con complicate logiche di ottimizzazione. werf utilizza una cache ed esegue la clonazione solo una volta, quindi utilizza fetch e solo quando necessario.
  • Possibilità di utilizzare i modelli Go nel file di configurazione della build werf.yaml permette di descrivere un assembly il cui risultato dipende da dati esterni.
  • L'uso di mount in werf accelera notevolmente la raccolta di artefatti, grazie alla cache, comune a tutte le pipeline.
  • werf semplifica la configurazione della pulizia, il che è particolarmente importante quando si costruisce dinamicamente.

PS

Leggi anche sul nostro blog:

Fonte: habr.com

Aggiungi un commento