Comment utiliser pleinement Docker pendant le développement

Photo par Johnson Wang sur Unsplash

TL: DR

Partie 1

  • Utilisez Docker pour gérer les documents et partager votre environnement de développement complet
  • Utilisez Docker pour exécuter vos tests de CI
  • Utilisez les couches Docker pour optimiser le processus de construction.
  • Utilisez les versions en plusieurs étapes de Docker pour créer un composant déployable en production à partir des sources.

Partie 2 (https://medium.com/tsftech/how-to-fully- utilise-docker-compose-during-development-4b723caed798)

  • Utilisez Docker-compose pour héberger / émuler votre système de production.
  • Utilisez un fichier Docker-compose distinct pour gérer votre développement / implémentation de CI.
  • Utilisez Docker-compose pour tester vos composants de production

Si vous ne connaissez pas Node…

Le blog traite de l'utilisation de Docker et de Docker-compose, toutes les fonctionnalités pouvant être appliquées de manière générique à de nombreuses technologies de développement. J'ai utilisé le même modèle avec des projets Javascript, python, java et scala.

Dans les exemples, j’utilise une application Node simple. Si vous n’êtes pas familier avec Node, c’est tout ce que vous devez savoir.

  • Node est un environnement d'exécution et vient avec un gestionnaire de paquets appelé npm.
  • Package.json définit les dépendances tierces et les scripts de génération
  • Les dépendances tierces sont téléchargées dans un sous-répertoire du projet appelé node_modules (contrairement à Maven qui utilise un répertoire configurable par défaut pour un répertoire utilisateur commun à de nombreux projets).
  • Ces commandes sont généralement utilisées dans le flux de travail de développement.
  • npm install - télécharge les dépendances tierces dans le répertoire node_modules
  • npm start - exécute le programme à partir du code source
  • npm test - exécute la suite de tests unitaires
  • npm build - optimise et emballe pour la production

Problèmes / Motivation

Historiquement, les développeurs ont dû télécharger et installer toute une suite de langages, compilateurs, bases de données et analyseurs sur leur ordinateur local. Ils ont également installé un ensemble d'outils similaires, mais souvent différents, sur un ou plusieurs serveurs d'EC. Au fil du temps, au fur et à mesure que l'équipe change et que le projet évolue, les serveurs de CI et chaque ordinateur de développeur, légèrement différents les uns des autres, sont légèrement différents. Ensuite, la construction se brise ou un bogue est soulevé au son de

Eh bien, cela a fonctionné sur ma machine

Si vous étiez une équipe assidue, vous disposiez d'une page wiki expliquant comment les nouveaux débutants pouvaient se lancer. Mais quand le débutant est arrivé, ils ont passé des jours (ou des semaines - je n’exagère pas) à se lever et à courir. Heureusement, nous avions un chef de projet qui connaissait une solution.

Mettez-le dans le wiki, alors le prochain newb ira bien

Ensuite, lorsque vous travaillez sur une nouvelle fonctionnalité, une personne change de dépendance. Leur construction fonctionne alors ils le poussent. Si vous configurez bien votre système CI, vous résolvez le problème, mais uniquement lorsque le développeur a marqué la tâche comme terminée et l'a laissée pour le week-end. Mais peut-être que la construction de CI passe. C’est ensuite le débutant qui ne possède pas une ancienne dépendance résidant dans un répertoire persistant et qui trouve que sa construction ne fonctionne pas, et il passe les premières heures à inspecter son propre code et sa propre configuration, ce qui est naturel étant donné que le code fonctionne pour le principal. développeur et le système CI.

À l’époque sombre, un bon développeur exécutait les tests unitaires localement avant de lancer. Ce n’était pas dommage que cela prenne 5 minutes, car ils pouvaient aller faire une infusion. Le système CI a été laissé pour exécuter la longue suite de tests. En cas de problème, le développeur ne pouvait pas toujours l'exécuter localement car la suite CI était configurée différemment de son environnement. Peut-être parce que c'était un gros projet et qu'en tant que développeur back-end, ils ne possèdent que la moitié de la pile de construction. Le seul moyen de résoudre le problème consistait à consulter les journaux de configuration, à appliquer une modification susceptible d'aider, à attendre et à répéter l'opération.

Dockerise votre environnement de développement

La première et la plus simple consiste à créer un fichier Docker pour votre environnement de développement. Dockerfile documente simplement les instructions d'installation avec des numéros de version et des étapes précises. La configuration du développeur est désormais aussi simple que l'installation du menu fixe, la construction du menu fixe my-dev-env et le menu fixe qui exécute my-dev-image. Le fichier Docker est ajouté au contrôle de source afin que l'environnement de développement reste toujours synchronisé avec le code qui l'exige.

Pour créer un environnement de développement javascript très simple, enregistrez les éléments suivants dans ./Dockerfile

Nœud FROM: 10.11.0-jessie
WORKDIR / home / app

Notez que vous devez toujours utiliser une version complète pour les images de base et les dépendances. Vous voulez que les changements soient une décision consciente.

Vous pouvez maintenant simplement monter votre code et l'exécuter, le tester et le conditionner, etc.

docker build -t my_dev_env.
docker run -v.: / home / app my_dev_env npm start

Ce n’est pas le meilleur exemple: nous n’avons enregistré qu’une installation locale de Node, mais nous avons au moins une version cohérente et documentée de l’ensemble de notre équipe de développement. Dans le monde réel, TOUS les projets sont plus complexes que cela et le coût est remboursé pour chaque dépendance supplémentaire.

Dockerise vos étapes de construction

L'exemple ci-dessus souffre encore de quelques problèmes:

  • Le remontage de l'espace de travail pollue la machine hôte et permet aux artefacts de génération de se vider d'une construction ou d'un projet à l'autre.
  • Le workflow de construction est toujours un processus externe documenté dans un wiki ou dans notre mémoire, mais maintenant, chaque commande est beaucoup plus cruelle, avec tout le menu fixe -cet -et -qui exécute my-step - its -args

Permet de faire quelques mises à jour du fichier Docker

Nœud FROM: 10.11.0-jessie
WORKDIR / home / app
# Créer une couche pour mettre en cache les dépendances changeant occasionnellement
COPY ./package.json ./package-lock.json ./
RUN npm installer
# Créer une couche avec un code source changeant fréquemment
COPY ./public ./public
COPY ./src ./src
# Exécuter des tests et un package pour la production
RUN npm lancer le test
RUN npm run build
# Set default command pour exécuter l'artefact de production
CMD [“noeud”, “build / www / index.js”]

La première étape consiste à copier dans le fichier package.json, qui définit les dépendances, et à les installer dans l'image du conteneur avec npm install. Remarquerez que:

  • Seul le fichier package.json est monté, pas les répertoires parent ou node_modules. Par conséquent, les dépendances sont enregistrées dans un répertoire node_modules qui n'existe que dans le conteneur. Ils ne polluent pas le répertoire source sur la machine hôte et ne peuvent pas se répandre dans des versions ultérieures ou d'autres projets.
  • Le téléchargement a lieu une fois pendant la phase de construction, de sorte que l'exécution du conteneur est rapide car les dépendances sont déjà présentes.

Une fois les dépendances tierces installées, copiez le code source et d’autres artefacts. Il est important de séparer ces étapes pour obtenir un temps de construction rapide. Docker hache l'entrée de chaque étape de la construction et réutilise un calque mis en cache si rien n'a changé ou reconstruit l'intégralité du calque en cas de changement. N'oubliez pas que les dépendances tierces sont téléchargées dans l'image du conteneur en une seule étape. Par conséquent, si une dépendance change, l'ensemble de la couche est invalidé et toutes les dépendances sont téléchargées à nouveau. La plupart des versions ne modifieront que le code source. Dans ce cas, Docker verra que le hachage du fichier package.json est inchangé et réutilisera la couche contenant les dépendances pré-téléchargées, accélérant ainsi considérablement la construction.

L'étape suivante consiste à exécuter les tests pendant la phase de construction. Cela a 2 avantages:

  • Il garantit que toute image de conteneur produite doit avoir passé les tests.
  • Il définit et documente les étapes d'exécution du test à un endroit unique, leur permettant d'être exécutées de manière fiable sur les systèmes de développement et les systèmes CI avec une simple commande.
docker construire -t mon-image.

Enfin, nous empaquetons pour la production et définissons le mode d’exécution du conteneur par défaut.
Nous pouvons maintenant exécuter facilement la version «production» avec

docker run my-image

Et même si nous continuons à pirater activement le code, nous exécutons la version de développement, qui surveille les modifications de code sur l'hôte rapidement et recompile / exécute / teste de manière dynamique, etc., comme défini dans le fichier projects package.json.

docker run -v ./src:/home/app/src --entrypoint = "npm run watch" my-image

Génial. Cela couvre à peu près tous les problèmes que nous avons abordés dans la section motivation. Mais le conteneur «production» contient également une charge de dépendances de développement qui ne sont pas requises dans une image de production. Cela frotte généralement les gens, en particulier les personnes soucieuses de la sécurité qui continuent de se sentir bien au chaud la nuit.

Constructions à plusieurs étages.

Les constructions à plusieurs étages sont une fonctionnalité de Docker qui nous permet parfaitement de construire un conteneur pour encapsuler la construction, puis de copier des artefacts dans un nouveau conteneur optimisé pour la production.

Marquez la première ligne FROM avec AS dev et ajoutez une nouvelle section avec une seconde FROM

Nœud FROM: 10.11.0-jessie AS dev
WORKDIR / home / app
# Créer une couche pour mettre en cache les dépendances changeant occasionnellement
COPY ./package.json ./package-lock.json ./
RUN npm installer
# Créer une couche avec un code source changeant fréquemment
COPY ./public ./public
COPY ./src ./src
# Exécuter des tests et un package pour la production
RUN npm lancer le test
RUN npm run build
# commande par défaut pour le conteneur dev
CMD [“npm”, “run”, “regarder”]
# Créer une image de conteneur optimisée pour la production
Nœud FROM: 10.11.0-jessie
RUN npm install -g serve
COPY - de = dev / home / app / build build
CMD [“servir”, “-s”, “construire”]

Je ne prétends pas que ce soit un bon exemple d’environnement de production, mais cela sert de but illustratif. Nous pourrions choisir n'importe quelle image de base pour la phase suivante. Un bon choix aurait pu être nginx. Notez que la commande COPY utilise l'indicateur --from = dev pour lui demander de copier à partir de la première étape nommée à la place de l'hôte.

Modifiez également la commande pour le conteneur dev afin qu'il passe par défaut au mode surveillance. Cela simplifie les commandes d'exécution les plus courantes.

Nous avons écrit un fichier Dockerfile définissant et documentant:

  • un environnement de développement complet et des étapes pour construire avec une seule commande
docker construire -t mon-image.
  • qui peut être exécuté en mode production avec une commande
docker run my-image
  • qui peut être construit et exécuté en mode de développement avec deux commandes
docker build - target = dev -t mon-dev-image.
docker run -v ./src:/home/app/src mon-dev-image
  • Qui peut être exécuté de manière fiable par tout nouveau membre d’équipe ou système CI en quelques minutes.
  • Ce qui maintient tous les artefacts isolés dans la protection des futures constructions et autres projets.
  • Ce qui garantit que les tests ont été effectués sur toutes les images de production

Partie 2

Jusqu'ici, nous avons seulement regardé Docker et utilisé un exemple très simple de processus de construction node.js.

Dans la partie 2 (à venir), je décrirai comment vous pouvez utiliser docker-compose pour étendre ce double exemple à des projets complexes à plusieurs composants.

:X

Publié à l'origine à thestartupfactory.tech.