Mejores prácticas para ejecutar Buildah dentro de un contenedor

¿Cuál es la belleza de dividir el tiempo de ejecución de los contenedores en componentes instrumentales separados? En particular, el hecho de que estas herramientas pueden comenzar a combinarse para protegerse entre sí.



A muchas personas les atrae la idea de construir contenedores OCI dentro de Kubernetes o un sistema similar. Supongamos que tenemos un CI / CD que recopila imágenes constantemente, entonces algo como Red Hat OpenShift / Kubernetes sería muy útil en términos de equilibrio de carga durante el ensamblaje. Hasta hace poco, la mayoría de la gente simplemente daba acceso a los contenedores al zócalo del acoplador y se les permitía ejecutar el comando de compilación del acoplador. Hace varios años demostramos que esto es muy inseguro, de hecho, es incluso peor que dar una raíz o sudo sin contraseña.

Por lo tanto, las personas constantemente intentan ejecutar Buildah en un contenedor. En resumen, creamos un ejemplo de cómo, en nuestra opinión, es mejor ejecutar Buildah dentro del contenedor y poner las imágenes apropiadas en quay.io/buildah . Comencemos ...

Personalización


Estas imágenes se compilan a partir de Dockerfiles, que se pueden encontrar en el repositorio de Buildah en la carpeta buildahimage .
Aquí nos fijamos en la 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 en el nivel de kernel de Linux del host, usamos el programa de superposición de fusibles dentro del contenedor, porque en este momento OverlayFS puede montarse solo si se le otorgan privilegios SYS_ADMIN utilizando las capacidades de Linux. Y queremos ejecutar nuestros contenedores Buildah sin ningún privilegio de root. Fuse-overlay es bastante rápido y mejor en rendimiento que el controlador de almacenamiento VFS. Tenga en cuenta que al iniciar un contenedor Buildah con Fuse, 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 almacenamiento adicional. El contenedor / almacenamiento admite el concepto de conectar almacenamientos de imágenes adicionales de solo lectura. Por ejemplo, puede configurar el á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 él sin descargar mediante extracción. Necesitamos este almacenamiento para poder conectar algún tipo de almacenamiento de imágenes desde el 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, usando la variable de entorno BUILDAH_ISOLATION, decimos que, por defecto, el contenedor Buildah debería comenzar con el aislamiento chroot. Aquí no se requiere aislamiento adicional, ya que ya trabajamos en el contenedor. Para que Buildah cree sus propios contenedores con separación de espacios de nombre, se requiere el privilegio SYS_ADMIN, y para esto será necesario debilitar las reglas SELinux y SECCOMP para el contenedor, lo que contradice nuestra instalación para construir desde un contenedor seguro.

Ejecute Buildah dentro del contenedor


El esquema de la imagen del contenedor de Buildah discutido anteriormente le permite variar de manera flexible la forma en que ejecuta dichos contenedores.

Velocidad vs. seguridad


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

La imagen del contenedor discutida anteriormente mantendrá su repositorio en / var / lib / container. Por lo tanto, necesitamos montar el contenido en esta carpeta, y la forma en que lo hagamos afectará en gran medida la velocidad de ensamblaje de las imágenes del contenedor.

Consideremos tres opciones.

Opción 1. 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 contenedor mismo, 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 Buildah que se ejecuta en dicho contenedor tiene la máxima seguridad: no tiene privilegios de root con capacidades, y todas las restricciones de SECOMP y SELinux se aplican a él. Incluso puede ejecutar dicho contenedor con aislamiento de espacio de nombres de usuario agregando una opción como --uidmap 0: 100000: 10000 .

Rendimiento Pero el rendimiento aquí es mínimo, ya que las imágenes de los registros de contenedores se copian al host cada vez, y el almacenamiento en caché no funciona con la palabra "de ninguna manera". Al completar su trabajo, el contenedor Buildah debe enviar la imagen al registro y destruir el contenido en el host. Cuando la imagen del contenedor se recopile la próxima vez, deberá descargarla del registro nuevamente, ya que para entonces no quedará nada en el host.

Opción 2. Si necesita un rendimiento de nivel 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 construir contenedores, porque aquí el contenedor puede modificar el almacenamiento en el host, y potencialmente puede deslizarse en Podman o CRI-O una imagen maliciosa. Además, deberá deshabilitar la separación de SELinux para que los procesos en el contenedor Buildah puedan interactuar con el almacenamiento en el host. Tenga en cuenta que esta opción sigue siendo mejor que el socket Docker, ya que el contenedor está bloqueado por las funciones de seguridad restantes y no puede simplemente recoger y ejecutar cualquier contenedor en el host.

