Nous avons vu dans notre article Docker : Maîtrisez la conteneurisation applicative de A à Z [Guide ultime] une vue d’ensemble de Docker. Dans un autre article, nous avons également détaillé la fonctionnalité docker run qui sert à exécuter un conteneur. Dans celui-ci nous continuons dans cette lignée en découvrant plus en détail docker compose.

Comme nous l’avons mentionné dans les articles mentionnés ci-dessus, Docker regorge de fonctionnalités plus intéressantes les unes que les autres permettant de conteneuriser une application. Dans ce mini-tutoriel, nous allons vous montrer comment utiliser docker compose pour exécuter une application multiconteneur.

Qu’est-ce qu’un docker compose ?

Lorsque l’on crée et déploie une application, on a souvent besoin de solliciter plusieurs services et autres solutions. Par exemple, on peut avoir l’application en elle-même, mais également la base de données ou encore le serveur de l’application. Et pour que celle-ci puisse fonctionner correctement, il faut que tous ces composants puissent être exécutés simultanément et c’est là que docker compose entre en jeu.

Docker compose est une fonctionnalité permettant d’orchestrer plusieurs conteneurs qui doivent travailler ensemble. Pour ce faire, on crée un fichier YAML (Yet Another Markup Language) à l’intérieur duquel on spécifie les configurations nécessaires à chaque service. Grâce à docker compose, tous les conteneurs dont on a besoin pourront être exécutés à l’aide d’une seule commande.

Quand utiliser un docker compose ?

On peut utiliser un docker compose dans plusieurs étapes de la création d’une application. Cependant, on le sollicite le plus souvent dans deux cas d’utilisation à savoir le développement et le test.

Pour une personne qui commence un projet, elle peut se confronter au manque de ressources nécessaires afin de le mener à bien. En effet, pour qu’une application puisse être fonctionnelle, il faut en général un serveur de déploiement, un outil de gestion de base de données et plusieurs autres technologies et frameworks.

La mise en place de tout cela peut être une tâche fastidieuse, ce qui peut ralentir le projet, voire décourager l’investigateur.

En utilisant docker compose, toutes ces configurations s’effectuent dans un seul et même fichier. Chaque composant du projet ainsi que leurs dépendances peuvent être conteneurisés. On peut ensuite regrouper tous les services dans un fichier YAML.

Procéder ainsi réduit considérablement le coût de développement, mais aussi permet de faciliter le reste du processus de création de l’application, car tout est regroupé dans un seul endroit.

Les tests sont également plus faciles à entreprendre lorsque l’on utilise docker compose, surtout s’il s’agit d’un test isolé. On peut créer autant de conteneurs possibles avec la même base de docker compose. En plus, on peut le lancer et le stopper selon nos besoins à l’aide de simples commandes. Il n’est donc pas nécessaire de configurer plusieurs environnements pour ce type de tâche, quel que soit le système utilisé, puisque Docker est multiplateforme.

Comment utiliser un docker compose ?

Dans ce tutoriel exhaustif, vous allez apprendre à manipuler le docker compose et à exécuter une application multiconteneur grâce aux fonctionnalités qu’il offre. Nous allons détailler cela étape par étape pour que vous puissiez suivre correctement le processus, alors commençons.

Installer Compose

Ici, on suppose que vous avez déjà installé docker sur votre machine. Si ce n’est pas le cas, vous pouvez vous rendre sur notre tutoriel complet sur docker afin de suivre les étapes nécessaires.

Pour ceux qui travaillent sur un système Windows ou Mac, il n’est pas utile d’installer Compose, puisque ce dernier est déjà inclus dans les dernières versions de Docker Desktop.

Quant à ceux qui utilisent Linux, il faut suivre les étapes suivantes pour disposer de compose sur votre système :

  • Télécharger Docker compose à l’aide de la commande ci-dessous :
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  • Ajouter docker compose au fichier bin afin d’autoriser l’exécution avec cette commande :
sudo chmod +x /usr/local/bin/docker-compose
  • Tester docker compose en demandant la version existante :
docker-compose --version

Si cette commande échoue, vous pouvez revoir le deuxième point, car il s’agit peut-être du chemin que vous avez spécifié. Ce dernier peut être introuvable, auquel cas il faut le modifier en créant juste un lien symbolique.

