GNU/Linux >> Linux Esercitazione >  >> Linux

Velocizzare le build di immagini del contenitore con Buildah

Alcuni mesi fa, ho scritto un articolo sull'accelerazione delle build di container all'interno di un container. Quel l'articolo si concentrava sulla velocità di estrazione delle immagini del contenitore e sui diversi modi per precompilare l'archivio immagini, utilizzando i montaggi di volume dall'host e il concetto Buildah di "negozi aggiuntivi".

Buildah è uno strumento da riga di comando per creare immagini compatibili con Open Container Initiative (che significa anche compatibili con Docker e Kubernetes) in modo rapido e semplice. Buildah è facile da incorporare in script e creare pipeline e, soprattutto, non richiede un demone contenitore in esecuzione per creare la sua immagine.

Questo articolo affronterà un secondo problema con la velocità di compilazione quando si utilizza dnf /yum comandi all'interno di contenitori. Tieni presente che in questo articolo utilizzerò il nome dnf (che è il nome a monte) invece di ciò che usano alcuni a valle (yum ) Questi commenti si applicano a entrambi dnf e yum .

Velocità di download

L'hai mai notato a volte quando esegui dnf -y update o dnf -y install per la prima volta dopo un po', il comando si interrompe per molto tempo prima ancora che inizi a ridurre gli RPM? Cosa sta succedendo?

La prima cosa che dnf non è altro che scaricare enormi file di cache. Questi file sono scritti in XML e contengono ogni singolo pacchetto nel repository remoto, inclusi molti dati sul pacchetto. Contengono persino tutti i percorsi all'interno del pacchetto. Questi dati sono necessari in modo che quando puoi eseguire qualcosa come dnf -y install /usr/bin/httpd e poi dnf determina il pacchetto da installare. Molti pacchetti contengono comandi come (requires: /usr/bin/sendmail ) che sfruttano questa funzionalità, consentendo dnf per tirare un pacchetto adeguato per soddisfare il bisogno.

L'estrazione di questi file enormi e, soprattutto, l'elaborazione di questi file può richiedere più di un minuto. Questi dati vengono utilizzati da libsolv , quindi deve essere convertito in solv formato, che è lento. La velocità non è un grosso problema quando lo fai solo periodicamente sul tuo host, ma quando si tratta di costruire container, questo è un affare molto più grande.

Sintassi del file Docker

Sebbene Buildah ti consenta di creare immagini di contenitori direttamente nella shell, la maggior parte delle persone utilizza Dockerfile e Containerfile per creare contenitori e definire ricette di immagini riproducibili. Buildah cerca automaticamente un Containerfile e un Dockerfile adesso. Ognuno condivide la stessa sintassi, quindi userò Containerfile per il resto di questo documento.

Una cosa comune da fare in un Containerfile è usare una sintassi come:

FROM ubi8  
RUN dnf -y update; dnf -y install nginx; dnf -y clean all  
…  
RUN dnf -y install jboss; dnf -y clean all  

Esaminiamo il dnf Linee. Il primo dnf riga:

(dnf -y update; dnf -y install nginx; dnf -y clean all ):

  1. Aggiorna tutti i pacchetti all'interno del contenitore.
  2. Installa il pacchetto selezionato nginx .
  3. Pulisce tutto.

Dal momento che ubi8 l'immagine è stata probabilmente creata qualche tempo fa e il suo /var/cache/dnf la directory probabilmente non esiste all'interno dell'immagine del contenitore, dnf deve estrarre il file della cache XML ed elaborarlo. Quindi, dnf installa i pacchetti effettivi prima di dnf -y clean all rimuove tutti i dati in eccesso che i comandi precedenti inserivano nell'immagine, come i file di registro e di cache.

