GNU/Linux >> Tutoriales Linux >  >> Linux

Acelerar la creación de imágenes de contenedores con Buildah

Hace unos meses, escribí un artículo sobre cómo acelerar la construcción de contenedores dentro de un contenedor. Ese artículo se concentró en la velocidad de extracción de imágenes de contenedores y las diferentes formas de rellenar previamente el almacén de imágenes, utilizando montajes de volumen del host y el concepto Buildah de "almacenes adicionales".

Buildah es una herramienta de línea de comandos para crear imágenes compatibles con Open Container Initiative (es decir, también compatibles con Docker y Kubernetes) de forma rápida y sencilla. Buildah es fácil de incorporar en secuencias de comandos y canalizaciones de compilación y, lo mejor de todo, no requiere un demonio de contenedor en ejecución para compilar su imagen.

Este artículo abordará un segundo problema con la velocidad de compilación cuando se usa dnf /yum Comandos dentro de contenedores. Tenga en cuenta que en este artículo usaré el nombre dnf (que es el nombre ascendente) en lugar de lo que usan algunos descendentes (yum ) Estos comentarios se aplican tanto a dnf y yum .

Velocidad de descarga

¿Alguna vez notaste que a veces cuando ejecutas dnf -y update o dnf -y install por primera vez en mucho tiempo, el comando se detiene durante mucho tiempo antes de que comience a reducir los RPM? ¿Qué está pasando?

Lo primero que dnf lo que hace es descargar enormes archivos de caché. Estos archivos están escritos en XML y contienen todos los paquetes del repositorio remoto, incluidos muchos datos sobre el paquete. Incluso contienen todas las rutas dentro del paquete. Estos datos son necesarios para que cuando pueda ejecutar algo como dnf -y install /usr/bin/httpd y luego dnf averigua el paquete a instalar. Muchos paquetes contienen comandos como (requires: /usr/bin/sendmail ) que aprovechan esta característica, lo que permite dnf para sacar un paquete apropiado para satisfacer la necesidad.

Extraer estos enormes archivos y, lo que es más importante, procesarlos, puede llevar más de un minuto. Estos datos son utilizados por libsolv , por lo que debe convertirse a solv formato, que es lento. La velocidad no es un gran problema cuando solo hace esto periódicamente en su host, pero cuando se trata de crear contenedores, esto es mucho más importante.

Sintaxis del archivo Docker

Aunque Buildah le permite crear imágenes de contenedores directamente en el shell, la mayoría de las personas usan Dockerfiles y Containerfiles para crear contenedores y definir recetas de imágenes reproducibles. Buildah busca por defecto un Containerfile y un Dockerfile ahora. Cada uno comparte la misma sintaxis, así que usaré Containerfile para el resto de este documento.

Algo común que hacer en un Containerfile es usar una sintaxis como:

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

Examinemos el dnf líneas. El primer dnf línea:

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

  1. Actualiza todos los paquetes dentro del contenedor.
  2. Instala el paquete seleccionado nginx .
  3. Limpia todo.

Desde el ubi8 la imagen probablemente se creó hace un tiempo y su /var/cache/dnf el directorio probablemente no existe dentro de la imagen del contenedor, dnf debe extraer el archivo de caché XML y procesarlo. Luego, dnf instala los paquetes reales antes de dnf -y clean all elimina todo el exceso de datos que los comandos anteriores colocaron en la imagen, como archivos de registro y caché.

Se recomienda a los usuarios ejecutar clean all para mantener la imagen lo más pequeña posible. Cada RUN El comando crea una nueva capa, e incluso si elimina el contenido en un RUN posterior comando, la capa inicial contendrá todo el contenido. Esto significa que todos los que alguna vez extraigan su imagen terminarán extrayendo los registros y los archivos de caché. Ahora, si su Containerfile contiene uno o más dnf comandos, pagarás el precio una y otra vez. No solo eso, sino que cada vez que reconstruyas esta imagen, pagarás ese precio una vez más. Si está en un servidor de compilación, cada imagen de contenedor que cree descargará estos archivos XML una y otra vez, desperdiciando toneladas de recursos y tiempo.

