Tagging basato sui contenuti nel costruttore werf: perché e come funziona?

Tagging basato sui contenuti nel costruttore werf: perché e come funziona?

werf — il nostro strumento GitOps CLI open source per costruire e distribuire applicazioni in Kubernetes. Nel rilascio v1.1 è stata introdotta una nuova funzionalità nel costruttore di immagini: tagging delle immagini in base al contenuto o tagging basato sul contenuto. Fino ad ora, lo schema di tagging tipico in werf prevedeva il tagging delle immagini Docker in base al tag Git, al branch Git o al commit Git. Ma tutte queste strategie hanno dei difetti, che vengono completamente risolti dalla nuova strategia di tagging. Maggiori dettagli su di essa e su quanto sia buona saranno forniti di seguito.

Distribuzione di un set di microservizi da un singolo repository Git

Si verifica spesso la situazione in cui un'applicazione è suddivisa in molti servizi più o meno indipendenti. Le release di questi servizi possono avvenire in modo indipendente: in un'unica occasione può essere rilasciato uno o più servizi, mentre gli altri devono continuare a funzionare senza alcuna modifica. Ma dal punto di vista della gestione del codice e del progetto, è più comodo mantenere tali servizi dell'applicazione in un unico repository.

Ci sono situazioni in cui i servizi sono davvero indipendenti e non appartengono a un'unica applicazione. In tal caso, saranno collocati in progetti separati e il loro rilascio avverrà tramite processi CI/CD separati in ciascun progetto.

Tuttavia, nella realtà, gli sviluppatori spesso suddividono un'unica applicazione in diversi microservizi, ma gestire un singolo repository e progetto per ciascuno… è palesemente un overkill. È di quest'ultima situazione di cui parleremo: diversi microservizi si trovano all'interno di un unico repository di progetto e le release avvengono tramite un unico processo in CI/CD.

Tagging per branch e tag Git

Supponiamo di utilizzare la strategia di tagging più comune — tag-or-branch. Per i branch Git, le immagini sono taggate con il nome del branch, per un singolo branch esiste in un dato momento solo un'immagine pubblicata con il nome di quel branch. Per i tag Git, le immagini sono taggate di conseguenza con il nome del tag.

Quando viene creato un nuovo tag Git — ad esempio, al rilascio di una nuova versione — verrà creato un nuovo tag Docker per tutte le immagini del progetto nel Docker Registry:

  • myregistry.org/myproject/frontend:v1.1.10
  • myregistry.org/myproject/myservice1:v1.1.10
  • myregistry.org/myproject/myservice2:v1.1.10
  • myregistry.org/myproject/myservice3:v1.1.10
  • myregistry.org/myproject/myservice4:v1.1.10
  • myregistry.org/myproject/myservice5:v1.1.10
  • myregistry.org/myproject/database:v1.1.10

Questi nuovi nomi delle immagini vengono inclusi nella configurazione di Kubernetes tramite i modelli Helm. Al momento del lancio del deployment con il comando werf deploy avviene l'aggiornamento del campo image nei manifesti delle risorse di Kubernetes e viene effettuato il riavvio delle risorse corrispondenti a causa della modifica del nome dell'immagine.

Problema: nel caso in cui il contenuto dell'immagine non sia realmente cambiato dal precedente rilascio (tag Git), ma sia solo il suo tag Docker a essere modificato, si verifica un inutile riavvio di questa applicazione e, di conseguenza, è possibile un certo fermo. Sebbene non ci siano state ragioni reali per effettuare questo riavvio.

Di conseguenza, con l'attuale schema di tagging, è necessario creare diversi repository Git separati e si pone il problema di organizzare il rilascio di questi diversi repository. In generale, questo schema risulta sovraccarico e complesso. È meglio unire più servizi in un unico repository e creare tag Docker in modo da evitare riavvii non necessari.

Tagging per commit Git

In werf è presente anche una strategia di tagging collegata ai commit Git.

Il commit Git è un identificatore del contenuto del repository Git e dipende dalla cronologia delle modifiche ai file nel repository Git, quindi sembra logico utilizzarlo per il tagging delle immagini nel Docker Registry.

Tuttavia, il tagging per commit Git presenta gli stessi svantaggi di quello per rami Git o tag Git:

  • Potrebbe essere stato creato un commit vuoto che non modifica i file, ma il tag Docker dell'immagine verrà modificato.
  • Potrebbe essere stato creato un commit di fusione che non modifica i file, ma il tag Docker dell'immagine verrà modificato.
  • Potrebbe essere stato creato un commit che modifica file in Git che non vengono importati nell'immagine, e il tag Docker dell'immagine verrà nuovamente modificato.

Il tagging per nome del ramo Git non riflette la versione dell'immagine

C'è anche un altro problema legato alla strategia di tagging per rami Git.

Il tagging per nome del ramo funziona finché i commit di quel ramo vengono raccolti in modo sequenziale in ordine cronologico.

Se un utente avvia la ricompilazione di un vecchio commit associato a un ramo nella configurazione attuale, werf sovrascriverà l'immagine con la versione ricompilata per il vecchio commit, utilizzando il corrispondente tag Docker. I Deployment che utilizzano questo tag rischiano di eseguire un pull di un'altra versione dell'immagine durante il riavvio dei pod, compromettendo la connessione della nostra applicazione con il sistema CI e causando una desincronizzazione.