Si consiglia agli utenti di eseguire clean all per mantenere l'immagine il più piccola possibile. Ogni RUN il comando crea un nuovo livello e anche se rimuovi il contenuto in un RUN successivo comando, il livello iniziale conterrà tutto il contenuto. Ciò significa che tutti coloro che estraggono la tua immagine finiranno per estrarre i registri e i file della cache. Ora, se il tuo Containerfile contiene uno o più dnf comandi, pagherai il prezzo più e più volte. Non solo, ma ogni volta che ricostruisci questa immagine, pagherai di nuovo quel prezzo. Se ti trovi su un server di compilazione, ogni immagine contenitore che crei scaricherà questi file XML più e più volte, sprecando tonnellate di risorse e tempo.

Buildah con cavalcature sovrapposte

Abbiamo visto il problema sopra descritto e abbiamo pensato di poterlo gestire in un modo migliore. Non potremmo semplicemente estrarre i dati XML sull'host, elaborarli sull'host e montarli in volume nei contenitori? Forse potremmo impostare un cron job o un systemd timer che esegue una dnf makecache una volta per ogni versione dei sistemi operativi per cui creerai immagini del contenitore? Puoi eseguire questo lavoro una o più volte al giorno sull'host e quindi fare in modo che tutti i generatori di contenitori montino le cache appropriate nei contenitori buildah.

Bene, Buildah supporta le directory di montaggio del volume dall'host ai container. Questo dovrebbe risolvere il problema, e lo fa. MA, i contenitori spesso vogliono scrivere in questa directory, se devono aggiornare la cache, quindi la cache deve essere montata nei contenitori di lettura/scrittura. Questo provoca un enorme buco di sicurezza. Immagina una situazione in cui una build di container ostile ha scritto contenuto in questa cache che un costruttore di container successivo ha letto. Potrebbe eventualmente indurre il secondo contenitore a installare software violato. Abbiamo bisogno di una soluzione in cui il contenuto è montato nel contenitore, non può essere scritto dal contenitore, ma può comunque essere scritto dalla prospettiva del contenitore. Questo è fondamentalmente ciò che è un punto di montaggio Overlay.

Il file system di overlay monta un lower directory e quindi allega un upper directory nel merged punto di montaggio. Quando un processo scrive in un nuovo file nel merged directory, il nuovo file viene scritto nella directory upper directory. Quando un processo modifica un file esistente in lower directory, il kernel copia il file da lower nella directory upper directory e consente al processo di modificare il file nella upper directory.

Abbiamo introdotto il concetto di cavalcatura Overlay in Buildah. Ora puoi eseguire build con

buildah bud -v /var/cache/dnf:/var/cache/dnf:O -f /tmp/Containerfile /tmp  

Dnf all'interno del contenitore verificherà comunque se sono presenti contenuti più recenti nei repository e tirerà giù il contenuto se esiste. Ma se il contenuto dell'host è aggiornato, utilizzerà rapidamente la cache dell'host. Ti consiglio di aggiornare la cache degli host almeno una volta al giorno.

Una caratteristica aggiuntiva che abbiamo aggiunto per la cavalcatura Buildah Overlay è quella di distruggere la upper directory su ogni RUN direttiva. Ricordiamo che nel nostro esempio abbiamo usato più RUN comandi che eseguivano ciascuno un dnf -y clean all . Il dnf -y clean all comando provoca il upper directory per mostrare tutto il contenuto dal basso come eliminato. Se il prossimo dnf comando condiviso nella parte superiore precedente vedrebbe la cache vuota e dovrebbe estrarre il datastore XML ed elaborarlo. Rimozione della upper directory significa che ogni dnf il comando vedrà di nuovo il lower directory dall'host e continuare a condividere la cache degli host.

Differenza di velocità

Creerò un semplice Containerfile contenente due dnf esegui i comandi.

FROM fedora:31  
RUN dnf -y install net-utils; dnf -y clean all  
RUN dnf -y install iputils; dnf -y clean all  

Eseguirlo localmente sulla mia scatola Fedora 31

# time -f "Elapsed Time: %E" buildah bud -f Containerfile .  
STEP 1: FROM fedora:31  
STEP 2: RUN dnf -y install procps-ng; dnf -y clean all  
Fedora Modular 31 - x86_64 2.0 MB/s | 5.2 MB 00:02  
Fedora Modular 31 - x86_64 - Updates 1.6 MB/s | 4.0 MB 00:02  
Fedora 31 - x86_64 - Updates 4.2 MB/s | 19 MB 00:04  
Fedora 31 - x86_64 1.8 MB/s | 71 MB 00:39  
Last metadata expiration check: 0:00:01 ago on Wed Feb 5 13:55:54 2020.  
Dependencies resolved.  
================================================================================  
Package Architecture Version Repository Size  
================================================================================  
Installing:  
procps-ng x86_64 3.3.15-6.fc31 fedora 326 k

Transaction Summary  
================================================================================  
Install 1 Package

Total download size: 326 k  
Installed size: 966 k  
Downloading Packages:  
procps-ng-3.3.15-6.fc31.x86_64.rpm 375 kB/s | 326 kB 00:00  
--------------------------------------------------------------------------------  
Total 218 kB/s | 326 kB 00:01  
Running transaction check  
Transaction check succeeded.  
Running transaction test  
Transaction test succeeded.  
Running transaction  
Preparing : 1/1  
Installing : procps-ng-3.3.15-6.fc31.x86_64 1/1  
Running scriptlet: procps-ng-3.3.15-6.fc31.x86_64 1/1  
Verifying : procps-ng-3.3.15-6.fc31.x86_64 1/1

Installed:  
procps-ng-3.3.15-6.fc31.x86_64

Complete!  
33 files removed  
STEP 3: RUN dnf -y install iputils; dnf -y clean all  
Fedora Modular 31 - x86_64 741 kB/s | 5.2 MB 00:07  
Fedora Modular 31 - x86_64 - Updates 928 kB/s | 4.0 MB 00:04  
Fedora 31 - x86_64 - Updates 3.8 MB/s | 19 MB 00:05  
Fedora 31 - x86_64 7.9 MB/s | 71 MB 00:08  
Last metadata expiration check: 0:00:01 ago on Wed Feb 5 13:57:13 2020.  
Dependencies resolved.  
================================================================================  
Package Architecture Version Repository Size  
================================================================================  
Installing:  
iputils x86_64 20190515-3.fc31 fedora 141 k

Transaction Summary  
================================================================================  
Install 1 Package

Total download size: 141 k  
Installed size: 387 k  
Downloading Packages:  
iputils-20190515-3.fc31.x86_64.rpm 252 kB/s | 141 kB 00:00  
--------------------------------------------------------------------------------  
Total 141 kB/s | 141 kB 00:01  
Running transaction check  
Transaction check succeeded.  
Running transaction test  
Transaction test succeeded.  
Running transaction  
Preparing : 1/1  
Installing : iputils-20190515-3.fc31.x86_64 1/1  
Running scriptlet: iputils-20190515-3.fc31.x86_64 1/1  
Verifying : iputils-20190515-3.fc31.x86_64 1/1

Installed:  
iputils-20190515-3.fc31.x86_64

Complete!  
33 files removed  
STEP 4: COMMIT  
Getting image source signatures  
Copying blob ac0b803c5612 skipped: already exists  
Copying blob 922380d685bc done  
Copying config 566e2afbb4 done  
Writing manifest to image destination  
Storing signatures  
566e2afbb417f0119109578a87950250b566a3b4908868627975a4c7428accfb  
566e2afbb417f0119109578a87950250b566a3b4908868627975a4c7428accfb

Elapsed Time: 2:15.00  

Questa esecuzione ha richiesto 2 minuti e 15 secondi per creare una nuova immagine del contenitore con i due nuovi pacchetti.

Ora proviamo questo con un montaggio Overlay dall'host.

# dnf -y makecache  
# time -f "Elapsed Time: %E" buildah bud -v /var/cache/dnf:/var/cache/dnf:O -f Containerfile .  
STEP 1: FROM fedora:31  
STEP 2: RUN dnf -y install procps-ng; dnf -y clean all  
Last metadata expiration check: 0:02:34 ago on Wed Feb 5 13:51:54 2020.  
Dependencies resolved.  
================================================================================  
Package Architecture Version Repository Size  
================================================================================  
Installing:  
procps-ng x86_64 3.3.15-6.fc31 fedora 326 k