Buildah con monturas superpuestas

Vimos el problema descrito anteriormente y pensamos que podríamos manejarlo de una mejor manera. ¿No podríamos simplemente extraer los datos XML al host, procesarlos en el host y montarlos en volumen en los contenedores? Tal vez podríamos configurar un trabajo cron o un systemd temporizador que hace un dnf makecache una vez por cada versión de los sistemas operativos para los que creará imágenes de contenedor? Puede ejecutar este trabajo una o varias veces al día en el host y luego hacer que todo el volumen de los constructores de contenedores monte las memorias caché adecuadas en los contenedores de compilación.

Bueno, Buildah admite directorios de montaje de volumen desde el host a los contenedores. Eso debería resolver el problema, y ​​lo hace. PERO, los contenedores a menudo quieren escribir en este directorio, si tienen que actualizar el caché, por lo que el caché debe montarse en los contenedores de lectura/escritura. Esto provoca un gran agujero de seguridad. Imagine una situación en la que una compilación de contenedor hostil escribió contenido en esta memoria caché que leyó un compilador de contenedor posterior. Posiblemente podría engañar al segundo contenedor para que instale software pirateado. Necesitamos una solución en la que el contenido se monte en el contenedor, el contenedor no pueda escribirlo, pero aún así se puede escribir desde la perspectiva del contenedor. Esto es fundamentalmente lo que es un punto de montaje superpuesto.

El sistema de archivos de superposición se monta en un lower directorio y luego adjunta un upper directorio al merged punto de montaje. Cuando un proceso escribe en un nuevo archivo en merged directorio, el nuevo archivo se escribe en el upper directorio. Cuando un proceso modifica un archivo existente en el lower directorio, el kernel copia el archivo desde el lower directorio al upper directorio y permite que el proceso modifique el archivo en el upper directorio.

Introdujimos el concepto de la montura Overlay en Buildah. Ahora puedes ejecutar compilaciones con

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

Dnf dentro del contenedor aún verificará si hay contenido más nuevo en los repositorios, y bajará el contenido si existe. Pero si el contenido del host está actualizado, usará rápidamente el caché del host. Le recomendaría que actualice la memoria caché de los hosts al menos una vez al día.

Una característica adicional que agregamos para la montura Buildah Overlay es destruir la upper directorio en cada RUN directiva. Recuerde en nuestro ejemplo, usamos múltiples RUN comandos que ejecutaban cada uno un dnf -y clean all . El dnf -y clean all comando hace que el upper directorio para mostrar todo el contenido de la parte inferior como eliminado. Si el próximo dnf el comando compartió la parte superior anterior, vería el caché como vacío y tendría que desplegar el almacén de datos XML y procesarlo. Quitar el upper directorio significa que cada dnf el comando volverá a ver el lower directorio del host y continúe compartiendo la memoria caché de los hosts.

Diferencia de velocidad

Voy a crear un Containerfile simple que contiene dos dnf ejecutar comandos.

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

Ejecutando esto localmente en mi caja 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  

Esta ejecución tomó 2 minutos y 15 segundos para crear una nueva imagen de contenedor con los dos nuevos paquetes.

Ahora probemos esto con una montura superpuesta del 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 el montaje Overlay, pudimos construir una nueva imagen con los dos paquetes adicionales en 17 segundos en lugar de 2 minutos y 15 segundos. Eso es casi 8 veces más rápido para construir la misma imagen de contenedor.

