Ora puoi costruire immagini Docker in werf anche usando un normale Dockerfile

Meglio tardi che mai. O come siamo stati sul punto di commettere un grave errore, non avendo il supporto dei comuni Dockerfile per la creazione delle immagini dell'applicazione.

Ora puoi costruire immagini Docker in werf anche usando un normale Dockerfile

Si parlerà di werf — un'utility GitOps che si integra con qualsiasi sistema CI/CD e gestisce l'intero ciclo di vita dell'applicazione, consentendo di:

  • creare e pubblicare immagini,
  • distribuire applicazioni in Kubernetes,
  • rimuovere immagini non utilizzate attraverso politiche specifiche.


La filosofia del progetto è quella di riunire strumenti di basso livello in un'unica sistema unificato, dando ai DevOps engineer il controllo sulle applicazioni. Dovrebbero essere utilizzati, se possibile, strumenti già esistenti (come Helm e Docker). Se non esiste una soluzione a un problema, possiamo creare e supportare tutto il necessario.

Retroscena: il nostro assembler di immagini

È proprio così che è successo con l'assembler di immagini in werf: ci mancava il consueto Dockerfile. Se si guarda brevemente alla storia del progetto, questo problema si è manifestato già nelle prime versioni di werf (allora chiamato dapp).

). Creando uno strumento per costruire applicazioni in immagini Docker, ci siamo subito resi conto che Dockerfile non era adatto per alcune esigenze molto specifiche:

  1. La necessità di assemblare tipiche piccole applicazioni web secondo il seguente schema standard:
    • installare le dipendenze di sistema dell'applicazione,
    • installare il pacchetto delle librerie di dipendenza dell'applicazione,
    • compilare le risorse,
    • e la cosa più importante — aggiornare il codice nell'immagine in modo rapido ed efficiente.
  2. Quando ci sono modifiche nei file del progetto, l'assembler deve creare rapidamente un nuovo layer sovrapponendo una patch sui file modificati.
  3. Se alcuni file sono cambiati, deve essere ricompilata la fase dipendente corrispondente.

Al giorno d'oggi, il nostro assembler offre molte altre funzionalità, ma le esigenze iniziali erano queste.

In generale, senza pensarci troppo, ci siamo attrezzati con il linguaggio di programmazione utilizzato (vedi sotto) e siamo partiti — per implementare il nostro DSL! In linea con gli obiettivi fissati, era destinato a descrivere il processo di assemblaggio per fasi e a definire le dipendenze di queste fasi dai file. E lo completava il nostro assembler, che trasformava il DSL nell'obiettivo finale — l'immagine assemblata. Inizialmente il DSL era in Ruby, ma con il passaggio a Golang — la configurazione del nostro assembler è cominciata a essere descritta in un file YAML.

Ora puoi costruire immagini Docker in werf anche usando un normale Dockerfile
Vecchia configurazione per dapp su Ruby

Ora puoi costruire immagini Docker in werf anche usando un normale Dockerfile
Configurazione attuale per werf su YAML

Il meccanismo di funzionamento del builder è cambiato nel tempo. Inizialmente generavamo al volo un Dockerfile temporaneo dalla nostra configurazione, poi abbiamo iniziato a eseguire le istruzioni di build in contenitori temporanei e a fare commit.

NB: Attualmente, il nostro builder, che lavora con la propria configurazione (in YAML) e si chiama Builder Stapel, si è evoluto in uno strumento piuttosto potente. La sua descrizione dettagliata meriterebbe articoli a parte, mentre i dettagli principali possono essere trovati in documentazione.

Consapevolezza del problema

Ma abbiamo capito, anche se non subito, di aver commesso un errore: non abbiamo aggiunto la possibilità di costruire immagini tramite Dockerfile standard e integrarli nella stessa infrastruttura di gestione complessa delle applicazioni (cioè costruire immagini, fare deployment e pulirle). Come si poteva creare uno strumento per il deployment in Kubernetes e non implementare il supporto per Dockerfile, cioè il modo standard per descrivere le immagini per la maggior parte dei progetti?..

Invece di rispondere a un tale quesito, proponiamo la sua soluzione. Cosa fare se hai già un Dockerfile (o un insieme di Dockerfile) e desideri utilizzare werf?

NB: A proposito, perché dovresti volere usare werf? Le caratteristiche principali sono le seguenti:

  • gestione completa dell'applicazione, inclusa la pulizia delle immagini;
  • possibilità di gestire la build di più immagini da un'unica configurazione;
  • processo di deployment migliorato per chart compatibili con Helm.

Puoi trovare un elenco più completo su pagina del progetto.

Quindi, se un tempo avremmo suggerito di riscrivere il Dockerfile nella nostra configurazione, ora diciamo con piacere: 'Lascia che werf costruisca i tuoi Dockerfile!'

Come usare?

La piena implementazione di questa funzionalità è stata introdotta nella release werf v1.0.3-beta.1. Il principio generale è semplice: l'utente specifica il percorso di un Dockerfile esistente nella configurazione di werf, dopodiché esegue il comando werf build… e tutto qui — werf costruirà l'immagine. Consideriamo un esempio astratto.

Dichiariamo il seguente Dockerfile nella root del progetto:

FROM ubuntu:18.04
RUN echo Building ...

E dichiariamo werf.yaml, che utilizza questo Dockerfile:

configVersion: 1
project: dockerfile-example
---
image: ~
dockerfile: .\/Dockerfile

Fatto! Resta da avviare werf build:

Ora puoi costruire immagini Docker in werf anche usando un normale Dockerfile

Inoltre, puoi dichiarare il seguente werf.yaml per costruire più immagini da diversi Dockerfile:

configVersion: 1
project: dockerfile-example
---
image: backend
dockerfile: .\/dockerfiles\/Dockerfile-backend
---
image: frontend
dockerfile: .\/dockerfiles\/Dockerfile-frontend

Finalmente, è supportato anche il passaggio di parametri aggiuntivi per la compilazione, come --build-arg e --add-host — attraverso la configurazione di werf. Una descrizione completa della configurazione dell'immagine Dockerfile è disponibile nella pagina della documentazione.

Come funziona?

Durante il processo di compilazione, funziona la cache standard dei layer locali in Docker. Tuttavia, è importante notare che werf integra anche la configurazione Dockerfile nella propria infrastruttura. Cosa significa questo?

  1. Ogni immagine costruita da un Dockerfile è composta da uno stage chiamato dockerfile (puoi leggere di più su cosa sono gli stages in werf nella qui).
  2. Per lo stage dockerfile werf calcola una firma che dipende dal contenuto della configurazione del Dockerfile. Quando la configurazione del Dockerfile viene modificata, la firma dello stage cambia dockerfile e werf avvia una ricompilazione di quello stage con la nuova configurazione del Dockerfile. Se la firma non cambia, werf prende l'immagine dalla cache (ulteriori informazioni sull'uso delle firme in werf sono state trattate nella questa relazione).
  3. Successivamente, le immagini costruite possono essere pubblicate con il comando werf publish (o werf build-and-publish) e utilizzate per il deploy in Kubernetes. Le immagini pubblicate nel Docker Registry verranno pulite con i mezzi di pulizia standard di werf, ovvero ci sarà una pulizia automatica delle vecchie immagini (più vecchie di N giorni), delle immagini associate a branch Git non esistenti e secondo altre politiche.

Per ulteriori informazioni sui temi descritti qui, puoi consultare la documentazione:

Note e precauzioni

1. URL esterni in ADD non supportati

Attualmente, non è supportato l'uso di URL esterni nella direttiva ADD. Werf non avvierà una ricompilazione quando la risorsa all'URL specificato cambia. È previsto l'aggiunta di questa funzionalità a breve.

2. Non è possibile aggiungere .git all'immagine

In generale, aggiungere la directory .git all'immagine è una cattiva pratica ecco perché:

  1. Se .git rimane nell'immagine finale, infrangendo i principi 12 factor app: poiché l'immagine finale dovrebbe essere legata a un singolo commit, non dovrebbe essere possibile eseguire git checkout commit arbitrari.
  2. .git aumenta la dimensione dell'immagine (il repository può essere grande perché in passato sono stati aggiunti file pesanti, e poi rimossi). Tuttavia, la dimensione del work-tree, legata solo a un commit specifico, non dipenderà dalla storia delle operazioni in Git. Inoltre, l'aggiunta e la successiva rimozione .git l'immagine finale non funzionerà: l'immagine acquisirà comunque uno strato superfluo — è così che funziona Docker.
  3. Docker può avviare una ricompilazione superflua, anche se si sta compilando lo stesso commit, ma da diverse work-tree. Ad esempio, GitLab crea directory separate clonate in /home/gitlab-runner/builds/HASH/[0-N]/yourproject con la compilazione parallela attivata. La ricompilazione superflua sarà dovuta al fatto che la directory .git è diversa in diverse versioni clonate dello stesso repository, anche se si sta compilando lo stesso commit.

L'ultimo punto ha conseguenze anche nell'uso di werf. Werf richiede che la cache compilata sia presente quando si eseguono alcuni comandi (ad esempio, werf deploy). Durante l'esecuzione di tali comandi, werf calcola le firme delle fasi per le immagini specificate in werf.yaml, e devono essere nella cache di build — altrimenti il comando non potrà continuare. Se la firma delle fasi dipende dal contenuto .git, otteniamo una cache instabile alle modifiche in file irrilevanti e werf non potrà perdonare tale distrazione (ulteriori dettagli si possono trovare in documentazione).

In generale l'aggiunta solo di file necessari tramite l'istruzione ADD aumenta comunque l'efficienza e l'affidabilità di quanto scritto Dockerfile, oltre a migliorare la stabilità della cache, costruita su questo Dockerfile, a cambiamenti irrilevanti in Git.

Risultato

Il nostro percorso iniziale nella scrittura di un proprio compilatore per esigenze specifiche è stato difficile, onesto e diretto: invece di utilizzare soluzioni tampone sopra un Dockerfile standard, abbiamo scritto la nostra soluzione con una sintassi personalizzata. E questo ha portato i suoi vantaggi: il compilatore Stapel svolge eccellentemente il suo compito.

Tuttavia, durante la scrittura del nostro compilatore, abbiamo trascurato il supporto per i Dockerfile già esistenti. Attualmente questo difetto è stato corretto, e in futuro prevediamo di sviluppare il supporto per Dockerfile insieme al nostro compilatore personalizzato Stapel per build distribuite e per build utilizzando Kubernetes (ovvero build su runner all'interno di Kubernetes, come fatto in kaniko).

Quindi, se avete qualche Dockerfile in giro... prova werf!

P.S. Elenco della documentazione sul tema

Leggi anche nel nostro blog: «werf — il nostro strumento per CI/CD in Kubernetes (panoramica e video della presentazione)».

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