Comment configurer un environnement de test d’intégration continue avec Docker et Docker Compose sur Ubuntu 14.04

Un article de Docker

introduction

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é (https://www.digitalocean.com/community/tutorials). / the-docker -osystem-an-overview-of-containerization [en savoir plus sur Docker]). 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.

Exigences

Avant de commencer, vous aurez besoin de:

Étape 1 - Installez Docker

Si Docker n’est pas encore disponible sur votre serveur, le moyen le plus simple est de télécharger et d’exécuter le script d’installation officiel de Docker, qui demande un mot de passe sudo (pour plus d’informations sur l’installation de Docker, consultez https://www.digitalocean.com/community/tutorials). / comment-installer-et-utiliser-docker-getting-started [ici]):

wget -qO- https://get.docker.com/ | sh

Pour faciliter votre travail avec Docker, ajoutez votre utilisateur au groupe * docker * à l’aide de la commande suivante:

sudo usermod -aG docker $(whoami)

Déconnectez-vous puis connectez-vous à votre serveur pour activer le groupe * docker * pour votre utilisateur.

Étape 2 - Installer Docker Compose

Docker Compose est un outil à code source ouvert permettant de définir et d’exécuter des applications multi-conteneurs à l’aide d’une approche déclarative. Pour installer Docker Compose, exécutez les commandes suivantes:

sudo apt-get update
sudo apt-get -y install python-pip
sudo pip install docker-compose

Vérifiez que + docker-compose + est correctement installé en exécutant:

docker-compose --version

Vous devriez voir quelque chose comme:

Sortie

docker-compose version 1.6.2, build 4d72027

Cela devrait vous indiquer la version + docker-compose + que vous avez installée.

Étape 3 - 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:

cd ~
mkdir hello_world
cd hello_world

Editez un nouveau fichier + app.py + avec nano:

nano app.py

Ajoutez le contenu suivant:

app.py

from flask import Flask
from redis import Redis

app = Flask(__name__)
redis = Redis(host="redis")

@app.route("/")
def hello():
   visits = redis.incr('counter')
   html = "<h3>Hello World!</h3>" \
          "<b>Visits:</b> {visits}" \
          "<br/>"
   return html.format(visits=visits)

if __name__ == "__main__":
   app.run(host="0.0.0.0", port=80)

+ app.py + est une application Web basée sur Flask qui se connecte à un service de données Redis. La ligne + visites = redis.incr ('compteur') + 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:

nano requirements.txt

Ajouter le contenu:

conditions.txt

Flask
Redis

Étape 4 - 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:

nano Dockerfile

Ajoutez le contenu suivant:

Dockerfile

FROM python:2.7

WORKDIR /app

ADD requirements.txt /app/requirements.txt
RUN pip install -r requirements.txt

ADD app.py /app/app.py

EXPOSE 80

CMD ["python", "app.py"]

Analysons le sens de chaque ligne:

  • + FROM python: 2.7 +: indique que notre image d’application «Hello World» est construite à partir du fichier + python: 2.7 + officiel de Docker.

  • + WORKDIR / app +: définit le répertoire de travail à l’intérieur de l’image Docker sur + / app +

  • + ADD exigences.txt / app / exigences.txt: ajoute le fichier` + exigences.txt` à votre image Docker

  • + RUN pip install -r exigences.txt +: installe les dépendances de l’application + pip +

  • + ADD app.py / app / app.py +: ajoute le code source de notre application à 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:

nano docker-compose.yml

Ajoutez le contenu suivant:

docker-compose.yml

web:
 build: .
 dockerfile: Dockerfile
 links:
   - redis
 ports:
   - "80:80"
redis:
 image: redis

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. Il définit un lien vers le conteneur + redis + afin d’avoir accès à l’IP du conteneur + redis +. 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 +

Étape 5 - 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:

docker-compose -f ~/hello_world/docker-compose.yml build
docker-compose -f ~/hello_world/docker-compose.yml up -d

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 + helloworld_web_1 + et + helloworld_redis_1 +.

Voyons si l’application est active. Nous pouvons obtenir l’adresse IP du conteneur + helloworld_web_1 + en exécutant:

WEB_APP_IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' helloworld_web_1)
echo $WEB_APP_IP

Vérifiez que l’application Web renvoie le message approprié:

curl http://${WEB_APP_IP}:80

Cela devrait retourner quelque chose comme:

Sortie

<h3>Hello World!</h3><b>Visits:</b> 1<br/>

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.

Pour un autre exemple sur la manière d’exécuter une application sur plusieurs conteneurs, lisez cet article sur l’exécution de https://www.digitalocean.com/community/tutorials/how-to-install-wordpress-and-phpmyadmin-with-docker-compose. -on-ubuntu-14-04 [WordPress et phpMyAdmin avec Docker Compose].

Étape 6 - 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:

nano test.sh

Ajoutez le contenu suivant:

test.sh

sleep 5
if curl web | grep -q '<b>Visits:</b> '; then
 echo "Tests passed!"
 exit 0
else
 echo "Tests failed!"
 exit 1
fi

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

Étape 7 - 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 5 *.

Premièrement, nous devons dockériser notre script de test en créant un nouveau fichier Dockerfile. Editer un nouveau fichier:

nano Dockerfile.test

Ajoutez le contenu suivant:

Dockerfile.test

FROM ubuntu:trusty

RUN apt-get update && apt-get install -yq curl && apt-get clean

WORKDIR /app

ADD test.sh /app/test.sh

CMD ["bash", "test.sh"]

+ Dockerfile.test + étend l’image officielle + ubuntu: trusty + pour installer la dépendance + curl +, ajoute + tests.sh + au système de fichiers 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:

nano docker-compose.test.yml

Ajoutez le contenu suivant:

docker-compose.test.yml

sut:
 build: .
 dockerfile: Dockerfile.test
 links:
   - web
web:
 build: .
 dockerfile: Dockerfile
 links:
   - redis
redis:
 image: redis

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 +. Il est lié au conteneur + web + afin que l’adresse IP du conteneur d’application soit accessible à notre script + test.sh +.

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

Étape 8 - 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:

docker-compose -f ~/hello_world/docker-compose.test.yml -p ci build

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:

docker-compose -f ~/hello_world/docker-compose.test.yml -p ci up -d

Vérifiez la sortie du conteneur + sut + en exécutant:

docker logs -f ci_sut_1

Sortie

 % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                Dload  Upload   Total   Spent    Left  Speed
100    42  100    42    0     0   3902      0 --:--:-- --:--:-- --:--:--  4200
Tests passed!

Et enfin, vérifiez le code de sortie du conteneur + sut + pour vérifier si vos tests ont réussi:

docker wait ci_sut_1

Sortie

0

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 quel environnement. 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.