Rendimiento Aquí es máximo, ya que el almacenamiento en caché está completamente involucrado. Si Podman o CRI-O ya lograron descargar la imagen deseada al host, entonces el proceso de Buildah dentro del contenedor no tendrá que descargarlo nuevamente, y los ensambles posteriores basados ​​en esta imagen también podrán tomar lo necesario del caché.

Opción 3. La esencia de este método es combinar varias imágenes en un proyecto con una carpeta compartida para imágenes de contenedor.

 # 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 los inicios, 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 en el host y, en consecuencia, no pueden introducir algo malo en el almacenamiento de imágenes Podman / CRI-O. Por otro lado, como parte de su proyecto, un contenedor puede interferir con el ensamblaje de otros contenedores.

Rendimiento Aquí es peor que cuando se usa un caché compartido a nivel de host, ya que no puede usar imágenes ya descargadas previamente usando Podman / CRI-O. Sin embargo, después de que Buildah descarga la imagen, esta imagen se puede usar en cualquier compilación posterior dentro del proyecto.

Almacenamiento adicional


Los contenedores / almacenamiento tienen algo tan genial como tiendas adicionales, gracias a lo cual los motores de contenedores pueden usar almacenes de imágenes externas en modo de superposición de solo lectura al lanzar y construir contenedores. De hecho, puede agregar uno o más almacenamientos de solo lectura al archivo storage.conf para que cuando se inicie el contenedor, el motor del contenedor busque la imagen deseada en ellos. Además, descargará la imagen del registro solo si no la encuentra en ninguno de estos repositorios. El motor del contenedor solo podrá escribir en el almacenamiento de escritura ...

Si te desplazas hacia arriba y ves el Dockerfile, que usamos para construir la imagen quay.io/buildah/stable, entonces hay tales líneas:

 # 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 utilice "almacenes de imágenes adicionales" en la carpeta / var / lib / shared. Y en la siguiente línea, cree una carpeta compartida y agregue un par de archivos de bloqueo para que no haya abuso de los contenedores / almacenamiento. Básicamente, simplemente creamos un contenedor de almacenamiento de imágenes vacío.

Si monta contenedores / almacenamiento sobre esta carpeta, Buildah podrá usar imágenes.

Ahora volvamos a la Opción 2 discutida anteriormente, cuando un 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 Podman / CRI-O, pero ofrece un mínimo de seguridad, ya que puede escribir directamente en almacenaje Y ahora aseguraremos almacenamiento adicional aquí y obtendremos lo mejor de dos 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 host / var / lib / container / storage está montado en / var / lib / shared dentro del contenedor en modo de solo lectura. Por lo tanto, trabajando en un contenedor, Buildah puede usar cualquier imagen que se haya descargado previamente 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


En ningún caso debe eliminar ninguna imagen del almacenamiento subyacente. De lo contrario, el contenedor Buildah puede salir volando.

Y esto no es todos los beneficios.


Las capacidades de almacenamiento adicionales no se limitan al escenario anterior. Por ejemplo, puede colocar todas las imágenes de contenedor en un almacenamiento de red compartido y dar acceso a todos los contenedores de Buildah. Supongamos que tenemos cientos de imágenes que nuestro sistema CI / CD usa regularmente para construir imágenes de contenedor. Concentramos todas estas imágenes en un único host de almacenamiento y luego, utilizando las herramientas de almacenamiento de red preferidas (NFS, Gluster, Ceph, ISCSI, S3 ...), abrimos el almacenamiento compartido a 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 mediante extracción. Por lo tanto, desechamos la fase de prepoblación y estamos listos para desplegar los contenedores.

Y, por supuesto, esto se puede usar dentro del sistema Kubernetes existente o de la infraestructura de contenedores para lanzar y ejecutar contenedores en cualquier lugar sin descargar imágenes mediante extracción. Además, el registro de contenedor, al recibir una solicitud de inserción para cargar una imagen actualizada en él, puede enviar automáticamente esta imagen a un almacenamiento de red compartido, donde estará disponible de forma instantánea para todos los nodos.

El tamaño de las imágenes del contenedor a veces puede alcanzar muchos gigabytes. La funcionalidad de almacenamientos adicionales le permite prescindir de la clonación de 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 de superposición que hará que el ensamblaje del contenedor sea aún más rápido.

Conclusión


Ejecutar un Buildah dentro de un contenedor en Kubernetes / CRI-O, Podman o incluso Docker es real, y es más simple y mucho más seguro que usar docker.socket. Hemos mejorado enormemente la flexibilidad de trabajar con imágenes, y ahora puede lanzarlas de varias maneras para lograr un equilibrio óptimo entre seguridad y rendimiento.

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

Source: https://habr.com/ru/post/470928/


All Articles