Pautas para ejecutar Buildah dentro de un contenedor

¿Cuál es la belleza de separar el tiempo de ejecución del contenedor en componentes de herramientas separados? En particular, el hecho de que estas herramientas puedan comenzar a combinarse para que se protejan entre sí.

Pautas para ejecutar Buildah dentro de un contenedor

Muchas personas se sienten atraídas por la idea de construir imágenes de contenedores OCI dentro de Kubernetes o sistema similar. Digamos que tenemos un CI/CD que crea imágenes constantemente, entonces algo como Red Hat OpenShift/Kubernetes sería muy útil en términos de equilibrio de carga de compilación. Hasta hace poco, la mayoría de las personas simplemente daban acceso a los contenedores a un socket de Docker y les permitían ejecutar el comando de compilación de docker. Mostramos hace unos añosque esto es muy inseguro, de hecho, es incluso peor que dar root sin contraseña o sudo.

Entonces, las personas intentan constantemente ejecutar Buildah en un contenedor. En resumen, hemos creado ejemplo cómo, en nuestra opinión, es mejor ejecutar Buildah dentro de un contenedor y publicar las imágenes correspondientes en muelle.io/buildah. Empecemos...

Ajuste

Estas imágenes se crean a partir de Dockerfiles, que se pueden encontrar en el repositorio de Buildah en la carpeta imagenconstruida.
Aquí consideraremos versión estable de Dockerfile.

# stable/Dockerfile
#
# Build a Buildah container image from the latest
# stable version of Buildah on the Fedoras Updates System.
# https://bodhi.fedoraproject.org/updates/?search=buildah
# This image can be used to create a secured container
# that runs safely with privileges within the container.
#
FROM fedora:latest

# Don't include container-selinux and remove
# directories used by dnf that are just taking
# up space.
RUN yum -y install buildah fuse-overlayfs --exclude container-selinux; rm -rf /var/cache /var/log/dnf* /var/log/yum.*

# Adjust storage.conf to enable Fuse storage.
RUN sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' /etc/containers/storage.conf

En lugar de OverlayFS implementado a nivel del kernel de Linux del host, usamos el programa dentro del contenedor superposición de fusibles, porque actualmente OverlayFS solo puede montarse si le otorga permisos SYS_ADMIN a través de las capacidades de Linux. Y queremos ejecutar nuestros contenedores Buildah sin privilegios de root. Fuse-overlay es bastante rápido y funciona mejor que el controlador de almacenamiento VFS. Tenga en cuenta que cuando se ejecuta un contenedor Buildah con Fuse, se debe proporcionar el dispositivo /dev/fuse.

podman run --device /dev/fuse quay.io/buildahctr ...
RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock

A continuación, creamos un directorio para repositorios adicionales. contenedor/almacenamiento admite el concepto de conectar repositorios de imágenes adicionales de solo lectura. Por ejemplo, puede configurar un área de almacenamiento de superposición en una máquina y luego usar NFS para montar este almacenamiento en otra máquina y usar imágenes de ella sin descargar mediante extracción. Necesitamos este almacenamiento para poder conectar algo de almacenamiento de imágenes del host como un volumen y usarlo dentro del contenedor.

# Set up environment variables to note that this is
# not starting with user namespace and default to
# isolate the filesystem with chroot.
ENV _BUILDAH_STARTED_IN_USERNS="" BUILDAH_ISOLATION=chroot

Finalmente, usamos la variable de entorno BUILDAH_ISOLATION para decirle al contenedor Buildah que comience con el aislamiento chroot de forma predeterminada. Aquí no se requiere aislamiento adicional, ya que estamos trabajando en un contenedor. Para que Buildah pueda crear sus propios contenedores separados por espacios de nombres, se requiere el privilegio SYS_ADMIN, lo que requeriría relajar las reglas SELinux y SECOMP del contenedor, lo que entraría en conflicto con nuestra configuración para compilar desde un contenedor seguro.

Ejecute Buildah dentro de un contenedor

El esquema de imagen de contenedor de Buildah discutido anteriormente le permite variar de manera flexible cómo se lanzan dichos contenedores.

Velocidad versus seguridad

La seguridad informática siempre es un compromiso entre la velocidad de un proceso y la cantidad de protección que lo rodea. Esta declaración también es cierta cuando se ensamblan contenedores, por lo que a continuación consideraremos opciones para tal compromiso.

La imagen del contenedor discutida anteriormente mantendrá su almacenamiento en /var/lib/containers. Por lo tanto, necesitamos montar contenido en esta carpeta, y la forma en que lo hagamos afectará en gran medida la velocidad de creación de imágenes de contenedores.

Consideremos tres opciones.

1 opción. Si se requiere la máxima seguridad, entonces para cada contenedor puede crear su propia carpeta para contenedores / imagen y conectarla al contenedor a través del montaje de volumen. Y además, coloque el directorio de contexto en el propio contenedor, en la carpeta /build:

# mkdir /var/lib/containers1
# podman run -v ./build:/build:z -v /var/lib/containers1:/var/lib/containers:Z quay.io/buildah/stable
buildah  -t image1 bud /build
# podman run -v /var/lib/containers1:/var/lib/containers:Z quay.io/buildah/stable buildah  push  image1 registry.company.com/myuser
# rm -rf /var/lib/containers1

Seguridad. Un Buildah que se ejecuta en un contenedor de este tipo tiene la máxima seguridad: las capacidades no le otorgan ningún privilegio de raíz, y se le aplican todas las restricciones de SECOMP y SELinux. Tal contenedor puede incluso ejecutarse con el aislamiento del espacio de nombres de usuario agregando una opción como --uidmap 0:100000:10000.

Rendimiento Pero el rendimiento aquí es mínimo, ya que todas las imágenes de los registros del contenedor se copian en el host cada vez, y el almacenamiento en caché no funciona a partir de la palabra "de ninguna manera". Cuando termina su trabajo, el contenedor Buildah debe enviar la imagen al registro y destruir el contenido en el host. La próxima vez que se construya la imagen del contenedor, deberá descargarse nuevamente del registro, ya que en ese momento no quedará nada en el host.

2 opción. Si necesita un rendimiento a nivel de Docker, puede montar el contenedor/almacenamiento del host directamente en el contenedor.

# podman run -v ./build:/build:z -v /var/lib/containers:/var/lib/containers --security-opt label:disabled quay.io/buildah/stable buildah  -t image2 bud /build
# podman run -v /var/lib/containers:/var/lib/containers --security-opt label:disabled  quay.io/buildah/stable buildah push image2 registry.company.com/myuser

Seguridad. Esta es la forma menos segura de crear contenedores, ya que permite que el contenedor modifique el almacenamiento en el host y podría introducir una imagen maliciosa en Podman o CRI-O. Además, deberá deshabilitar la separación de SELinux para que los procesos en el contenedor Buildah puedan interactuar con el repositorio en el host. Tenga en cuenta que esta opción sigue siendo mejor que un socket de Docker, ya que el contenedor está bloqueado por las funciones de seguridad restantes y no puede simplemente seleccionar y ejecutar ningún contenedor en el host.

Rendimiento Aquí es máximo, ya que el almacenamiento en caché está completamente involucrado. Si Podman o CRI-O ya descargaron la imagen deseada en el host, entonces el proceso Buildah dentro del contenedor no tendrá que volver a descargarlo, y las compilaciones posteriores basadas en esta imagen también podrán tomar la imagen necesaria del caché. .

3 opción. La esencia de este método es combinar varias imágenes en un proyecto con una carpeta común para imágenes contenedoras.

# mkdir /var/lib/project3
# podman run --security-opt label_level=s0:C100, C200 -v ./build:/build:z 
-v /var/lib/project3:/var/lib/containers:Z quay.io/buildah/stable buildah  -t image3 bud /build
# podman run --security-opt label_level=s0:C100, C200 
-v /var/lib/project3:/var/lib/containers quay.io/buildah/stable buildah push image3  registry.company.com/myuser

En este ejemplo, no eliminamos la carpeta del proyecto (/var/lib/project3) entre ejecuciones, por lo que todas las compilaciones posteriores dentro del proyecto aprovechan el almacenamiento en caché.

Seguridad. Algo entre las opciones 1 y 2. Por un lado, los contenedores no tienen acceso al contenido del host y, en consecuencia, no pueden colar algo malo en el almacenamiento de imágenes de Podman/CRI-O. Por otro lado, dentro de su propio proyecto, un contenedor puede interferir con el montaje de otros contenedores.

Rendimiento Aquí es peor que usar un caché compartido a nivel de host, ya que no puedes usar imágenes que ya se hayan descargado usando Podman/CRI-O. Sin embargo, una vez que Buildah haya descargado la imagen, esa imagen se puede usar en cualquier compilación posterior dentro del proyecto.

Almacenamiento adicional

У contenedores/almacenamiento hay algo tan bueno como las tiendas adicionales (tiendas adicionales), gracias a las cuales, al iniciar y construir contenedores, los motores de contenedores pueden usar tiendas de imágenes externas en modo de superposición de solo lectura. De hecho, puede agregar uno o más almacenamientos de solo lectura al archivo storage.conf, de modo que cuando se inicie el contenedor, el motor del contenedor buscará la imagen deseada en ellos. Además, descargará la imagen del registro solo si no la encuentra en ninguno de estos almacenamientos. El motor del contenedor solo podrá escribir en el almacenamiento grabable...