Transaction Summary  
================================================================================  
Install 1 Package

Total download size: 326 k  
Installed size: 966 k  
Downloading Packages:  
procps-ng-3.3.15-6.fc31.x86_64.rpm 496 kB/s | 326 kB 00:00  
--------------------------------------------------------------------------------  
Total 245 kB/s | 326 kB 00:01  
Running transaction check  
Transaction check succeeded.  
Running transaction test  
Transaction test succeeded.  
Running transaction  
Preparing : 1/1  
Installing : procps-ng-3.3.15-6.fc31.x86_64 1/1  
Running scriptlet: procps-ng-3.3.15-6.fc31.x86_64 1/1  
Verifying : procps-ng-3.3.15-6.fc31.x86_64 1/1

Installed:  
procps-ng-3.3.15-6.fc31.x86_64

Complete!  
285 files removed  
STEP 3: RUN dnf -y install iputils; dnf -y clean all  
Last metadata expiration check: 0:02:41 ago on Wed Feb 5 13:51:54 2020.  
Dependencies resolved.  
================================================================================  
Package Architecture Version Repository Size  
================================================================================  
Installing:  
iputils x86_64 20190515-3.fc31 fedora 141 k

Transaction Summary  
================================================================================  
Install 1 Package

Total download size: 141 k  
Installed size: 387 k  
Downloading Packages:  
iputils-20190515-3.fc31.x86_64.rpm 556 kB/s | 141 kB 00:00  
--------------------------------------------------------------------------------  
Total 222 kB/s | 141 kB 00:00  
Running transaction check  
Transaction check succeeded.  
Running transaction test  
Transaction test succeeded.  
Running transaction  
Preparing : 1/1  
Installing : iputils-20190515-3.fc31.x86_64 1/1  
Running scriptlet: iputils-20190515-3.fc31.x86_64 1/1  
Verifying : iputils-20190515-3.fc31.x86_64 1/1

Installed:  
iputils-20190515-3.fc31.x86_64

Complete!  
285 files removed  
STEP 4: COMMIT  
Getting image source signatures  
Copying blob ac0b803c5612 skipped: already exists  
Copying blob 524bb3b83d61 done  
Copying config 0f82aa6064 done  
Writing manifest to image destination  
Storing signatures  
0f82aa6064814ff3dcb603c34c75e516e00817811681b83b8632f3e9b694e518  
0f82aa6064814ff3dcb603c34c75e516e00817811681b83b8632f3e9b694e518  
Elapsed Time: 0.17.44  

Con la montatura Overlay, siamo stati in grado di creare una nuova immagine con i due pacchetti aggiuntivi in ​​17 secondi invece di 2 minuti e 15 secondi. È quasi 8 volte più veloce creare la stessa immagine del contenitore.

Ora questo mostra che se crei immagini su un sistema operativo host che ha il dnf metadati pre-cache puoi accelerare la velocità di installazione di una quantità ENORME. Ma cosa succede se il tuo sistema di build crea immagini per altre versioni del sistema operativo? Supponiamo di voler costruire immagini per Fedora 30 e Fedora 31. Nota:questo funzionerebbe anche su un sistema RHEL8, dove potresti voler costruire immagini RHEL7 e forse anche RHEL6.
Dnf include un'interessante funzionalità in cui puoi specificare versioni diverse durante il pull dei contenuti, utilizzando il --releasever opzione. Dnf ti consente anche di specificare directory alternative per posizionare la cachedir, --setopt=cachedir .

Nell'esempio seguente, eliminerò due cache sull'host e quindi utilizzerò Buildah in modalità riga di comando.

# dnf -y makecache --releasever=31 --setopt=cachedir=/var/cache/dnf/31  
# dnf -y makecache --releasever=30 --setopt=cachedir=/var/cache/dnf/30  
# ctr31=$(buildah from fedora:31)  
# time -f 'Elapsed Time: %E' buildah run -v /var/cache/dnf/31:/var/cache/dnf:O ${ctr31} dnf -y install iputils  
Last metadata expiration check: 0:00:15 ago on Wed Feb 5 14:17:41 2020.  
Dependencies resolved.  
================================================================================  
Package Architecture Version Repository Size  
================================================================================  
Installing:  
iputils x86_64 20190515-3.fc31 fedora 141 k

Transaction Summary  
================================================================================  
Install 1 Package

Total download size: 141 k  
Installed size: 387 k  
Downloading Packages:  
iputils-20190515-3.fc31.x86_64.rpm 192 kB/s | 141 kB 00:00  
--------------------------------------------------------------------------------  
Total 107 kB/s | 141 kB 00:01  
Running transaction check  
Transaction check succeeded.  
Running transaction test  
Transaction test succeeded.  
Running transaction  
Preparing : 1/1  
Installing : iputils-20190515-3.fc31.x86_64 1/1  
Running scriptlet: iputils-20190515-3.fc31.x86_64 1/1  
Verifying : iputils-20190515-3.fc31.x86_64 1/1

Installed:  
iputils-20190515-3.fc31.x86_64

Complete!  
Elapsed Time: 0:06.85

# ctr30=$(buildah from fedora:30)  
# time -f 'Elapsed Time: %E' buildah run -v /var/cache/dnf/30:/var/cache/dnf:O ${ctr30} dnf -y install iputils  
Last metadata expiration check: 0:00:15 ago on Wed Feb 5 14:17:47 2020.  
Dependencies resolved.  
================================================================================  
Package Architecture Version Repository Size  
================================================================================  
Installing:  
iputils x86_64 20180629-4.fc30 fedora 123 k

Transaction Summary  
================================================================================  
Install 1 Package

Total download size: 123 k  
Installed size: 351 k  
Downloading Packages:  
iputils-20180629-4.fc30.x86_64.rpm 370 kB/s | 123 kB 00:00  
--------------------------------------------------------------------------------  
Total 138 kB/s | 123 kB 00:00  
Running transaction check  
Transaction check succeeded.  
Running transaction test  
Transaction test succeeded.  
Running transaction  
Preparing : 1/1  
Installing : iputils-20180629-4.fc30.x86_64 1/1  
Running scriptlet: iputils-20180629-4.fc30.x86_64 1/1  
Verifying : iputils-20180629-4.fc30.x86_64 1/1

Installed:  
iputils-20180629-4.fc30.x86_64

Complete!  
Elapsed Time: 0:08.88  

Come puoi vedere, siamo stati in grado di eseguire i contenitori Buildah utilizzando il dnf cache da due diverse versioni di Fedora dallo stesso host di build e i container per Fedora 31 hanno impiegato più di 6 secondi e la build di Fedora 30 ha impiegato più di 8 secondi.

Nota:ho scelto una sottodirectory di /var/cache/dnf per i file di cache, per assicurarsi che le etichette di SELinux fossero corrette. Basta eseguire dnf clean all non pulirà /var/cache/dnf/31 . Dovresti eseguire dnf clean all --setopt=cachedir=/var/cache/dnf/31 per pulire correttamente i file memorizzati nella cache del repository, ma alcuni artefatti rimarranno comunque (chiavi gpg, directory vuote).

Ora, solo per vedere quanto tempo ci vorrebbe per eseguire la build su Fedora 31 senza il supporto Overlay.

# ctr31=$(buildah from fedora:31)  
# time -f 'Elapsed Time: %E' buildah run ${ctr31} dnf -y install iputils  
Fedora Modular 31 - x86_64 1.2 MB/s | 5.2 MB 00:04  
Fedora Modular 31 - x86_64 - Updates 875 kB/s | 4.0 MB 00:04  
Fedora 31 - x86_64 - Updates 2.4 MB/s | 19 MB 00:07  
Fedora 31 - x86_64 1.7 MB/s | 71 MB 00:41  
Dependencies resolved.  
================================================================================  
Package Architecture Version Repository Size  
================================================================================  
Installing:  
iputils x86_64 20190515-3.fc31 fedora 141 k

