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.

Se hablará de — 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 ).
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:
- 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.
- Cuando hay cambios en los archivos del proyecto, el compilador debe crear rápidamente una nueva capa aplicando un parche a los archivos modificados.
- 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 , la configuración de nuestro compilador comenzó a describirse en un archivo YAML.

Configuración antigua para dapp en Ruby

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 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 .
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 . 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:

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 .
¿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?
- 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 ). - Para la etapa
dockerfilewerf 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 etapadockerfiley 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 ). - Los imágenes construidas se pueden publicar con el comando
werf publish(owerf 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é:
- Si
.gitpermanecerá en la imagen final, esto viola los principios de : dado que la imagen final debe estar relacionada con un solo commit, no debería haber posibilidad de hacergit checkoutun commit arbitrario. -
.gitaumenta 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.gitDesde la imagen final no se ejecutará: la imagen adquirirá una capa adicional, así funciona Docker. - 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]/yourprojectcon la compilación paralela habilitada. La reconstrucción adicional estará relacionada con el hecho de que el directorio.gitvarí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 ).
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 !
P.D. Lista de documentación sobre el tema
- ;
- ;
- ;
- ;
- ;
- ;
- .
Lee también en nuestro blog: "».
Fuente: habr.com