Si nos desplazamos hacia arriba y miramos el Dockerfile que usamos para construir la imagen quay.io/buildah/stable, hay líneas como esta:

# Adjust storage.conf to enable Fuse storage.
RUN sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' /etc/containers/storage.conf
RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock

En la primera línea, modificamos /etc/containers/storage.conf dentro de la imagen del contenedor, diciéndole al controlador de almacenamiento que use "almacenes de imágenes adicionales" en la carpeta /var/lib/shared. Y en la siguiente línea, creamos una carpeta compartida y agregamos un par de archivos de bloqueo para que no haya abuso de contenedores/almacenamiento. Esencialmente, solo estamos creando un almacén de imágenes de contenedor vacío.

Si monta contenedores/almacenamiento un nivel por encima de esta carpeta, Buildah podrá usar las imágenes.

Ahora volvamos a la Opción 2 discutida anteriormente, cuando el contenedor Buildah puede leer y escribir en contenedores/almacenar en hosts y, en consecuencia, tiene el máximo rendimiento debido al almacenamiento en caché de imágenes en el nivel de Podman/CRI-O, pero ofrece un mínimo de seguridad. ya que puede escribir directamente en el almacenamiento. Y ahora agregaremos almacenamiento adicional aquí y obtendremos lo mejor de ambos mundos.

# mkdir /var/lib/containers4
# podman run -v ./build:/build:z -v /var/lib/containers/storage:/var/lib/shared:ro -v  /var/lib/containers4:/var/lib/containers:Z  quay.io/buildah/stable 
 buildah  -t image4 bud /build
# podman run -v /var/lib/containers/storage:/var/lib/shared:ro  
-v >/var/lib/containers4:/var/lib/containers:Z quay.io/buildah/stable buildah push image4  registry.company.com/myuser
# rm -rf /var/lib/continers4

Tenga en cuenta que el /var/lib/containers/storage del host está montado en /var/lib/shared dentro del contenedor en modo de solo lectura. Por lo tanto, al trabajar en un contenedor, Buildah puede usar cualquier imagen que ya se haya descargado usando Podman / CRI-O (hola, velocidad), pero solo puede escribir en su propio almacenamiento (hola, seguridad). También tenga en cuenta que esto se hace sin deshabilitar la separación de SELinux para el contenedor.

Matiz importante

Bajo ninguna circunstancia se debe eliminar ninguna imagen del repositorio subyacente. De lo contrario, el contenedor Buildah puede bloquearse.

Y esos no son todos los beneficios.

Las posibilidades de almacenamiento adicional no se limitan al escenario anterior. Por ejemplo, puede colocar todas las imágenes de contenedores en un almacenamiento de red compartido y dar acceso a todos los contenedores de Buildah. Digamos que tenemos cientos de imágenes que nuestro sistema de CI/CD usa regularmente para crear imágenes en contenedores. Concentramos todas estas imágenes en un único host de almacenamiento y luego, utilizando las herramientas de almacenamiento en red preferidas (NFS, Gluster, Ceph, iSCSI, S3...), compartimos este almacenamiento con todos los nodos de Buildah o Kubernetes.

Ahora es suficiente montar este almacenamiento de red en el contenedor Buildah en /var/lib/shared y eso es todo: los contenedores Buildah ya no tienen que descargar imágenes a través de pull. Así, descartamos la fase de prepoblación y estamos inmediatamente listos para desplegar los contenedores.

Y, por supuesto, esto se puede usar dentro de un sistema Kubernetes en vivo o una infraestructura de contenedores para lanzar y ejecutar contenedores en cualquier lugar sin necesidad de extraer imágenes. Además, cuando un registro de contenedores recibe una solicitud de inserción para cargar una imagen actualizada, puede enviar automáticamente esta imagen a un almacenamiento de red compartido, donde está disponible instantáneamente para todos los nodos.

Las imágenes de contenedor a veces pueden tener muchos gigabytes de tamaño. La funcionalidad de almacenamientos adicionales elimina la necesidad de clonar tales imágenes por nodos y hace que el lanzamiento de contenedores sea casi instantáneo.

Además, actualmente estamos trabajando en una nueva función de montajes de volumen superpuestos que hará que la construcción de contenedores sea aún más rápida.

Conclusión

Ejecutar Buildah dentro de un contenedor en un entorno Kubernetes/CRI-O, Podman o incluso Docker es bastante posible, y es simple y mucho más seguro que usar docker.socket. Hemos aumentado considerablemente la flexibilidad de trabajar con imágenes y ahora puede ejecutarlas de varias formas para obtener el mejor equilibrio entre seguridad y rendimiento.

La funcionalidad de almacenamientos adicionales le permite acelerar o incluso eliminar por completo la descarga de imágenes a los nodos.

Fuente: habr.com

Añadir un comentario