Transaction Summary  
================================================================================  
Install 1 Package

Total download size: 141 k  
Installed size: 387 k  
Downloading Packages:  
iputils-20190515-3.fc31.x86_64.rpm 279 kB/s | 141 kB 00:00  
--------------------------------------------------------------------------------  
Total 129 kB/s | 141 kB 00:01  
Running transaction check  
Transaction check succeeded.  
Running transaction test  
Transaction test succeeded.  
Running transaction  
Preparing : 1/1  
Installing : iputils-20190515-3.fc31.x86_64 1/1  
Running scriptlet: iputils-20190515-3.fc31.x86_64 1/1  
Verifying : iputils-20190515-3.fc31.x86_64 1/1

Installed:  
iputils-20190515-3.fc31.x86_64

Complete!  
Elapsed Time: 1:29.85  

In questo caso, ci sono voluti quasi 1,5 minuti per eseguire lo stesso container. Buildah con le cavalcature Overlay è stato eseguito 14 volte più velocemente.

Contenitori senza radici

Tutti i miei esempi fino ad ora hanno eseguito le build utilizzando Containerfiles come radice. Ma puoi farlo anche con contenitori senza radici. Nei prossimi due esempi, farò in modo che Buildah esegua i container usando buildah run sintassi per dimostrare l'utilizzo della cache.

In esecuzione

$ buildah run -v /var/cache/dnf/30:/var/cache/dnf:O ${ctr30} dnf -y install iputils  

funziona bene. Finché l'utente può leggere il /var/cache/dnf/30 directory, il lower è possibile leggere la directory. Ma devi fare affidamento su qualcosa sull'host per aggiornare periodicamente la cache.

Se gli utenti lo desiderano possono persino utilizzare dnf per creare la cache nella loro home directory.

$ dnf -y makecache --releasever=30 --setopt=cachedir=$HOME/dnfcache  
$ chcon --reference /var/cache/dnf -R $HOME/dnfcache  
$ ctr30=$(buildah from fedora:30)  
$ buildah run -v $HOME/dnfcache:/var/cache/dnf:O ${ctr30} dnf -y install iputils  

Nota che ho dovuto cambiare l'etichetta SELinux di $HOME/dnfcache directory in modo che SELinux consenta ai contenitori di leggere il lower directory per il montaggio Overlay.

Conclusione

L'accelerazione della compilazione dei contenitori richiede la comprensione di ciò che accade durante l'installazione dei pacchetti. Memorizzazione nella cache di dnf dati sull'host e l'utilizzo di montaggi overlay per montare la cache nel contenitore con Buildah può aumentare notevolmente la velocità delle build e ridurre il numero di risorse necessarie per supportare una build farm.

Buildah è sinonimo di semplicità, ma ha anche alcune fantastiche funzionalità come Overlay mounts e additional stores che può aiutarti a velocizzare le build di immagini del contenitore.

[ Nuovo per i container? Scarica Containers Primer e impara le basi dei container Linux. ]


Linux
  1. Ripara un'immagine di sistema con DISM

  2. Usa gli stati delle attività con l'imaging del server

  3. Ottimizzazione delle immagini con webp

  4. Elenca tutti i file di immagini grafiche con find?

  5. Cosa c'è all'interno di un'immagine/contenitore Docker?

Come lavorare con i gruppi di pacchetti dnf

Come clonare un'immagine del disco crittografata con Clonezilla

Come installare il software con Yum/Dnf utilizzando l'immagine ISO RHEL

La guida definitiva alla manipolazione delle immagini con ImageMagick

Come creare un'immagine di Windows Docker con il tag di build Docker

Guida introduttiva a Buildah per la gestione dei container Linux