Note : Si vous utilisez alpine, il faut que les dépendances suivantes soient disponibles : py-pip, python3-dev, libffi-dev, openssl-dev, gcc, libc-dev, rust et cargo.make.

Et voilà, vous pouvez maintenant utiliser docker compose, quel que soit votre système d’exploitation. Nous pouvons maintenant passer à la suite.

Configurer l’application à conteneuriser

Dans cette section et celles qui suivront, nous allons nous baser sur l’exemple que nous avons également vu dans notre tutoriel complet, à la partie sur Nginx. Vous pouvez retrouver la base de ce programme ici : https://github.com/docker/getting-started/tree/master/app

Ce que vous allez faire, c’est de récupérer la partie /app de ce projet, créer un dockerfile dans ce dossier et coller ces instructions dans ce fichier :

FROM node:12-alpine
WORKDIR /app
RUN apk add --no-cache python2 g++ make
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
EXPOSE 3000
dockerfile

Vous allez ensuite créer un dossier nommé nginx à l’intérieur de app/ dans lequel vous allez créer deux fichiers : un fichier appelé nginx.conf et un autre dockerfile.

Dans nginx.conf, voici les instructions à intégrer :

server {
    listen [::]:80;
    listen 80;
    server_name nodeserver;
    charset utf-8;
    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_pass http://nodeserver:3000;
    }
}
nginx-conf

Et dans le dockerfile, il faut ajouter les lignes suivantes :

FROM nginx
COPY nginx.conf /etc/nginx/conf.d/default.conf
nginx-dockerfile

Vous avez maintenant les environnements nécessaires pour la suite.

Créer un docker compose

Une fois que vous avez vos bases de conteneurs, il faut créer le fichier qui va les exécuter simultanément, à savoir le fichier nommé docker-compose.yml. Pour ce faire, rendez-vous à la racine du projet à savoir le dossier /app et créer ce fichier. Ajoutez à l’intérieur de celui-ci les instructions suivantes :

version: "3.8"
services:
    nodeserver:
        build:
            context: .
        ports:
            - "3000:3000"
    nginx:
        restart: always
        build:
            context: ./nginx
        ports:
            - "80:80"
docker-compose-yml

Examinons un peu ce qui se trouve dans ce fichier. Tout d’abord, nous voyons la version que nous souhaitons exécuter.

Ensuite, les lignes qui suivent contiennent l’ensemble des services, c’est-à-dire la désignation de tous les conteneurs à exécuter à savoir celui de l’application node JS et du serveur Nginx. Vous êtes libre de renommer les services comme vous le souhaitez.

Chaque service possède des spécifications précises comme les informations sur l’emplacement des dépendances à exécuter. Ici, dans la partie build, nous voyons un paramètre appelé context qui désigne l’emplacement du dockerfile de l’image docker.

Nous avons également une partie appelée ports dans laquelle on spécifie le port vers lequel pointe l’application une fois celle-ci exécutée.

Cet exemple montre un docker-compose très basique, nous allons étoffer ce dernier le long de cet article avec d’autres fonctionnalités.

Exécuter un docker compose

Avant d’ajouter d’autres informations à l’intérieur de ce fichier docker-compose, nous allons tout d’abord tester si celui-ci fonctionne correctement. Pour ce faire, nous allons exécuter l’application multiconteneur avec la commande suivante :

docker-compose up
docker-compose-up

Avec cette commande, l’application se lance en avant-plan, c’est-à-dire que vous pouvez interagir avec l’application directement à partir de l’invite de commande. Cependant, cela vous empêche d’exécuter d’autres commandes jusqu’à ce que l’on arrête les conteneurs.

docker-compose-up2

Pour remédier à cela, on peut lancer l’application en mode détachée, comme c’est le cas de docker run. Pour ce faire il faut juste ajouter le mot clé -d à la fin de la commande précédente.

Une fois que vous avez exécuté cette commande, vous pouvez taper localhost sur votre navigateur pour avoir accès à l’application.

todo-app-test

Une autre manière de vérifier si tout s’est bien passé est de taper la commande suivante qui va lister les images disponibles :

docker images
docker-images

Vous pouvez aussi ne lister que les services en cours d’exécution en tapant la commande ci-dessous :

