GNU/Linux >> Tutoriels Linux >  >> Linux

Accélérer la création d'images de conteneurs avec Buildah

Il y a quelques mois, j'ai écrit un article sur l'accélération de la construction de conteneurs à l'intérieur d'un conteneur. Cet article s'est concentré sur la vitesse d'extraction des images de conteneurs et sur les différentes manières de préremplir le magasin d'images, en utilisant les montages de volume de l'hôte et le concept Buildah de "magasins supplémentaires".

Buildah est un outil de ligne de commande permettant de créer rapidement et facilement des images compatibles avec l'Open Container Initiative (c'est-à-dire compatibles avec Docker et Kubernetes). Buildah est facile à intégrer dans des scripts et à créer des pipelines, et surtout, il ne nécessite pas de démon de conteneur en cours d'exécution pour créer son image.

Cet article abordera un deuxième problème avec la vitesse de construction lors de l'utilisation de dnf /yum commandes à l'intérieur des conteneurs. Notez que dans cet article j'utiliserai le nom dnf (qui est le nom en amont) au lieu de ce que certains utilisateurs en aval utilisent (yum ) Ces commentaires s'appliquent à la fois à dnf et yum .

Vitesse de téléchargement

Avez-vous déjà remarqué que, parfois, lorsque vous exécutez dnf -y update ou dnf -y install pour la première fois depuis longtemps, la commande s'interrompt longtemps avant même de commencer à réduire les RPM ? Que se passe-t-il ?

La première chose que dnf est de télécharger d'énormes fichiers de cache. Ces fichiers sont écrits en XML et contiennent chaque package du référentiel distant, y compris de nombreuses données sur le package. Ils contiennent même tous les chemins du package. Ces données sont nécessaires pour que vous puissiez exécuter quelque chose comme dnf -y install /usr/bin/httpd puis dnf détermine le paquet à installer. De nombreux packages contiennent des commandes telles que (requires: /usr/bin/sendmail ) qui tirent parti de cette fonctionnalité, en autorisant dnf pour tirer un package approprié pour satisfaire le besoin.

L'extraction de ces fichiers volumineux, et plus important encore, leur traitement, peut prendre plus d'une minute. Ces données sont utilisées par libsolv , il doit donc être converti en solv format, qui est lent. La vitesse n'est pas un gros problème lorsque vous ne le faites que périodiquement sur votre hôte, mais lorsqu'il s'agit de créer des conteneurs, c'est beaucoup plus important.

Syntaxe Dockerfile

Bien que Buildah vous permette de créer des images de conteneurs directement dans le shell, la plupart des gens utilisent Dockerfiles et Containerfiles pour créer des conteneurs et définir des recettes d'images reproductibles. Buildah recherche par défaut un Containerfile et un Dockerfile à présent. Chacun partage la même syntaxe, je vais donc utiliser Containerfile pour le reste de ce document.

Une chose courante à faire dans un Containerfile est d'utiliser une syntaxe du type :

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

Examinons le dnf lignes. Le premier dnf ligne :

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

  1. Met à jour tous les packages du conteneur.
  2. Installe le package sélectionné nginx .
  3. Nettoie tout.

Depuis ubi8 l'image a probablement été créée il y a quelque temps et son /var/cache/dnf le répertoire n'existe probablement pas dans l'image du conteneur, dnf doit extraire le fichier cache XML et le traiter. Ensuite, dnf installe les packages réels avant dnf -y clean all supprime toutes les données en excès que les commandes précédentes ont placées dans l'image, comme les fichiers journaux et de cache.

Il est recommandé aux utilisateurs d'exécuter clean all pour garder l'image aussi petite que possible. Chaque RUN La commande crée un nouveau calque, et même si vous supprimez le contenu dans un RUN ultérieur commande, la couche initiale contiendra tout le contenu. Cela signifie que tous ceux qui extraient votre image finiront par extraire les journaux et les fichiers de cache. Maintenant, si votre Containerfile contient un ou plusieurs dnf commandes, vous en paierez le prix encore et encore. Non seulement cela, mais chaque fois que vous reconstruisez cette image, vous paierez à nouveau ce prix. Si vous êtes sur un serveur de compilation, chaque image de conteneur que vous créez téléchargera ces fichiers XML encore et encore, ce qui vous fera perdre des tonnes de ressources et de temps.