Ahora bien, esto muestra que si crea imágenes en un sistema operativo host que tiene el dnf metadatos almacenados previamente en caché puede acelerar la velocidad de instalación en una cantidad ENORME. Pero, ¿qué sucede si su sistema de compilación crea imágenes para otras versiones del sistema operativo? Supongamos que desea crear imágenes para Fedora 30 y Fedora 31. Nota:esto también funcionaría en un sistema RHEL8, donde es posible que desee crear imágenes RHEL7 y tal vez incluso RHEL6.
Dnf incluye una característica genial en la que puede especificar diferentes lanzamientos al extraer contenido, usando el --releasever opción. Dnf también le permite especificar directorios alternativos para colocar el cachedir, --setopt=cachedir .

En el siguiente ejemplo, desplegaré dos cachés en el host y luego usaré Buildah en modo de línea de comandos.

# 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  

Como puede ver, pudimos ejecutar contenedores Buildah usando dnf el caché de dos versiones diferentes de Fedora del mismo host de compilación y los contenedores para Fedora 31 tardaron más de 6 segundos y la compilación de Fedora 30 tardó más de 8 segundos.

Nota:Elegí un subdirectorio de /var/cache/dnf para los archivos de caché, para asegurarse de que las etiquetas de SELinux fueran correctas. Simplemente ejecutando dnf clean all no limpiará /var/cache/dnf/31 . Debería ejecutar dnf clean all --setopt=cachedir=/var/cache/dnf/31 para limpiar correctamente los archivos en caché del repositorio, pero algunos artefactos permanecerán de todos modos (claves gpg, directorios vacíos).

Ahora solo para ver cuánto tiempo llevaría ejecutar la compilación en Fedora 31 sin el montaje 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  

En este caso, se tardó casi 1,5 minutos en ejecutar el mismo contenedor. Buildah con monturas superpuestas funcionó 14 veces más rápido.

Contenedores sin raíz

Todos mis ejemplos hasta ahora han estado ejecutando las compilaciones usando Containerfiles como raíz. Pero también puede hacer esto con contenedores sin raíz. En los próximos ejemplos, haré que Buildah ejecute contenedores usando buildah run sintaxis para demostrar el uso del caché.

Ejecutando

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

funciona bien. Siempre que el usuario pueda leer el /var/cache/dnf/30 directorio, el lower Se puede leer el directorio. Pero debe confiar en algo en el host para actualizar el caché periódicamente.

Si los usuarios quieren, pueden incluso usar dnf para crear el caché en su directorio de inicio.

$ 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  

Tenga en cuenta que tuve que cambiar la etiqueta SELinux de $HOME/dnfcache directorio para que SELinux permitiera que los contenedores leyeran el lower directorio para el montaje Overlay.

Conclusión

Acelerar la construcción de contenedores requiere una comprensión de lo que sucede cuando instala paquetes. Almacenamiento previo en caché dnf datos en el host y el uso de montajes superpuestos para montar la memoria caché en el contenedor con Buildah puede aumentar considerablemente la velocidad de las compilaciones y reducir la cantidad de recursos necesarios para admitir una granja de compilación.

Buildah es igual a simplicidad, pero también tiene algunas funciones excelentes, como Overlay mounts y additional stores que puede ayudarlo a acelerar la creación de imágenes de contenedores.

[ ¿Nuevo en contenedores? Descargue Containers Primer y aprenda los conceptos básicos de los contenedores de Linux. ]


Linux
  1. Reparar una imagen del sistema con DISM

  2. Optimización de imágenes con webp

  3. Listar todos los archivos de imágenes gráficas con find?

  4. ¿Qué hay dentro de una imagen/contenedor de Docker?

  5. Confirmar datos en un contenedor mysql

Cómo trabajar con grupos de paquetes dnf

Cómo clonar una imagen de disco cifrada con Clonezilla

Cómo instalar software con Yum/Dnf usando una imagen ISO de RHEL

La guía definitiva para la manipulación de imágenes con ImageMagick

Cómo crear una imagen de ventana de Docker con la etiqueta de compilación de Docker

Primeros pasos con Buildah para administrar contenedores de Linux