Il est désormais possible de créer des images Docker dans werf en utilisant un Dockerfile classique.

Mieux vaut tard que jamais. Ou comment nous avons failli commettre une grave erreur en n'ayant pas de support pour les Dockerfiles classiques pour la construction des images d'application.

Il est désormais possible de créer des images Docker dans werf en utilisant un Dockerfile classique.

Nous allons parler de werf — un outil GitOps qui s'intègre à n'importe quel système CI/CD et qui assure la gestion de tout le cycle de vie de l'application, permettant :

  • de construire et publier des images,
  • de déployer des applications sur Kubernetes,
  • de supprimer des images inutilisées grâce à des politiques spéciales.


La philosophie du projet est de regrouper des outils de bas niveau dans un système unifié, permettant aux ingénieurs DevOps de contrôler les applications. Si possible, les utilitaires existants (comme Helm et Docker) doivent être utilisés. Si une solution à un problème donné n'existe pas, nous pouvons créer et maintenir tout ce qui est nécessaire.

Contexte : notre propre constructeur d'images

C'est ainsi qu'il en a été avec le constructeur d'images dans werf : nous avions besoin d'un Dockerfile habituel. En regardant rapidement l'historique du projet, ce problème est apparu dès les premières versions de werf (alors encore connu sous le nom de dapp).

En créant un outil pour construire des applications en images Docker, nous avons rapidement réalisé que le Dockerfile ne convenait pas à certaines tâches particulières :

  1. La nécessité de construire des applications web typiques selon le schéma standard suivant :
    • installer les dépendances système de l'application,
    • installer le bundle des bibliothèques de dépendances de l'application,
    • compiler les assets,
    • et surtout — mettre à jour le code dans l'image rapidement et efficacement.
  2. Lors des modifications des fichiers du projet, le constructeur doit rapidement créer une nouvelle couche en appliquant un patch sur les fichiers modifiés.
  3. Si certains fichiers changent, il est nécessaire de reconstruire la phase dépendante correspondante.

À ce jour, notre constructeur offre de nombreuses autres fonctionnalités, mais les désirs et les urgences initiaux étaient les suivants.

En bref, sans trop réfléchir, nous avons utilisé le langage de programmation (voir ci-dessous) et nous avons commencé — à réaliser notre propre DSL! Conformément aux objectifs fixés, il était destiné à décrire le processus de construction par étapes et à définir les dépendances de ces étapes par rapport aux fichiers. Et il était complété par notre propre constructeur, qui transformait le DSL en objectif final — l'image assemblée. Au départ, le DSL était en Ruby, mais progressivement avec la transition vers Golang — la configuration de notre constructeur a commencé à être décrite dans un fichier YAML.

Il est désormais possible de créer des images Docker dans werf en utilisant un Dockerfile classique.
Ancienne configuration pour dapp sur Ruby

Il est désormais possible de créer des images Docker dans werf en utilisant un Dockerfile classique.
Configuration actuelle pour werf en YAML

Le mécanisme de fonctionnement du constructeur a également évolué avec le temps. Au début, nous générions simplement à la volée un Dockerfile temporaire à partir de notre configuration, puis nous avons commencé à exécuter des instructions de construction dans des conteneurs temporaires et à faire des commits.

NB: À l'heure actuelle, notre constructeur, qui fonctionne avec sa propre configuration (en YAML) et s'appelle le constructeur Stapel, a déjà évolué en un outil assez puissant. Sa description détaillée mérite des articles à part entière, et les principaux détails peuvent être trouvés dans documentation.

La prise de conscience du problème

Mais nous avons réalisé, et ce n'était pas tout de suite, que nous avions commis une erreur : nous n'avons pas ajouté la possibilité de construire des images via un Dockerfile standard et de les intégrer dans la même infrastructure de gestion d'applications globales (c'est-à-dire construire, déployer et nettoyer les images). Comment pouvait-on créer un outil de déploiement pour Kubernetes sans mettre en œuvre le support du Dockerfile, c'est-à-dire le moyen standard de décrire des images pour la plupart des projets ?..

Au lieu de répondre à une telle question, nous proposons sa solution. Que faire si vous avez déjà un Dockerfile (ou un ensemble de Dockerfiles) et que vous souhaitez utiliser werf ?

NB: À propos, pourquoi voudriez-vous utiliser werf ? Les principales fonctionnalités se résument comme suit :

  • cycle complet de gestion d'application, y compris le nettoyage des images ;
  • capacité à gérer la construction de plusieurs images à partir d'une seule configuration ;
  • amélioration du processus de déploiement des charts compatibles avec Helm.

Une liste plus complète est disponible sur page du projet.

Ainsi, si auparavant nous aurions proposé de réécrire le Dockerfile dans notre configuration, nous dirons maintenant avec plaisir : « Laissez werf construire vos Dockerfiles ! »

Comment utiliser?

La mise en œuvre complète de cette fonctionnalité est apparue dans la version werf v1.0.3-beta.1. Le principe général est simple : l'utilisateur spécifie le chemin vers le Dockerfile existant dans la configuration de werf, puis exécute la commande werf build… et voilà — werf construira l'image. Examinons un exemple abstrait.

Déclarons le suivant Dockerfile à la racine du projet :

FROM ubuntu:18.04
RUN echo Building ...

Et déclarons werf.yaml, qui utilise cette Dockerfile:

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

C'est tout ! Il ne reste plus qu'à démarrer werf build:

