Ahora se pueden construir imágenes de Docker en werf utilizando un Dockerfile estándar

Mejor tarde que nunca. O cómo casi cometimos un grave error al no tener soporte para Dockerfiles convencionales para construir imágenes de aplicación.

Ahora se pueden construir imágenes de Docker en werf utilizando un Dockerfile estándar

Se hablará de werf — una herramienta GitOps que se integra con cualquier sistema CI/CD y proporciona gestión de todo el ciclo de vida de la aplicación, permitiendo:

  • compilar y publicar imágenes,
  • desplegar aplicaciones en Kubernetes,
  • eliminar imágenes no utilizadas mediante políticas especiales.


La filosofía del proyecto es combinar herramientas de bajo nivel en un único sistema unificado que brinde a los ingenieros de DevOps control sobre las aplicaciones. Siempre que sea posible, se deben utilizar herramientas existentes (como Helm y Docker). Si no hay una solución para un problema específico, podemos crear y mantener todo lo necesario para ello.

Contexto: nuestro compilador de imágenes

Así sucedió con el compilador de imágenes en werf: nos faltaba el habitual Dockerfile. Si echamos un vistazo a la historia del proyecto, este problema se manifestó ya en las primeras versiones de werf (entonces aún conocido como dapp).

Al crear una herramienta para construir aplicaciones en imágenes Docker, rápidamente nos dimos cuenta de que Dockerfile no era adecuado para algunas tareas específicas:

  1. La necesidad de compilar pequeñas aplicaciones web típicas siguiendo el siguiente esquema estándar:
    • instalar dependencias del sistema para la aplicación,
    • instalar la biblioteca de dependencias de la aplicación,
    • compilar los assets,
    • y lo más importante: actualizar el código en la imagen de manera rápida y eficiente.
  2. Cuando hay cambios en los archivos del proyecto, el compilador debe crear rápidamente una nueva capa aplicando un parche a los archivos modificados.
  3. Si ciertos archivos han cambiado, es necesario recompilar la etapa dependiente correspondiente.

Hoy en día, nuestro compilador tiene muchas más capacidades, pero los deseos y objetivos iniciales eran así.

En general, sin pensarlo mucho, utilizamos el lenguaje de programación (ver más abajo) y nos pusimos en marcha para implementar nuestro propio DSL! Cumpliendo con los objetivos planteados, estaba destinado a describir el proceso de compilación por etapas y definir las dependencias de esas etapas respecto a los archivos. Y se complementó con nuestro propio compilador, que convertía el DSL en el objetivo final: la imagen compilada. Inicialmente, el DSL estaba en Ruby, y a medida que nos movimos a Golang , la configuración de nuestro compilador comenzó a describirse en un archivo YAML.

Ahora se pueden construir imágenes de Docker en werf utilizando un Dockerfile estándar
Configuración antigua para dapp en Ruby

Ahora se pueden construir imágenes de Docker en werf utilizando un Dockerfile estándar
Configuración actual para werf en YAML

El mecanismo de trabajo del compilador también ha cambiado con el tiempo. Al principio, simplemente generábamos sobre la marcha un Dockerfile temporal a partir de nuestra configuración, y luego comenzamos a ejecutar instrucciones de compilación en contenedores temporales y hacer commit.

NBEn la actualidad, nuestro compilador, que trabaja con su propia configuración (en YAML) y se llama compilador Stapel, ya se ha convertido en una herramienta bastante potente. Su descripción detallada merece artículos por separado, y se pueden conocer los principales detalles en la documentación.

La comprensión del problema

Pero entendimos, aunque no de inmediato, que cometimos un error: no añadimos la posibilidad de compilar imágenes a través de un Dockerfile estándar e integrarlas en la misma infraestructura de gestión integral de aplicaciones (es decir, compilar imágenes, desplegarlas y limpiarlas). ¿Cómo se pudo crear una herramienta para desplegar en Kubernetes y no implementar soporte para Dockerfile, es decir, la forma estándar de describir imágenes para la mayoría de los proyectos?..

En lugar de responder a tal pregunta, proponemos su solución. ¿Qué hacer si ya tienes un Dockerfile (o un conjunto de Dockerfiles) y quieres usar werf?

NB: Por cierto, ¿por qué querrías usar werf? Las características principales son las siguientes:

  • ciclo completo de gestión de aplicaciones incluyendo limpieza de imágenes;
  • la posibilidad de gestionar la compilación de varias imágenes desde una única configuración;
  • proceso mejorado de despliegue de charts compatibles con Helm.

Puedes consultar una lista más completa en la página del proyecto.

Así que, si antes sugeriríamos reescribir el Dockerfile en nuestra configuración, ahora con gusto diremos: «¡Permite que werf compile tus Dockerfiles!»

¿Cómo usarlo?

La implementación completa de esta posibilidad apareció en la versión werf v1.0.3-beta.1. El principio general es simple: el usuario indica la ruta hasta el Dockerfile existente en la configuración de werf, tras lo cual ejecuta el comando werf build… y eso es todo: werf compilará la imagen. Veamos un ejemplo abstracto.

Declararemos lo siguiente Dockerfile en la raíz del proyecto:

FROM ubuntu:18.04
RUN echo Building ...

Y declararemos werf.yaml, que utiliza este Dockerfile:

configVersion: 1
project: dockerfile-example
---
image: ~
dockerfile: .\/Dockerfile

¡Eso es todo! Solo queda iniciar werf build:

Ahora se pueden construir imágenes de Docker en werf utilizando un Dockerfile estándar

Además, se puede declarar lo siguiente werf.yaml para compilar varias imágenes desde diferentes Dockerfiles:

configVersion: 1
project: dockerfile-example
---
image: backend
dockerfile: .\/dockerfiles\/Dockerfile-backend
---
image: frontend
dockerfile: .\/dockerfiles\/Dockerfile-frontend

Finalmente, se admite la transmisión de parámetros adicionales de construcción, como --build-arg y --add-host a través de la configuración de werf. La descripción completa de la configuración de la imagen Dockerfile está disponible en la página de documentación.

¿Cómo funciona?

Durante el proceso de construcción, funciona la caché estándar de capas locales en Docker. Sin embargo, lo importante es que werf también integra la configuración del Dockerfile en su infraestructura. ¿Qué significa esto?

  1. Cada imagen construida a partir de un Dockerfile consta de una etapa llamada dockerfile (puedes leer más sobre qué son las etapas en werf en aquí).
  2. Para la etapa dockerfile werf calcula una firma que depende del contenido de la configuración del Dockerfile. Al cambiar la configuración del Dockerfile, se produce un cambio en la firma de la etapa dockerfile y werf inicia la reconstrucción de esta etapa con la nueva configuración del Dockerfile. Si la firma no cambia, werf toma la imagen de la caché (se habló más sobre el uso de firmas en werf en esta presentación).
  3. Los imágenes construidas se pueden publicar con el comando werf publish (o werf build-and-publish) y utilizar para el despliegue en Kubernetes. Las imágenes publicadas en Docker Registry serán limpiadas por los medios estándar de limpieza de werf, es decir, se realizará una limpieza automática de imágenes antiguas (mayores de N días), imágenes asociadas con ramas de Git inexistentes, y según otras políticas.

Puedes aprender más sobre los aspectos descritos aquí en la documentación:

Notas y precauciones

1. No se admite URL externo en ADD

Actualmente no se admite el uso de URL externo en la directiva ADD. Werf no iniciará la reconstrucción al cambiar el recurso en la URL especificada. Se planea agregar esta funcionalidad pronto.

2. No se puede agregar .git a la imagen

En general, agregar el directorio .git a la imagen es una mala práctica y aquí está el porqué:

  1. Si .git permanecerá en la imagen final, esto viola los principios de 12 factor app: dado que la imagen final debe estar relacionada con un solo commit, no debería haber posibilidad de hacer git checkout un commit arbitrario.
  2. .git aumenta el tamaño de la imagen (el repositorio puede ser grande porque en algún momento se agregaron archivos grandes y luego se eliminaron). El tamaño del work-tree, relacionado solo con un commit específico, no dependerá del historial de operaciones en Git. Al mismo tiempo, la adición y posterior eliminación .git Desde la imagen final no se ejecutará: la imagen adquirirá una capa adicional, así funciona Docker.
  3. Docker puede iniciar una reconstrucción innecesaria, incluso si se está construyendo el mismo commit, pero desde diferentes work-trees. Por ejemplo, GitLab crea directorios clonados separados en /home/gitlab-runner/builds/HASH/[0-N]/yourproject con la compilación paralela habilitada. La reconstrucción adicional estará relacionada con el hecho de que el directorio .git varía en diferentes versiones clonadas del mismo repositorio, incluso si se está construyendo el mismo commit.

El último punto tiene consecuencias también al usar werf. Werf requiere que la caché construida esté presente al ejecutar algunos comandos (por ejemplo, werf deploy). Durante la ejecución de esos comandos, werf calcula las firmas de las etapas para las imágenes especificadas en werf.yaml, y deben estar en la caché de construcción; de lo contrario, el comando no podrá continuar. Si la firma de las etapas depende del contenido .git, entonces obtenemos una caché que no es estable ante cambios en archivos no relevantes, y werf no podrá perdonar tal descuido (para más detalles, ver la documentación).

En general agregar solo los archivos necesarios a través de la instrucción ADD en cualquier caso, mejora la eficacia y la fiabilidad de lo escrito Dockerfile, así como aumenta la resistencia de la caché construida de acuerdo con esto Dockerfile, a cambios no relevantes en Git.

Summary

Nuestro camino inicial al escribir nuestro propio compilador para necesidades específicas fue difícil, honesto y directo: en lugar de usar parches sobre un Dockerfile estándar, escribimos nuestra propia solución con una sintaxis personalizada. Y esto tuvo sus beneficios: el compilador Stapel hace muy bien su trabajo.

Sin embargo, en el proceso de escribir nuestro propio compilador, perdimos de vista el soporte para Dockerfiles ya existentes. Ahora se ha corregido este defecto y en el futuro planeamos desarrollar el soporte para Dockerfiles junto con nuestro compilador personalizado Stapel para compilaciones distribuidas y para compilaciones utilizando Kubernetes (es decir, compilaciones en runners dentro de Kubernetes, como se hace en kaniko).

Así que, si de repente tienes un par de Dockerfiles guardados... prueba werf!

P.D. Lista de documentación sobre el tema

Lee también en nuestro blog: "werf: nuestra herramienta para CI/CD en Kubernetes (reseña y video de la presentación)».

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster