Aller au contenu principal

Introduction à Docker Compose

Lorsqu’on utilise juste Docker, pouvoir gérer plusieurs conteneurs différents peut vite devenir fastidieux. Docker Compose est une première solution pour les orchestrer plus facilement.

Introduction

Docker Compose intervient en tant qu'outil essentiel. Docker Compose est une extension de Docker qui permet de définir et de gérer des applications multi-conteneurs grâce à des fichiers de configuration simples utilisant le langage YAML. Plutôt que de gérer manuellement chaque conteneur individuellement, Docker Compose permet de déclarer les services, les réseaux, les volumes dans un seul fichier, ce qui simplifie considérablement le processus de déploiement.

Dans ce tutoriel, nous verrons les principales fonctionnalités, mais attardons pour commencer sur son installation et ensuite sur son fichier de configuration écrit en yaml.

Installation de docker-compose

attention

Attention désormais Docker Compose est un plugin de la CLI Docker-CE !

for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt remove $pkg; done

sudo apt update
sudo apt install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

On vérifie :

docker compose --help

Usage:  docker compose [OPTIONS] COMMAND

Define and run multi-container applications with Docker.

Options:
      --ansi string                Control when to print ANSI control characters ("never"|"always"|"auto") (default "auto")
      --compatibility              Run compose in backward compatibility mode
      --dry-run                    Execute command in dry run mode
      --env-file stringArray       Specify an alternate environment file.
  -f, --file stringArray           Compose configuration files
      --parallel int               Control max parallelism, -1 for unlimited (default -1)
      --profile stringArray        Specify a profile to enable
      --progress string            Set type of progress output (auto, tty, plain, quiet) (default "auto")
      --project-directory string   Specify an alternate working directory
                                   (default: the path of the, first specified, Compose file)
  -p, --project-name string        Project name

Commands:
  build       Build or rebuild services
  config      Parse, resolve and render compose file in canonical format
  cp          Copy files/folders between a service container and the local filesystem
  create      Creates containers for a service.
  down        Stop and remove containers, networks
  events      Receive real time events from containers.
  exec        Execute a command in a running container.
  images      List images used by the created containers
  kill        Force stop service containers.
  logs        View output from containers
  ls          List running compose projects
  pause       Pause services
  port        Print the public port for a port binding.
  ps          List containers
  pull        Pull service images
  push        Push service images
  restart     Restart service containers
  rm          Removes stopped service containers
  run         Run a one-off command on a service.
  start       Start services
  stop        Stop services
  top         Display the running processes
  unpause     Unpause services
  up          Create and start containers
  version     Show the Docker Compose version information
  wait        Block until the first service container stops

Run 'docker compose COMMAND --help' for more information on a command.

Structure d'un fichier Docker Compose

Le fichier Docker Compose, docker-compose.yaml définit l'ensemble des services qui composent votre application, ainsi que leurs configurations, les réseaux et les volumes associés. Voici une structure de base d'un fichier Docker Compose :

version: '3' # Version de Docker Compose à utiliser

services:
  service1: # Nom du premier service
    image: nom_de_l_image # Image Docker utilisée pour ce service
    ports:
      - "port_hôte:port_conteneur" # Mappage des ports
    environment:
      - VARIABLE_1=valeur_1 # Variables d'environnement
    volumes:
      - /chemin/hote:/chemin/conteneur # Mappage de volumes
    depends_on:
      - service2 # Dépendances entre les services

  service2:
    # Configuration du deuxième service
    # ...

networks:
  mynetwork: # Définition d'un réseau personnalisé
    driver: bridge # Type de réseau

Configuration des services

Commençons maintenant par inspecter les principaux paramètres d'un service.

Les images

Si l'image dont nous avons besoin pour notre service a déjà été publiée dans une registry, alors nous il utiliser la référence avec l'attribut image :

services:
  my-service:
    image: ubuntu:latest

Il est aussi possible de créer une image à partir du code d'un fichier Dockerfile, avec le paramètre build. Ce paramètre peut être un chemin ou une Url :

services:
  web:
    build: /path/to/dockerfile/
    ...
  db:
    build: https://gitlab.com/srobert/my-project.git

Il est possible d'ajouter le paramètre image qui taguera l'image une fois créée. Ce qui permet de la rendre disponible pour d'autres services :

services:
  web:
    build: https://gitlab.com/srobert/my-project.git
    image: my-project-image
    ...

La gestion des dépendances entre services

La directive depends_on permet de définir des dépendances entre les services. Elle spécifie qu'un service donné dépend d'un ou plusieurs autres services avant de pouvoir être démarré. Cela permet de garantir que les services requis sont opérationnels avant de lancer un service dépendant.

L'utilisation de depends_on est particulièrement utile lorsque vous avez une application composée de plusieurs services et que certains d'entre eux ont besoin d'attendre que d'autres services soient prêts avant de pouvoir fonctionner correctement. Voici comment cela fonctionne :

Supposons que vous ayez une application composée de deux services : un service de base de données (par exemple, PostgreSQL) et un service d'application web (par exemple, un serveur Node.js). Le service d'application web dépend de la base de données pour fonctionner correctement.

version: '3'

services:
  app:
    image: my-node-app
    ports:
      - "80:80"
    depends_on:
      - db

  db:
    image: postgres:latest
    environment:
      POSTGRES_PASSWORD: mysecretpassword

Dans cet exemple, le service app dépend du service db. Lorsque vous utilisez docker-compose up pour lancer l'ensemble de l'application, Docker Compose veillera à ce que le service db soit démarré en premier, puis seulement le service app sera lancé. Cela garantit que le service d'application web a accès à la base de données dès son démarrage.