Il est désormais possible de créer des images Docker dans werf en utilisant un Dockerfile classique.

De plus, il est possible de déclarer le suivant werf.yaml pour construire plusieurs images à partir de différents Dockerfiles :

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

Enfin, la transmission de paramètres de construction supplémentaires est également prise en charge, tels que --build-arg et --add-host — via la configuration werf. Une description complète de la configuration de l'image Dockerfile est disponible sur la page de documentation.

Comment cela fonctionne ?

Pendant le processus de construction, le cache standard des couches locales de Docker fonctionne. Cependant, il est important de noter que werf intègre également la configuration du Dockerfile dans son infrastructure. Que signifie cela ?

  1. Chaque image créée à partir d'un Dockerfile se compose d'un stage appelé dockerfile (pour en savoir plus sur ce que sont les stages dans werf, vous pouvez lire ici).
  2. Pour le stage dockerfile werf calcule une signature qui dépend du contenu de la configuration du Dockerfile. Lorsque la configuration du Dockerfile est modifiée, la signature du stage change dockerfile et werf déclenche une reconstruction de ce stage avec la nouvelle configuration du Dockerfile. En revanche, si la signature ne change pas, werf prend l'image du cache (pour en savoir plus sur l'utilisation des signatures dans werf, cela a été discuté dans cet exposé).
  3. Ensuite, les images compilées peuvent être publiées avec la commande werf publish ou werf build-and-publish) et utilisées pour le déploiement dans Kubernetes. Les images publiées dans le Docker Registry seront nettoyées par les outils de nettoyage standard de werf, c'est-à-dire qu'un nettoyage automatique des anciennes images (plus de N jours), des images associées à des branches Git inexistantes et selon d'autres politiques aura lieu.

Pour en savoir plus sur les points décrits ici, vous pouvez consulter la documentation :

Remarques et précautions

1. L'URL externe dans ADD n'est pas prise en charge

Actuellement, l'utilisation d'une URL externe dans l'instruction ADD. Werf ne déclenchera pas de reconstruction lorsque la ressource liée à l'URL change. La possibilité d'ajouter cette fonctionnalité est prévue prochainement.

2. Ne pas ajouter .git à l'image

En général, l'ajout du répertoire .git à l'image est une mauvaise pratique, et voici pourquoi :

  1. Si .git reste dans l'image finale, ce qui enfreint les principes 12 factor appcar l'image finale doit être liée à un seul commit, il ne doit donc pas être possible de faire git checkout un commit aléatoire.
  2. .git augmente la taille de l'image (le référentiel peut être grand en raison de l'ajout antérieur de fichiers volumineux qui ont ensuite été supprimés). En revanche, la taille de l'arbre de travail, lié à un commit spécifique, ne dépendra pas de l'historique des opérations dans Git. Pendant ce temps, l'ajout et la suppression ultérieure .git Il ne fonctionnera pas à partir de l'image finale : l'image acquièrera tout de même une couche supplémentaire — c'est ainsi que fonctionne Docker.
  3. Docker peut initier une reconstruction supplémentaire, même s'il s'agit de construire le même commit, mais à partir de différents work-tree. Par exemple, GitLab crée des répertoires clonés séparés dans /home/gitlab-runner/builds/HASH/[0-N]/yourproject une compilation parallèle activée. La reconstruction supplémentaire sera liée au fait que le répertoire .git diffère dans les différentes versions clonées du même répertoire, même si le même commit est construit.

Le dernier point a des conséquences également lors de l'utilisation de werf. Werf exige que le cache construit soit présent lors de l'exécution de certaines commandes (par exemple, werf deploy). Pendant l'exécution de ces commandes, werf calcule les signatures des étapes pour les images spécifiées dans werf.yaml, et elles doivent être présentes dans le cache de construction — sinon, la commande ne pourra pas continuer. Si la signature de l'étape dépend du contenu .git, alors nous obtenons un cache instable face aux modifications dans des fichiers non pertinents, et werf ne pourra pas pardonner une telle négligence (voir plus de détails dans documentation).

Dans l'ensemble l'ajout uniquement de fichiers nécessaires via l'instruction ADD améliore néanmoins l'efficacité et la fiabilité de ce qui est écrit Dockerfile, ainsi que la robustesse du cache construit selon ce Dockerfile, face aux modifications non pertinentes dans Git.

Conclusion

Notre parcours initial avec l'écriture de notre propre assembleur pour des besoins spécifiques a été difficile, honnête et direct : au lieu d'utiliser des solutions de contournement au-dessus du Dockerfile standard, nous avons écrit notre propre solution avec une syntaxe personnalisée. Et cela a eu ses avantages : l'assembleur Stapel s'acquitte parfaitement de sa tâche.

Cependant, lors de l'écriture de notre propre assembleur, nous avons omis de prendre en charge les Dockerfile existants. Ce manque est maintenant corrigé, et nous prévoyons d'étendre le support des Dockerfile parallèlement à notre assembleur personnalisé Stapel pour la construction distribuée et pour la construction utilisant Kubernetes (c'est-à-dire des constructions sur des runners à l'intérieur de Kubernetes, comme cela est fait dans kaniko).

Alors, si vous avez quelques Dockerfile qui traînent... essayez werf!

P.S. Liste de la documentation sur le sujet

Lisez également dans notre blog : «werf est notre outil pour CI/CD dans Kubernetes (aperçu et vidéo de la présentation).».

Source : habr.com

Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS 🔥 Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster