Cartouche

Champ Valeur
Auteur·e Élise
Édition 2025-02-10
Taille des équipes 1 personnes
Rendu via git, dans vos forks, avec les droits en lecture à delivery-collector

Introduction

Plus les exercices passent, plus vos commandes docker run sont longues, et elles commencent à prendre plusieurs lignes et il en faut plusieurs pour déployer un projet. En plus vous devez faire des commandes pour déclarer vos réseaux, créer des volumes, etc.

Les exercices précédents vous demandent de documenter vos avancées dans des scripts .sh. L’avantage, c’est qu’ils vous permettent de consigner les commandes à faire pour faire fonctionner un projet. Le désavantage c’est qu’ils ne sont pas idempotents. Ce qui signifie : si une étape (comme créer un réseau ou démarrer) est déjà faite, le script peut planter.

Pour résoudre ces problèmes d’expérience développeur (DX), il existe c’est fichiers docker-compose.yaml.

Ce sont des fichiers avec plusieurs sections :

  • services décrit des conteneurs et les options avec lesquelles démarrer ;
  • volumes décrit les volumes que peuvent utiliser les services ;
  • networks décrit les réseaux que peuvent utiliser les services.

Prenons pour exemple ces commandes qui démarrent un frontend, un backend et une base de données, sur un réseau :

docker network create app-net
docker volume create pg_data

docker build -t fe ./fe
docker build -t be ./be

docker run -d --name db \
  --network app-net \
  --restart always \
  -e POSTGRES_PASSWORD=your_password \
  -e POSTGRES_USER=ticket_user \
  -e POSTGRES_DB=ticket_db \
  -v pg_data:/var/lib/postgresql \
  --health-cmd="pg_isready -U ticket_user -d ticket_db" \
  --health-interval=5s \
  --health-timeout=5s \
  --health-retries=5 \
  postgres:18

until [ "$(docker inspect --format='{{.State.Health.Status}}' db)" = "healthy" ]; do
  echo "En attente de db..."
  sleep 2
done

docker run -d --name be \
  --network app-net \
  -e DATABASE_URL="postgres://ticket_user:your_password@db/ticket_db" \
  -e RUST_LOG="sqlx=warn,ticket_please_be=info,poem=warn" \
  be

docker run -d --name fe \
  --network app-net \
  -p 80:80 \
  fe

Elles peuvent être exprimées ainsi dans un docker-compose.yaml :

services:
  fe:
    build: ./fe
    ports:
      - 80:80
  be:
    build: ./be
    depends_on:
      db:
        condition: service_healthy
    environment:
      DATABASE_URL: "postgres://ticket_user:your_password@db/ticket_db"
      RUST_LOG: sqlx=warn,ticket_please_be=info,poem=warn
  db:
    image: postgres:18
    restart: always
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ticket_user -d ticket_db"]
      interval: 5s
      timeout: 5s
      retries: 5
    environment:
      POSTGRES_PASSWORD: your_password
      POSTGRES_USER: ticket_user
      POSTGRES_DB: ticket_db
    volumes:
      - pg_data:/var/lib/postgresql

volumes:
  pg_data:

Une fois cette configuration écrite, les commandes pour s’en servir sont les suivantes (si tant est que le docker-compose.yml se trouve dans le repertoire courant) :

# Démarre les services, au premier plan dans ce terminal
docker compose up

# Démarre seulement la db
docker compose up db

# Démarre les services, en arrière plan (mode détaché)
docker compose up -d

# Liste les conteneurs en cours d'exéuction pour ce docker-compose.yml
docker compose ps

# Exécute une commande sur le conteneur d'un service en cours
# de fonctionnement
docker compose exec nom_de_service ...ARGUMENTS_DE_COMMANDE
# exemple:
docker compose exec api echo "hello world"

# Arrête les conteneurs, mais ne les supprime pas, dans le but de pouvoir
# les redémarrer
docker compose stop

# Arrête les services, et supprime les contenneurs
docker compose down

# Arrête les services, et supprime les contenneurs et les volumes nommés
docker compose down -v

# provoque la construction des services qui ont une clause "build", en utilisant
# le Dockerfile qui se trouve au chemin indiqué par la clause "build".
docker compose build

# provoque la construction du service be grâce à sa clause build
docker compose build be

Exercice A : compose elysia hello

Commençons par le docker-compose.yml qui permet de déployer un seul service. Dans votre dépôt YEAR_elysia_hello (où YEAR correspond au début de l’année scolaire, comme toujours) vous devez écrire le fichier docker-compose.yml qui :

  • construit l’image ;
  • fait écouter le conteneur sur 6543 ;
  • fait répondre à l’API “hello compose” lorsqu’on lui fait une requête.

Dans votre README.md ajoutez les commandes compose qui permettent de lancer l’API.

Exercice B : compose Elysia Valkey

Faites un fork de ce dépôt et appelez-le YEAR_elysia_valkey (où YEAR correspond au début de l’année scolaire, comme toujours).

Il contient le code de l’exemple – provenant d’une vidéo démonstration – d’une API qui utilise un serveur valkey/redis.

Écrivez le fichier docker-compose.yaml qui permet la construction et l’exécution de l’API et d’un serveur soit redis, soit valkey. Ce n’est pas grave si au docker-compose down le contenu de la base de donnée est perdu.

Écrivez dans un fichier README.md la ou les commande·s qui permettent de lancer le projet avec docker compose.

Exercice C : compose ruby todo

Dans votre fork du dépôt ruby_todo, écrivez le fichier docker-compose.yaml qui permet la construction et le déploiement des 3 livrables du projet :

  • frontend servit par un serveur web
    • sur le port 80 de l’hôte
  • API Ruby on Rails ;
  • Base de données PostgreSQL.