docker-compose ps
docker-compose-ps

Pour arrêter les services, il vous suffit de taper la commande docker-compose down ou CTRL+C dans le cas où vous avez lancé l’application sans utiliser la mode détachée.

docker-compose-arret

Autres fonctionnalités

Nous allons maintenant ajouter quelques fonctionnalités en plus à notre application.

Monter un volume et définir une variable d’environnement

Commençons par le volume. Ce dernier permet d’identifier des dossiers ou des fichiers nécessaires pour que l’on puisse modifier ou ajouter des fonctionnalités à l’application, sans pour autant réexécuter docker-compose.

Une variable d’environnement, quant à lui, permet de définir un ensemble de clés/valeurs qui peut spécifier l’état dans lequel on souhaite lancer le conteneur ou un paramètre nécessaire à l’application pour son bon fonctionnement.

Par exemple, nous allons ajouter le répertoire contenant le code source de notre application dans la section volume de docker-compose.yml. Nous allons également ajouter une variable d’environnement spécifiant le type d’environnement avec lequel on souhaite exécuter l’application comme ceci :

version: "3.8"
services:
    nodeserver:
        build:
            context: .
        volumes:
            - ./src:/app/src
        environment:
            NODE_ENV: production
        ports:
            - "3000:3000"
    nginx:
        restart: always
        build:
            context: ./nginx
        ports:
            - "80:80"
docker-compose-yml-volume

Ici, l’instruction – ./src:/app/src spécifie que nous allons récupérer le code source de notre application dans le dossier src à la racine de notre projet. Nous allons par la suite le copier dans un autre fichier src. Ce dernier va être créé dans le dossier app que nous avons spécifié dans la section WORKDIR du dockerfile.

Maintenant, si l’on modifie un peu notre code source et que l’on actualise l’application, la modification sera prise en compte instantanément.

todo-app-modification

Attribuer et activer des profils

Un profil sert à activer ou non un service présent dans le fichier docker-compose selon la ou les valeurs spécifiées dans cette clause. Cela veut dire que si le profil défini n’est pas activé au moment du démarrage du conteneur, le service en question ne démarrera pas.

Considérons notre précédent exemple et ajoutons un profil dans le service nodeserver :

version: "3.8"
services:
    nodeserver:
        build:
            context: .
        volumes:
            - ./src:/app/src
        environment:
            NODE_ENV: production
        profiles:
            - debug
        ports:
            - "3000:3000"
    nginx:
        restart: always
        build:
            context: ./nginx
        ports:
            - "80:80"
docker-compose-profil

Pour lancer un conteneur en activant un profil, il faut exécuter la commande suivante :

docker-compose --profile debug up

où debug est le nom du profil que nous venons de spécifier dans le fichier docker-compose.

docker-compose-profil-up

Voilà, vous savez maintenant utiliser docker-compose afin de lancer vos applications multiconteneurs en une seule commande. Les fonctionnalités que nous venons de voir vont vous permettre de bien paramétrer votre fichier. Cela permet de mieux gérer l’exécution de chaque conteneur inclus dans docker-compose et lancer votre application selon vos besoins.

Si vous souhaitez apprendre d’autres fonctionnalités Docker, vous pouvez parcourir notre blog, car quelques articles sur ce sujet y sont présents. Et si vous souhaitez aller plus loin dans le Big Data, nous vous invitons à télécharger notre formation sur Spark avec Scala.


Juvénal JVC

Juvénal est spécialisé depuis 2011 dans la valorisation à large échelle des données. Son but est d'aider les professionnels de la data à développer les compétences indispensables pour réussir dans le Big Data. Il travaille actuellement comme Lead Data Engineer auprès des grands comptes. Lorsqu'il n'est pas en voyage, Juvénal rédige des livres ou est en train de préparer la sortie d'un de  ses livres. Vous pouvez télécharger un extrait de son dernier livre en date ici : https://www.data-transitionnumerique.com/extrait-ecosystme-hadoop/

  • Donald Mbouendeu dit :

    Merci à vous Juvenal, j’aimerais beaucup avoir la maitrise de tous ces outils.

    • Juvénal JVC dit :

      Bonjour Donald,
      vous êtes au bon endroit pour ça !

  • >