12. Déployer un Docker Compose multi-conteneurs - Docker

Nous n'avons pas fini d'explorer le réel intérêt de Docker Compose.
Nous avons jusqu'ici déployé un simple conteneur. Prenons maintenant le cas d'une architecture nécessitant plusieurs conteneurs, avec des dépendances entre eux, comme une application qui se connecte à une base de données par exemple.

Contexte

Dans le cas d'une architecture trois-tiers composée d'un applicatif se connectant à une base de données, chaque composant aura son propre conteneur.
Rappelons que la philosophie de Docker est de dire qu'un conteneur = un processus.
Il n'est pas envisageable de déployer toute cette architecture composant par composant, commande par commande.
C'est ici que Docker Compose intervient, pour déployer le tout en même temps.

Dans l'exemple qui va suivre, nous allons déployer un conteneur Flask (framework Python) connecté à un autre conteneur avec une base de données Redis.

Voici à quoi ressemble notre projet :

├── app.py
├── docker-compose.yml
├── Dockerfile
├── .env
└── requirements.txt

Le conteneur Flask

Inutile de détailler le code Flask, tout ce qu'il faut savoir c'est qu'il récupère le nombre de requêtes HTTP à la racine (/), affiche ce nombre et l'incrémente à chaque nouvelle requête.

L'objectif est d'afficher ceci dans notre navigateur :

Créons notre fichier app.py contenant notre code Flask :

from flask import Flask
from redis import Redis

app = Flask(__name__)
redis = Redis(host='redis', port=6379)
@app.route('/')
def hello():
    redis.incr('hits')
    counter = str(redis.get('hits'),'utf-8')
    return "Cette page a été consultée "+counter+" fois"
if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)

Comme nous voulons exécuter notre propre code dans le conteneur Flask, nous allons construire notre propre image Docker.
Pour ce faire, nous allons créer ce Dockerfile :

FROM python:3.11

WORKDIR /app

COPY requirements.txt /app

RUN pip3 install -r requirements.txt --no-cache-dir

COPY . /app

CMD ["app.py"]

ENTRYPOINT ["python3"]

Vous l'avez vu ! L'instruction RUN mentionne un certain fichier requirements.txt que nous allons tout de suite créer (ce fichier sert à installer les modules Python nécessaires) comme ceci :

flask
redis

C'est tout pour notre conteneur Flask. Nous avons :

  • Notre code
  • Notre image Docker prête à être build
  • Notre fichier requirements.txt contenant les dépendances de notre code à installer

Le Docker Compose

Pour le déploiement de nos deux services Flask et Redis à partir du fichier docker-compose.yml , voici d'abord la composition de notre service Redis :

---
version: '3.3'
services:
  redis: 
    image: bitnami/redis
    container_name: redis
    restart: unless-stopped
    env_file: .env

Deux nouvelles clés entrent en jeu :

  • restart : Cette clé applique une politique de redémarrage pour le conteneur en cas d'echec.
    Ici, la valeur unless-stopped indique que Docker va automatiquement essayer de relancer le conteneur en cas d'echec, sauf si le conteneur est arrêté manuellement.
    Cette clé est l'équivalent de l'argument --restart de la commande docker run
  • env_file : Désigne le fichier contenant les variables d'environnement. Nous verrons son contenu plus bas. Le fichier par défaut est nommé .env. Il est donc possible d'omettre cette clé, sauf si le fichier est nommé différemment.
    C'est l'équivalent de la clé environment pour Docker Compose et de l'argument -e de la commande docker run.

Pour la composition de notre service Flask, voici le bloc suivant :

  flask:
    build: .
    container_name: flask
    restart: unless-stopped
    ports:
      - "5000:5000"
    volumes:
      - app:/code
    depends_on:
      - redis

volumes:
  app:

Les clés build, ports, volumes etc... vous sont familières. Attardons-nous plus particulièrement sur celle-ci :

depends_on : Définit l'ordre de démarrage des conteneurs. Dans notre cas le service Flask ne démarrera pas tant que le conteneur Redis ne sera pas démarré.

Comme dit plus haut, nous allons définir les variables d'environnement de nos conteneurs dans un fichier nommé .env comme ceci :

ALLOW_EMPTY_PASSWORD=yes

Cette variable d'environnement est propre au conteneur Redis mais le contenu de ce fichier s'applique pour toute notre Docker Compose.

Voici à quoi ressemble le fichier docker-compose.yml au complet :

---
version: '3.3'
services:
  redis: 
    image: bitnami/redis
    container_name: redis
    restart: unless-stopped
    env_file: .env

  flask:
    build: .
    container_name: flask
    restart: unless-stopped
    ports:
      - "5000:5000"
    volumes:
      - app:/code
    depends_on:
      - redis

volumes:
  app:

Pour le déployer, il suffit d'exécuter la commande suivante :

docker-compose up -d

Il est possible de vérifier le statut des conteneurs avec la commande suivante :

docker-compose ps

C'est l'équivalent de la commande docker ps mais avec une sortie différente.

Pour vérifier si notre projet a été déployé correctement, il suffit de se rendre sur son navigateur et d'accéder à http://localhost:5000.

Maintenant que nous avons déployé plusieurs conteneurs simultanément, regardons dans le cours suivant comment les administrer.