Inoltre, durante i push consecutivi su uno stesso ramo con breve intervallo di tempo tra di essi, un vecchio commit potrebbe essere ricompilato dopo un commit più recente: la vecchia versione dell'immagine sovrascriverà la nuova in base al tag del ramo Git. Tali problemi possono essere risolti da un sistema CI/CD (ad esempio, in GitLab CI, viene attivato un pipeline per l'ultimo di una serie di commit). Tuttavia, non tutti i sistemi lo supportano e deve esserci un metodo più affidabile per prevenire un problema così fondamentale.

Che cos'è il content-based tagging?

Allora, cos'è il content-based tagging — il tagging delle immagini basato sul contenuto.

Per creare i tag Docker non si utilizzano i primitivi di Git (ramo Git, tag Git…), ma un checksum associato a:

  • il contenuto dell'immagine. L'identificatore-tag dell'immagine riflette il suo contenuto. Durante la costruzione di una nuova versione, questo identificatore non cambierà se non ci sono stati cambiamenti nei file dell'immagine;
  • la storia di creazione di quest'immagine in Git. Le immagini correlate a diversi rami Git e con storie di costruzione diverse mediante werf avranno identificatori-tag diversi.

Come identificatore-tag viene utilizzata la cosiddetta firma delle fasi dell'immagine.

Ogni immagine consiste in un insieme di fasi: da, before-install, git-archive, install, imports-after-install, before-setup,… git-latest-patch ecc. Ogni fase ha un identificatore che riflette il suo contenuto — firma della fase (stage signature).

L'immagine finale, composta da queste fasi, viene etichettata con quella che si chiama firma dell'insieme di queste fasi — stages signature, che è un riassunto per tutte le fasi dell'immagine.

Ogni immagine dalla configurazione werf.yaml in generale avrà una propria firma e, di conseguenza, un tag Docker.

La firma delle fasi risolve tutti i problemi menzionati:

  • È resistente ai commit Git vuoti.
  • È resistente ai commit Git che modificano file non rilevanti per l'immagine.
  • Non provoca il problema di sovrascrivere la versione attuale dell'immagine durante il riavvio delle costruzioni per vecchi commit Git del ramo.

Ora questa è la strategia di tagging raccomandata e viene utilizzata per impostazione predefinita in werf per tutti i sistemi CI.

Come attivare e utilizzare in werf

L'opzione corrispondente è stata aggiunta al comando werf publish: --tag-by-stages-signature=true|false

Nella CI, la strategia di tagging è impostata dal comando werf ci-env. In precedenza, per essa era definito il parametro werf ci-env --tagging-strategy=tag-or-branch. Ora, se si specifica werf ci-env --tagging-strategy=stages-signature o non si specifica questa opzione, werf utilizzerà per impostazione predefinita la strategia di tagging stages-signature. Il comando werf ci-env imposterà automaticamente i flag necessari per il comando werf build-and-publish (o werf publish), quindi non è necessario specificare ulteriori opzioni per questi comandi.

Ad esempio, il comando:

werf publish --stages-storage :local --images-repo registry.hello.com/web/core/system --tag-by-stages-signature

… può creare le seguenti immagini:

  • registry.hello.com/web/core/system/backend:4ef339f84ca22247f01fb335bb19f46c4434014d8daa3d5d6f0e386d
  • registry.hello.com/web/core/system/frontend:f44206457e0a4c8a54655543f749799d10a9fe945896dab1c16996c6

Qui 4ef339f84ca22247f01fb335bb19f46c4434014d8daa3d5d6f0e386d — questa è la firma della fase dell'immagine backend, ma f44206457e0a4c8a54655543f749799d10a9fe945896dab1c16996c6 — firma della fase dell'immagine frontend.

Utilizzando funzioni speciali werf_container_image e werf_container_env nei modelli Helm non è necessario modificare nulla: queste funzioni genereranno automaticamente nomi di immagini corretti.

Esempio di configurazione nel sistema CI:

type multiwerf && source <(multiwerf use 1.1 beta)
type werf && source <(werf ci-env gitlab)
werf build-and-publish|deploy

Maggiore informazioni sulla configurazione sono disponibili nella documentazione:

Totale

  • Una nuova opzione werf publish --tag-by-stages-signature=true|false.
  • Nuovo valore dell'opzione werf ci-env --tagging-strategy=stages-signature|tag-or-branch (se non specificato, per impostazione predefinita sarà stages-signature).
  • Se in precedenza sono state utilizzate opzioni di tagging basate su commit Git (WERF_TAG_GIT_COMMIT o l'opzione werf publish --tag-git-commit COMMIT), allora bisogna cambiare obbligatoriamente alla strategia di tagging stages-signature.
  • È meglio cambiare i nuovi progetti subito alla nuova schema di tagging.
  • Per i progetti esistenti che passano a werf 1.1, è consigliabile cambiare alla nuova schema di tagging, tuttavia la vecchia tag-or-branch è ancora supportata.

Il tagging basato sul contenuto risolve tutti i problemi menzionati nell'articolo:

  • Resistenza del nome del tag Docker ai commit Git vuoti.
  • Resistenza del nome del tag Docker a commit Git che modificano file non rilevanti per l'immagine.
  • Non comporta problemi di sovrascrittura della versione attuale dell'immagine durante il riavvio delle build per vecchi commit Git per i rami Git.

Usate! E non dimenticate di visitare il nostro GitHub, per creare un'issue o trovare già esistente, mettere un like, creare una PR o semplicemente seguire lo sviluppo del progetto.

P.S.

Leggi 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