YML Guide pas-à-pas - Laboratoire Compose

WordPress en trois services
avec Docker Compose

Fini les commandes docker run de trois lignes : la partition décrit l'application entière, et une seule commande la fait lever. Quatre étapes guidées : PARTITION, LEVER, SECRETS, SURVIE.

Ce qu'on vous fournit

La sauvegarde complète du site en ligne cornucopia.projet.autos, la boutique de Flora, en un seul fichier : sauvegarde-cornucopia-abonnement.zip (39 Mo). Il contient :

Comptes du tableau de bord pour ce laboratoire : agence, flora et hazel, tous avec le mot de passe cornucopia-2026. Les mots de passe de la sauvegarde ont été réinitialisés pour le laboratoire : ce ne sont pas ceux du site en production.

Trois images officielles de Docker Hub : wordpress (figée en version 7.1), mysql et phpmyadmin. Rien à construire cette semaine : toute l'intelligence du laboratoire tient dans un seul fichier que vous écrivez vous-même, docker-compose.yml.

Vous y ajoutez : docker-compose.yml (la partition), .env (les clés secrètes) et votre README.md.

Avant de commencer

Pré-requis

Vue d'ensemble

Le parcours en quatre étapes

La grande idée : décrire au lieu de commander. Le WordPress de la semaine dernière devient une partition en trois services (le web, la base de données, phpMyAdmin), chacun dans son conteneur, tous levés d'une seule commande. Et vous prouverez que les données survivent au grand ménage.

Étape 01 · Partition

Déballer le site, écrire la partition

Étape 02 · Lever

docker compose up -d

Étape 03 · Secrets

Sortir les mots de passe dans .env

Étape 04 · Survie

stop, down, rm et la preuve

01

Écrire la partition : trois services dans un fichier

Partition

Créer le répertoire du projet, y déballer la sauvegarde de Cornucopia, puis décrire l'application entière : le service wordpress, le service db et le service phpmyadmin, reliés par un réseau et nourris par les fichiers et la base de données de la sauvegarde, montés depuis la machine hôte.

Pour mieux comprendre

Un service de la partition correspond à un conteneur. Les services se trouvent entre eux par leur nom : WordPress joint sa base à l'adresse db:3306 parce que le service s'appelle db. C'est le DNS interne de Docker qui fait la traduction : aucun numéro IP dans la partition.

Comme au laboratoire Docker, on ne réinstalle pas WordPress : on transplante la sauvegarde. L'image officielle wordpress:7.1 fournit le serveur (PHP, Apache, WordPress 7.1); nous y apportons notre site : notre thème, nos téléversements, notre module d'abonnement, notre wp-config.php et notre base de données. Et cette fois, pas de Dockerfile ni de COPY : les fichiers du site sont montés depuis l'hôte dans le service wordpress, et l'export de la base est déposé dans le service db, qui l'importe tout seul à son premier démarrage.

Démarche - récupérer la sauvegarde

C'est ici que le zip du matériel entre en scène : il se déballe dans le répertoire du projet, à côté de la partition que vous écrirez ensuite.

Terminal - le répertoire du projet et la sauvegarde
$ mkdir ~/my_wordpress
$ cd ~/my_wordpress
$ wget https://evolutif.projet.autos/laboratoire/conteneurs/compose/guide/sauvegarde-cornucopia-abonnement.zip
$ unzip sauvegarde-cornucopia-abonnement.zip
$ ls
base-de-donnees.sql  fichiers-wordpress  README.md  sauvegarde-cornucopia-abonnement.zip
$ sudo chown -R www-data:www-data fichiers-wordpress
# Apache, dans le conteneur, doit pouvoir ecrire (televersements, mises a jour)

Deux ajustements avant de lever quoi que ce soit. D'abord wp-config.php : la base ne vit plus sur localhost mais dans le service db (les autres valeurs, base cornucopia, compte flora, mot de passe potager-2026, restent telles quelles, le README.md les récapitule) :

fichiers-wordpress/wp-config.php - une seule ligne à changer
$ sudo nano fichiers-wordpress/wp-config.php
define( 'DB_HOST', 'db:3306' );

Ensuite l'adresse : la sauvegarde croit que le site vit à https://cornucopia.projet.autos. On ajoute à la fin de l'export les trois requêtes de repointage vues au laboratoire Docker; elles s'exécuteront toutes seules lors de l'import, au premier démarrage du service db :

Terminal - repointer l'adresse dans l'export
# ADRESSE-DE-VOTRE-INSTANCE = ce que vous taperez dans le navigateur, sans le port :
#   localhost        (Docker sur votre poste)
#   192.168.56.2     (machine virtuelle VirtualBox, son adresse IP vue de votre poste)
#   203.0.113.10     (VPS : son adresse IP publique, ou son nom de domaine)
$ tee -a base-de-donnees.sql <<'FIN'
UPDATE wp_options SET option_value='http://ADRESSE-DE-VOTRE-INSTANCE:8082'
    WHERE option_name IN ('siteurl','home');