Buildah avec des supports superposés

Nous avons vu le problème décrit ci-dessus et avons pensé que nous pourrions mieux le gérer. Ne pourrions-nous pas simplement extraire les données XML vers l'hôte, les traiter sur l'hôte et les monter en volume dans les conteneurs ? Peut-être pourrions-nous mettre en place une tâche cron ou un systemd timer qui fait un dnf makecache une fois pour chaque version des systèmes d'exploitation pour lesquels vous allez créer des images de conteneur ? Vous pouvez exécuter cette tâche une ou plusieurs fois par jour sur l'hôte, puis demander à tous les volumes de création de conteneurs de monter les caches appropriés dans les conteneurs buildah.

Eh bien, Buildah prend en charge les répertoires de montage de volume de l'hôte dans les conteneurs. Cela devrait résoudre le problème, et c'est le cas. MAIS, les conteneurs veulent souvent écrire dans ce répertoire, s'ils doivent mettre à jour le cache, donc le cache doit être monté dans les conteneurs en lecture/écriture. Cela provoque un énorme trou de sécurité. Imaginez une situation dans laquelle une construction de conteneur hostile écrit du contenu dans ce cache qu'un constructeur de conteneur ultérieur lit. Cela pourrait éventuellement inciter le deuxième conteneur à installer un logiciel piraté. Nous avons besoin d'une solution où le contenu est monté dans le conteneur, ne peut pas être écrit par le conteneur, mais toujours écrit du point de vue du conteneur. C'est fondamentalement ce qu'est un point de montage de superposition.

Le système de fichiers de superposition monte un lower répertoire, puis attache un upper répertoire vers le merged point de montage. Lorsqu'un processus écrit dans un nouveau fichier dans le merged répertoire, le nouveau fichier est écrit dans le upper annuaire. Lorsqu'un processus modifie un fichier existant dans le lower répertoire, le noyau copie le fichier depuis le répertoire lower répertoire vers le upper répertoire et permet au processus de modifier le fichier dans le upper répertoire.

Nous avons introduit le concept de la monture Overlay dans Buildah. Vous pouvez maintenant exécuter des builds avec

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

Dnf à l'intérieur du conteneur vérifiera toujours s'il y a du contenu plus récent dans les dépôts et extraira le contenu s'il existe. Mais si le contenu de l'hôte est à jour, il utilisera rapidement le cache de l'hôte. Je vous recommande de mettre à jour le cache des hôtes au moins une fois par jour.

Une fonctionnalité supplémentaire que nous avons ajoutée pour le montage Buildah Overlay est de détruire le upper répertoire à chaque RUN directif. Rappelons dans notre exemple, nous avons utilisé plusieurs RUN commandes qui exécutaient chacune un dnf -y clean all . Le dnf -y clean all commande provoque le upper répertoire pour afficher tout le contenu du bas comme supprimé. Si le prochain dnf La commande partageait la partie supérieure précédente, elle verrait le cache comme vide et devrait extraire le magasin de données XML et le traiter. Suppression du upper répertoire signifie que chaque dnf la commande verra à nouveau le lower répertoire de l'hôte et continuez à partager le cache des hôtes.

Différence de vitesse

Je vais créer un simple Containerfile contenant deux dnf exécuter des commandes.

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

Exécuter ceci localement sur ma boîte 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  

Cette exécution a pris 2 minutes et 15 secondes pour créer une nouvelle image de conteneur avec les deux nouveaux packages.

Essayons maintenant avec un montage Overlay de l'hôte.

# 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  

Avec le montage Overlay, nous avons pu construire une nouvelle image avec les deux packages supplémentaires en 17 secondes au lieu de 2 minutes et 15 secondes. C'est presque 8 fois plus rapide pour créer la même image de conteneur.

Maintenant, cela montre que si vous créez des images sur un système d'exploitation hôte qui a le dnf métadonnées pré-cachées, vous pouvez accélérer considérablement la vitesse d'installation. Mais que se passe-t-il si votre système de build crée des images pour d'autres versions du système d'exploitation ? Supposons que vous souhaitiez créer des images pour Fedora 30 ainsi que Fedora 31. Remarque :cela fonctionnerait également sur un système RHEL8, où vous pourriez vouloir créer des images RHEL7 et peut-être même RHEL6.
Dnf inclut une fonctionnalité intéressante où vous pouvez spécifier différentes versions lors de l'extraction de contenu, en utilisant le --releasever option. Dnf vous permet également de spécifier des répertoires alternatifs pour placer le cachedir, --setopt=cachedir .

Dans l'exemple suivant, je vais extraire deux caches sur l'hôte, puis utiliser Buildah en mode ligne de commande.

# 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  

Comme vous pouvez le voir, nous avons pu exécuter des conteneurs Buildah en utilisant le dnf cache de deux versions différentes de Fedora à partir du même hôte de construction et les conteneurs pour Fedora 31 ont pris plus de 6 secondes et la construction de Fedora 30 a pris plus de 8 secondes.

Remarque :J'ai choisi un sous-répertoire de /var/cache/dnf pour les fichiers de cache, pour s'assurer que les étiquettes SELinux étaient correctes. Exécutez simplement dnf clean all ne nettoiera pas /var/cache/dnf/31 . Vous devrez exécuter dnf clean all --setopt=cachedir=/var/cache/dnf/31 pour nettoyer correctement les fichiers mis en cache du référentiel, mais certains artefacts resteront quand même (clés gpg, répertoires vides).

Maintenant, juste pour voir combien de temps cela prendrait pour exécuter la version sur Fedora 31 sans le montage 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  

Dans ce cas, il a fallu près d'une minute et demie pour exécuter le même conteneur. Buildah avec des montures superposées a fonctionné 14 fois plus vite.

Conteneurs sans racine

Jusqu'à présent, tous mes exemples ont exécuté les builds à l'aide de Containerfiles en tant que racine. Mais vous pouvez également le faire avec des conteneurs sans racine. Dans les deux prochains exemples, j'aurai des conteneurs d'exécution Buildah en utilisant le buildah run syntaxe pour démontrer l'utilisation du cache.

Exécution

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

fonctionne bien. Tant que l'utilisateur peut lire le /var/cache/dnf/30 répertoire, le lower répertoire peut être lu. Mais vous devez compter sur quelque chose sur l'hôte pour mettre à jour le cache périodiquement.

Si les utilisateurs le souhaitent, ils peuvent même utiliser dnf pour créer le cache dans leur répertoire personnel.

$ 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  

Remarquez que j'ai dû changer l'étiquette SELinux du $HOME/dnfcache répertoire afin que SELinux autorise les conteneurs à lire le lower répertoire pour le montage Overlay.

Conclusion

Accélérer la construction de conteneurs nécessite de comprendre ce qui se passe lorsque vous installez des packages. Pré-cache dnf les données sur l'hôte et l'utilisation de montages superposés pour monter le cache dans le conteneur avec Buildah peuvent considérablement augmenter la vitesse des builds et réduire le nombre de ressources nécessaires pour prendre en charge une batterie de builds.

Buildah est synonyme de simplicité, mais il possède également des fonctionnalités intéressantes telles que les Overlay mounts et additional stores qui peut vous aider à accélérer la création de vos images de conteneur.

[ Nouveau dans les conteneurs ? Téléchargez le Containers Primer et apprenez les bases des conteneurs Linux. ]


Linux
  1. Répertorier tous les fichiers d'images graphiques avec rechercher ?

  2. Que contient une image/un conteneur Docker ?

  3. Valider les données dans un conteneur mysql

  4. Comment copier une image ISO sur USB avec dd

  5. Réglage du noyau avec le conteneur Docker privilégié

Comment travailler avec les groupes de packages dnf

Comment cloner une image disque cryptée avec Clonezilla

Comment installer un logiciel avec Yum/Dnf à l'aide de l'image ISO RHEL

Le guide ultime de la manipulation d'images avec ImageMagick

Comment créer une image Windows Docker avec la balise Docker Build

Premiers pas avec Buildah pour la gestion des conteneurs Linux