Il est important de noter que bien que depends_on permette de gérer l'ordre de démarrage des services, il ne garantit pas que le service dépendant a terminé son initialisation avant de démarrer le service dépendant. Certains services peuvent être prêts à accepter des connexions plus rapidement que d'autres. Pour gérer la synchronisation des dépendances plus avancées, vous devrez peut-être utiliser des outils supplémentaires ou des scripts dans vos conteneurs.

Configuration des réseaux

Les conteneurs Docker communiquent entre eux dans des réseaux créés, implicitement ou via la configuration du même nom.

services:
  service-1:
    image: alpine:latest
    networks:
      - network-1
    ...
  service-2:
    image: alpine:latest
    networks:
      - network-1
    ...
  service-3:
    image: alpine:latest
    networks:
      - network-2
    ...
networks:
  network-1: {}
  network-2: {}

Vous pouvez spécifier le type de réseau (par exemple, bridge pour un réseau privé), ce qui permet aux services de communiquer entre eux de manière sécurisée.

networks:
  network-1: # Définition d'un réseau personnalisé
    driver: bridge # Type de réseau

Exposition de ports

Pour atteindre un port d'un conteneur depuis l'hôte, il doit être exposé de manière déclarative via le mot-clé ports :

services:
  service-1:
    image: alpine:latest
    ports:
      - "80:80"
    ...
  service-2:
    image: alpine:latest
    ports:
      - "8080:3000"
    ...
  service-3:
    image: alpine:latest
    ports:
      - "8081:3000"
    ...

Le premier chiffre indique le port sur l'hôte et le second celui du conteneur. Ainsi le port 80 sera visible depuis l'hôte, tandis que le port 3000 des deux autres conteneurs seront disponibles sur les ports 8080 et 8081 de l'hôte. Cela permet d'exécuter différents conteneurs exposant les mêmes ports sans collisions.

Les volumes

La directive volumes permet de configurer des volumes nommés qui peuvent être réutilisés sur plusieurs services. Pour utiliser un volume sur plusieurs services, vous devez explicitement accorder l'accès à chaque service à l'aide de l'attribut volumes.

services:
  service-1:
    image: alpine:latest
    volumes:
      - global-volume:/my-volumes/named-global-volume
    ...
volumes:
  global-volume:

Les variables d'environnement

Il est possible de définir des variables d'environnement statiques, ainsi que des variables dynamiques, avec la notation ${} :

services:
  database:
    image: "postgres:${POSTGRES_VERSION}"
    environment:
      DB: mydb
      USER: "${USER}"

On peut par exemple les définir dans un fichier .env dans le même répertoire.

La gestion des secrets

Dans un environnement DevOps, la gestion des secrets est une préoccupation importante pour garantir la sécurité des données sensibles, telles que les informations d'authentification, les clés API et les autres données confidentielles utilisées par les applications. Docker Compose offre des fonctionnalités pour gérer ces secrets de manière sécurisée. Dans cette partie, nous allons explorer comment Docker Compose permet de gérer les secrets dans un environnement de déploiement.

Création de Secrets

Pour créer un secret dans Docker Compose, vous devez d'abord le définir dans un fichier de configuration. Voici un exemple de définition de secret dans un fichier Docker Compose YAML :

version: '3'

services:
  myapp:
    image: myapp:latest
    secrets:
      - my_secret
secrets:
  my_secret:
    file: ./my_secret.txt

Dans cet exemple, nous avons défini un service myapp qui utilise un secret nommé my_secret. Le secret est défini en dehors de la section services, sous la section secrets, avec un chemin vers un fichier my_secret.txt qui contient la valeur du secret.

Accès aux Secrets dans les Conteneurs

Les secrets définis dans Docker Compose sont montés dans les conteneurs en tant que fichiers dans le répertoire /run/secrets/. Les conteneurs peuvent y accéder comme s'il s'agissait de fichiers normaux. Par exemple, si vous avez défini un secret nommé my_secret, le conteneur peut le lire depuis /run/secrets/my_secret.

Sécurité des secrets

Les secrets définis dans Docker Compose sont stockés de manière sécurisée sur le système hôte. Ils sont uniquement accessibles par les conteneurs spécifiques qui en ont besoin, ce qui garantit leur confidentialité. De plus, Docker Compose permet de chiffrer les secrets en transit entre les services, renforçant ainsi la sécurité de l'ensemble du processus.

Les commandes de la CLI

Examinons maintenant de plus près la syntaxe de Docker Compose :

docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]

Bien qu'il existe de nombreuses options et commandes disponibles, nous devons au moins connaître celles qui permettent de lancer et d'arrêter les services.

Premier lancement

Pour démarrer les conteneurs, les réseaux et les volumes définis dans la configuration, on utilise l'option up :

docker-compose up

Si le fichier de configuration a un nom différent de celui par défaut, docker-compose.yml, vous pouvez utiliser l'option -f avec le nom du fichier :

docker-compose -f custom-compose-file.yml up

On peut aussi demander à docker compose de s'exécuter en arrière-plan en tant que démon avec l'option -d :

docker-compose up -d

Stop

Pour arrêter les services actifs en toute sécurité, nous pouvons utiliser stop, qui préservera les conteneurs, les volumes et les réseaux, ainsi que toutes les modifications qui leur sont apportées :

docker-compose stop

Start

Cependant, après la première fois, nous pouvons simplement utiliser start pour démarrer les services :

docker-compose start

Arrêt et nettoyage

Pour réinitialiser le statut de notre projet, nous pouvons simplement utiliser la commande down, ce qui détruira tout à l'exception des volumes externes :

docker-compose down

Plus d'infos

Vidéos