UPDATE wp_posts SET post_content = REPLACE(post_content,
    'https://cornucopia.projet.autos', 'http://ADRESSE-DE-VOTRE-INSTANCE:8082');
UPDATE wp_posts SET guid = REPLACE(guid,
    'https://cornucopia.projet.autos', 'http://ADRESSE-DE-VOTRE-INSTANCE:8082');
FIN
L'adresse du repointage est celle avec laquelle vous visiterez le site à l'étape 02 : localhost sur votre poste, l'adresse IP de la machine virtuelle avec VirtualBox, l'adresse publique sur un VPS. Et il faut la faire AVANT le premier up : l'import ne se rejoue pas tant que ./database existe.

Démarche - écrire la partition

Terminal - la partition
$ nano docker-compose.yml

La partition à compléter (le mot de passe root de MySQL est racine-potager-2026 pour ce laboratoire, il revient à l'étape 03; la base, le compte et le mot de passe de Flora sont imposés par le wp-config.php de la sauvegarde) :

docker-compose.yml - squelette
services:
  wordpress:
    depends_on:
      - db
    image: wordpress:7.1
    restart: always
    volumes:
      - ./fichiers-wordpress:/var/www/html
    ports:
      - 8082:80
    networks:
      - myNetwork
  db:
    image: mysql:8.0
    restart: always
    volumes:
      - ./database:/var/lib/mysql
      - ./base-de-donnees.sql:/docker-entrypoint-initdb.d/base-de-donnees.sql
    environment:
      MYSQL_ROOT_PASSWORD: racine-potager-2026
      MYSQL_DATABASE: cornucopia
      MYSQL_USER: flora
      MYSQL_PASSWORD: potager-2026
    networks:
      - myNetwork
  phpmyadmin:
    depends_on:
      - db
    image: phpmyadmin
    restart: always
    ports:
      - 8083:80
    environment:
      PMA_HOST: db
      MYSQL_ROOT_PASSWORD: racine-potager-2026
    networks:
      - myNetwork
networks:
  myNetwork:

L'image wordpress est figée à la version 7.1 : le thème et la base de données de la sauvegarde sont calibrés sur elle, alors que latest bougera pendant la session. Ne changez pas cette version. Même prudence pour mysql:8.0, la version avec laquelle l'import de la sauvegarde a été validé.

Pas de variables WORDPRESS_DB_* dans le service wordpress : le wp-config.php de la sauvegarde raconte déjà la connexion à la base, et l'image ne le remplace jamais quand il est présent. C'est le service db qui doit offrir exactement la base et le compte qu'il attend. Le fichier base-de-donnees.sql, déposé dans /docker-entrypoint-initdb.d/, est importé automatiquement par l'image mysql au premier démarrage, quand ./database est encore vide.

En YAML, l'indentation est la grammaire : deux espaces par niveau, jamais de tabulations. Un espace en trop devant image: et Compose refuse tout le fichier. La moitié des bogues de la semaine seront des problèmes d'indentation.
La commande docker compose config relit votre partition et l'affiche sans message d'erreur : la grammaire est bonne.
02

Lever l'application : une commande, trois services

Lever

Démarrer l'application entière avec docker compose up -d et observer ce que Compose fait tout seul : le réseau, les répertoires de données, l'ordre de démarrage, et l'import de la sauvegarde au premier démarrage de la base.

Terminal - lever, observer
$ sudo docker compose up -d
# tout demarre : reseau, conteneurs, dans le bon ordre
$ sudo docker compose ps
$ sudo docker compose logs db
# le premier demarrage importe base-de-donnees.sql : comptez quelques secondes

Ce qu'il faut aller voir

  • http://ADRESSE-DE-VOTRE-INSTANCE:8082 : la boutique de Cornucopia s'affiche, avec ses articles, ses images et son module d'abonnement (/abonnement/). Pas d'assistant d'installation : le site est transplanté, pas réinstallé. Entrez au tableau de bord (/wp-admin/) avec flora et cornucopia-2026.
  • http://ADRESSE-DE-VOTRE-INSTANCE:8083 : phpMyAdmin, connecté au service db. Entrez avec flora et potager-2026 (ou root et racine-potager-2026) et explorez la base cornucopia : wp_posts pour les articles, abonnements pour la première abonnée.
  • Publiez un court article : il servira de témoin à l'étape 04.
L'adresse dépend de votre instance, comme au laboratoire Docker : localhost sur votre poste, l'adresse IP de la machine virtuelle avec VirtualBox, l'adresse publique sur un VPS. Si le navigateur vous renvoie vers cornucopia.projet.autos (le vrai site), c'est que le repointage de l'étape 01 n'était pas dans l'export au premier up : down, sudo rm -rf ./database, corrigez l'export, puis up -d.
docker compose ps montre les trois services en marche, la boutique de Flora répond sur le port 8082 avec ses articles et phpMyAdmin sur le 8083.
03

Les clés secrètes : sortir les mots de passe de la partition

Secrets

Votre partition contient des mots de passe en clair : la rendre publiable en déplaçant les secrets dans un fichier .env qui, lui, ne se partage jamais.

Pour mieux comprendre

La partition est faite pour être versionnée, remise, partagée : c'est le capital de l'entreprise. Un mot de passe écrit en clair dans un fichier partagé est un mot de passe donné. Le fichier .env, posé à côté de la partition, garde les clés : Compose y lit les variables ${NOM} tout seul.

Démarche

.env - les secrets, à part
MYSQL_UTILISATEUR=flora
MYSQL_MOT_DE_PASSE=potager-2026
MYSQL_MOT_DE_PASSE_ROOT=racine-potager-2026

Puis, dans la partition, chaque secret devient une référence (dans le service db, et le mot de passe root aussi dans phpmyadmin) :

docker-compose.yml - extrait corrigé du service db
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_MOT_DE_PASSE_ROOT}
      MYSQL_DATABASE: cornucopia
      MYSQL_USER: ${MYSQL_UTILISATEUR}
      MYSQL_PASSWORD: ${MYSQL_MOT_DE_PASSE}
Règle du cours : jamais de vrai mot de passe dans un docker-compose.yml remis ou versionné. Le fichier .env ne se remet pas non plus : dans votre README, indiquez plutôt les variables attendues.
Après docker compose down puis up -d, le site fonctionne toujours, et votre partition ne contient plus un seul mot de passe : grep -i password docker-compose.yml ne montre que des ${...}.
04

La survie des données : pause, rangement, incendie

Survie

Prouver la nuance entre stop, down et l'effacement des répertoires de données : une pause, un rangement, un incendie volontaire. C'est la démonstration de persistance exigée dans l'évaluation.

Démarche

  1. Votre article témoin est en ligne (étape 02).
  2. La pause : sudo docker compose stop arrête les conteneurs sans les enlever (docker ps -a les montre en Exited), puis sudo docker compose start : tout revient tel quel.
  3. Le rangement : sudo docker compose down : les conteneurs et le réseau disparaissent (docker ps -a ne montre plus rien)... mais ls montre que ./fichiers-wordpress et ./database sont toujours là. Puis sudo docker compose up -d : tout renaît, et l'article témoin a survécu.
  4. L'incendie volontaire : sudo docker compose down, puis sudo rm -rf ./database, puis up -d : la base a brûlé... et le service db, trouvant ./database vide, rejoue l'import de la sauvegarde. Votre article témoin a disparu, mais la boutique et l'abonnement de Hazel sont revenus tels qu'au jour de la sauvegarde.
Terminal - la preuve en trois actes
$ sudo docker compose stop
# pause : conteneurs arretes mais conserves
$ sudo docker compose start
# reprise : tout revient tel quel
$ sudo docker compose down
# rangement : enleve conteneurs et reseau, PRESERVE ./fichiers-wordpress et ./database
$ sudo docker compose up -d
# l'article temoin a survecu
$ sudo docker compose down
$ sudo rm -rf ./database
# incendie volontaire : la base brule
$ sudo docker compose up -d
# la base renait de la sauvegarde : l'article temoin a disparu, l'abonnement de Hazel est la
Un rm -rf ne pardonne pas : vérifiez avec pwd que vous êtes bien dans ~/my_wordpress avant de le lancer, et recopiez le chemin sans improviser. Le sudo est nécessaire : MySQL écrit ses fichiers sous un autre utilisateur que le vôtre. Pour un incendie total, brûlez aussi ./fichiers-wordpress et redéballez le zip : sans ses fichiers, l'image wordpress installerait un site vierge.
Vous savez démontrer le cycle complet et expliquer, dans vos mots, la différence entre la pause, le rangement et l'incendie volontaire : c'est une question d'examen classique.
Pour les curieux : la surprise de docker compose down --volumes

Docker possède un deuxième mécanisme de persistance, les volumes, et une commande de nettoyage qui semble faite pour l'incendie... mais qui ne brûle rien du tout dans ce laboratoire. L'explication complète, la partition alternative et le défi qui va avec sont dans En savoir plus - Les volumes Docker.

Défis facultatifs

Défi A - Le bilan de santé

Ajoutez un healthcheck au service db et remplacez le simple depends_on par une condition service_healthy : WordPress n'essaiera plus de parler à une base encore endormie.

Défi B - La sauvegarde par phpMyAdmin

Exportez la base depuis phpMyAdmin, faites l'incendie volontaire, puis réimportez : votre article témoin peut-il renaître de la sauvegarde ?

Le fichier complet

Pour vérifier votre travail ou repartir d'un bon pied : docker-compose.yml, la partition complète telle qu'à la fin de l'étape 03 (secrets en .env, montages de la sauvegarde). Le fichier .env et les ajustements de l'étape 01 (wp-config.php, repointage de l'export) restent à faire par vous.