Comment configurer un environnement de test d'intégration continue ?
avec Docker
420-5A4-MT · Module 3 · Techniques DockerIntroduction
Intégration continue (CI) fait référence à la pratique selon laquelle les développeurs intègrent du code aussi souvent que possible et chaque validation est testée avant et après sa fusion dans un référentiel partagé par un build automatisé.
CI accélère votre processus de développement et minimise le risque de problèmes critiques en production, mais sa configuration n'est pas une mince affaire; les versions automatisées fonctionnent dans un environnement différent où l'installation de dépendances d'exécution et la configuration de services externes peuvent être différentes de celles des environnements local et de développement.
Docker est une plate-forme de conteneurisation qui vise à simplifier les problèmes de normalisation de l'environnement afin que le déploiement d'applications puisse également être normalisé. Pour les développeurs, Docker vous permet de simuler des environnements de production sur des machines locales en exécutant des composants d'application dans des conteneurs locaux. Ces conteneurs sont facilement automatisables à l'aide de Docker Compose, indépendamment de l'application et du système d'exploitation sous-jacent.
Ce didacticiel utilise Docker Compose pour illustrer l'automatisation des flux de travail CI.
Nous allons créer une application Python de type «Hello world» dockerisée et un script de test Bash. L'application Python nécessite l'exécution de deux conteneurs: un pour l'application elle-même et un conteneur Redis pour le stockage requis en tant que dépendance de l'application.
Ensuite, le script de test sera dockérisé dans son propre conteneur et l'ensemble de l'environnement de test sera déplacé vers un fichier docker-compose.test.yml afin que nous puissions nous assurer que nous exécutons chaque exécution de test dans un environnement d'application nouveau et uniforme.
Cette approche montre comment vous pouvez créer un nouvel environnement de test identique pour votre application, y compris ses dépendances, chaque fois que vous le testez.
Ainsi, nous automatisons les flux de travaux CI indépendamment de l'application testée et de l'infrastructure sous-jacente.
Installation
Installer Docker et Docker Compose
Créez l'application Python «Hello World»
Dans cette étape, nous allons créer une application Python simple en tant qu'exemple du type d'application que vous pouvez tester avec cette configuration.
Créez un nouveau dossier pour notre application en exécutant:
Editez un nouveau fichier app.py avec nano:
Ajoutez le contenu suivant:
app.py
app.py est une application Web basée sur Flask qui se connecte à un service de données Redis.
La ligne visits = redis.incr('counter') augmente le nombre de visites et conserve cette valeur dans Redis. Enfin, un message «Hello World» avec le nombre de visites est renvoyé en HTML.
Notre application a deux dépendances, Flask et Redis, que vous pouvez voir dans les deux premières lignes. Ces dépendances doivent être définies avant que nous puissions exécuter l'application.
Editer un nouveau fichier:
Ajouter le contenu:
requirements.txt
Dockérisez l'application «Hello World»
Docker utilise un fichier nommé Dockerfile pour indiquer les étapes requises pour créer une image Docker pour une application donnée.
Editer un nouveau fichier:
Ajoutez le contenu suivant:
Dockerfile
Analysons le sens de chaque ligne:
FROM python:3.12 : indique que notre image d'application «Hello World» est construite à partir de l'image python:3.12 officielle de Docker.
WORKDIR /app : définit le répertoire de travail à l'intérieur de l'image Docker sur /app
COPY requirements.txt /app/requirements.txt : copie le fichier requirements.txt dans votre image Docker
RUN pip install -r requirements.txt : installe les dépendances de l'application avec pip
COPY app.py /app/app.py : copie le code source de notre application dans l'image Docker
EXPOSE 80 : indique que notre application est accessible via le port 80 (le port Web public standard)
CMD ["python", "app.py"] : la commande qui lance notre application
Ce fichier Dockerfile contient toutes les informations nécessaires à la création du composant principal de notre application «Hello World».
La dépendance
Nous arrivons maintenant à la partie plus sophistiquée de l'exemple. Notre application nécessite Redis en tant que service externe. C'est le type de dépendance qui pourrait être difficile à configurer de manière identique à chaque fois dans un environnement Linux traditionnel, mais avec Docker Compose, nous pouvons le configurer de manière répétable à tout moment.
Créons un fichier docker-compose.yml pour commencer à utiliser Docker Compose.
Editer un nouveau fichier:
Ajoutez le contenu suivant:
docker-compose.yml
Ce fichier Docker Compose indique comment lancer l'application «Hello World» localement dans deux conteneurs Docker.
Il définit deux conteneurs, web et redis.
web utilise le dossier actuel pour le contexte build et construit votre application Python à partir du fichier Dockerfile que nous venons de créer. Ceci est une image Docker locale que nous avons créée uniquement pour notre application Python. Les deux services partagent le réseau créé automatiquement par Docker Compose : le conteneur web peut joindre redis simplement par son nom de service, et depends_on garantit que la base démarre avant l'application. Il rend également le port 80 accessible au public sur Internet à l'aide du réseau IP public de votre serveur Ubuntu.
redis est exécuté à partir d'une image publique standard de Docker, nommée redis
Déployer l'application «Hello World»
Au cours de cette étape, nous déploierons l'application qui, à la fin, sera accessible sur Internet. Pour les besoins de votre flux de travail de déploiement, vous pouvez considérer qu'il s'agit d'un environnement de développement, de transfert ou de production, car vous pouvez déployer l'application de la même manière à plusieurs reprises.
Les fichiers docker-compose.yml et Dockerfile vous permettent d'automatiser le déploiement d'environnements locaux en exécutant:
La première ligne construit notre image d'application locale à partir du fichier Dockerfile. La deuxième ligne exécute les conteneurs web et redis en mode démon (-d), comme indiqué dans le fichier docker-compose.yml.
Vérifiez que les conteneurs d'applications ont été créés en exécutant: docker ps
Cela devrait afficher deux conteneurs en cours d'exécution, nommés hello_world-web-1 et hello_world-redis-1.
Voyons si l'application est active. Le port 80 du conteneur web est publié sur la machine hôte : l'application répond donc directement à l'adresse locale du serveur.
Vérifiez que l'application Web renvoie le message approprié:
Cela devrait retourner quelque chose comme:
Le nombre de visites est incrémenté chaque fois que vous atteignez ce noeud final. Vous pouvez également accéder à l'application «Hello World» à partir de votre navigateur en visitant l'adresse IP publique de votre serveur Ubuntu.
Comment personnaliser pour votre propre application
La clé pour configurer votre propre application consiste à placer votre application dans son propre conteneur Docker et à exécuter chaque dépendance à partir de son propre conteneur. Ensuite, vous pouvez définir les relations entre les conteneurs avec Docker Compose, comme illustré dans l'exemple. Docker Compose est traité plus en détail dans cet article Docker Compose.
Créer le script de test
Nous allons maintenant créer un script de test pour votre application Python. Ce sera un script simple qui vérifie la sortie HTTP de l'application. Le script est un exemple du type de test que vous souhaitez peut-être exécuter dans le cadre de votre processus de déploiement d'intégration continue.
Editer un nouveau fichier:
Ajoutez le contenu suivant:
test.sh
Créer le script de test
test.sh teste la connectivité Web de base de notre application «Hello World». Il utilise cURL pour récupérer le nombre de visites et indique si le test a été réussi ou non.
Créer l'environnement de test
Afin de tester notre application, nous devons déployer un environnement de test. De plus, nous voulons nous assurer qu'il est identique à l'environnement d'applications dynamiques créé à l'étape Déployer l'application «Hello World».
Premièrement, nous devons dockériser notre script de test en créant un nouveau fichier Dockerfile. Editer un nouveau fichier:
Ajoutez le contenu suivant:
Dockerfile.test
Créer l'environnement de test
Dockerfile.test étend l'image officielle ubuntu:24.04 pour installer la dépendance curl, copie test.sh dans le système de fichiers de l'image et indique la commande CMD qui exécute le script de test avec Bash. Une fois que nos tests sont dockérisés, ils peuvent être exécutés de manière réplicable et agnostique.
La prochaine étape consiste à relier notre conteneur de tests à notre application «Hello World». C'est ici que Docker Compose vient à la rescousse. Editer un nouveau fichier:
Ajoutez le contenu suivant:
docker-compose.test.yml
La seconde moitié du fichier Docker Compose déploie l'application principale web et sa dépendance redis de la même manière que le fichier docker-compose.yml précédent. C'est la partie du fichier qui spécifie les conteneurs web et redis. La seule différence est que le conteneur web n'expose plus le port 80 et que l'application ne sera donc pas disponible sur Internet lors des tests. Ainsi, vous pouvez voir que nous construisons l'application et ses dépendances exactement de la même manière qu'elles le sont dans le déploiement en direct.
Le fichier docker-compose.test.yml définit également un conteneur sut (nommé pour le système sous tests) chargé de l'exécution de nos tests d'intégration. Le conteneur sut spécifie le répertoire en cours en tant que notre répertoire build et spécifie notre fichier Dockerfile.test. Sur le réseau partagé du projet, le nom de service web se résout automatiquement : notre script test.sh peut donc appeler curl web directement, et depends_on assure l'ordre de démarrage.
Comment personnaliser pour votre propre application
Notez que docker-compose.test.yml peut inclure des dizaines de services externes et plusieurs conteneurs de test. Docker pourra exécuter toutes ces dépendances sur un seul hôte car chaque conteneur partage le système d'exploitation sous-jacent.
Si vous avez d'autres tests à exécuter sur votre application, vous pouvez créer pour eux des fichiers Dockerfiles similaires au fichier Dockerfile.test présenté ci-dessus.
Ensuite, vous pouvez ajouter des conteneurs supplémentaires sous le conteneur sut dans le fichier docker-compose.test.yml, en référençant les fichiers Docker supplémentaires.
Testez l'application «Hello World»
Enfin, pour étendre les idées Docker des environnements locaux aux environnements de test, nous disposons d'un moyen automatisé de tester notre application à l'aide de Docker en exécutant:
Cette commande construit les images locales nécessaires à docker-compose.test.yml. Notez que nous utilisons -f pour pointer sur docker-compose.test.yml et -p pour indiquer un nom de projet spécifique.
Maintenant, lancez votre nouvel environnement de test en exécutant:
Après l'exécution de cette commande, la valeur de $? sera 0 si les tests réussissent. Sinon, nos tests d'application ont échoué.
Notez que d'autres outils de CI peuvent cloner notre référentiel de code et exécuter ces quelques commandes pour vérifier si les tests réussissent avec les derniers bits de votre application sans se soucier des dépendances d'exécution ou des configurations de services externes.
C'est ça! Nous avons réussi à exécuter nos tests dans un environnement nouvellement construit identique à notre environnement de production.
Conclusion
Grâce à Docker et Docker Compose, nous avons pu automatiser la création d'une application (Dockerfile), le déploiement d'un environnement local (docker-compose.yml), la création d'une image de test (Dockerfile.test), et comment exécuter des tests (d'intégration) (docker-compose.test.yml) pour toute application.
En particulier, l'utilisation du fichier docker-compose.test.yml à des fins de test a pour avantage que le processus de test est le suivant:
Automatable : la manière dont un outil exécute le docker-compose.test.yml est indépendante de l'application testée
Léger : des centaines de services externes peuvent être déployés sur un seul hôte simulant des environnements de test complexes (intégration)
Agnostique : évitez le blocage du fournisseur de CI, et vos tests peuvent s'exécuter dans n'importe quelle infrastructure et sur tout système d'exploitation qui prend en charge Docker
Immutable : les tests passés sur votre machine locale passeront dans votre outil de CI
Ce tutoriel montre un exemple de test d'une application simple «Hello World».
Il est maintenant temps d'utiliser vos propres fichiers d'application, de dockériser vos propres scripts de test d'application et de créer votre propre docker-compose.test.yml pour tester votre application dans un environnement nouveau et immuable.