Docker Compose et Infrastructure as Code¶
Jusqu’ici, chaque conteneur était lancé manuellement avec docker run. Cette approche fonctionne pour tester ou découvrir, mais elle pose problème en production : les commandes ne sont pas sauvegardées, l’ordre de démarrage doit être respecté manuellement, et reproduire l’environnement sur une autre machine demande de retaper chaque commande en espérant n’en oublier aucune.
Docker Compose résout ces problèmes en décrivant toute une pile applicative dans un fichier texte docker-compose.yml : services, réseaux, volumes, variables d’environnement, ordre de démarrage. Une seule commande (docker-compose up) suffit ensuite pour déployer l’ensemble, quelle que soit la machine.
Ce principe — décrire une infrastructure dans des fichiers texte plutôt que de l’assembler à la main — s’appelle l’Infrastructure as Code (IaC). Il est au cœur des pratiques modernes d’administration système et DevOps.
Les bénéfices concrets de l’IaC :
Reproductibilité : le même fichier produit le même résultat sur n’importe quel poste ou serveur
Versionnement : le fichier
docker-compose.ymlest versionné dans Git comme n’importe quel code source — on voit qui a modifié quoi, quand, et pourquoiAutomatisation : un pipeline CI/CD peut déployer ou mettre à jour la pile sans intervention humaine
Documentation implicite : le fichier est une description lisible de l’architecture, plus fiable qu’un wiki qui se désynchronise
Réversibilité : revenir à une version précédente consiste à rétablir un fichier dans Git et relancer
docker-compose up
Docker Compose est une première étape vers des outils d’IaC plus avancés comme Ansible (configuration de machines), Terraform (provisionnement d’infrastructure cloud) ou Kubernetes (orchestration à grande échelle). Le principe reste le même : l’infrastructure se décrit, ne se clique pas.
Structure d’un fichier docker-compose.yml¶
Un fichier docker-compose.yml est organisé en quatre sections principales, toutes au même niveau de la hiérarchie YAML.
services: # les conteneurs de la pile
volumes: # les volumes nommés persistants
networks: # les réseaux virtuels
configs: # fichiers de configuration injectés (Swarm uniquement)Balises pouvant être présentes dans docker-compose.yaml
Le format YAML est sensible à l’indentation : utiliser exclusivement des espaces (jamais de tabulations), et respecter scrupuleusement l’alignement.
La section services est la seule obligatoire. Chaque service décrit un conteneur :
services:
nom-du-service: # nom utilisé comme nom DNS sur le réseau
image: nginx:alpine # image Docker à utiliser
container_name: web # nom du conteneur (optionnel)
ports:
- "8080:80" # port-hote:port-conteneur
volumes:
- ./html:/usr/share/nginx/html:ro # bind mount
- data-app:/var/lib/mysql # volume nommé
networks:
- reseau-frontend # réseaux auxquels se connecter
environment:
MYSQL_DATABASE: wordpress # variable d environnement inline
env_file:
- .env # variables chargées depuis un fichier
depends_on:
- db # attend que db soit démarré avant
restart: unless-stopped # politique de redémarrageExemple de docker-compose.yaml
La section volumes déclare les volumes nommés. Un volume déclaré ici est géré par Docker et persiste entre redémarrages :
volumes:
data-app: # créé automatiquement au premier docker-compose up
logs-apache: # peut être préfixé du nom du projetConfiguration des volumes
La section networks déclare les réseaux. Sans déclaration, Compose crée un réseau par défaut. Avec des réseaux explicites, on contrôle l’isolation :
networks:
reseau-frontend:
driver: bridge # driver par défaut, peut être omis
reseau-backend:
driver: bridgeConfiguration des réseaux
Commandes essentielles :
| Commande | Action |
|---|---|
docker-compose up -d | Démarrer la pile en mode détaché |
docker-compose down | Arrêter et supprimer les conteneurs et réseaux |
docker-compose down -v | Idem + supprimer les volumes |
docker-compose ps | État des services |
docker-compose logs -f NOM | Logs en temps réel d’un service |
docker-compose exec NOM CMD | Exécuter une commande dans un service actif |
docker-compose pull | Mettre à jour les images |
docker-compose restart NOM | Redémarrer un service sans toucher aux autres |
Limiter les ressources CPU et mémoire
Par défaut, un conteneur peut consommer l’intégralité des ressources de l’hôte. En production, il est indispensable de poser des limites pour éviter qu’un service défaillant ne pénalise les autres. C’est le rôle des Cgroups (Control Groups) du noyau Linux, que Docker expose via la clé deploy.resources.
services:
wordpress:
image: wordpress:latest
deploy:
resources:
limits:
cpus: "0.50" # au maximum 50 % d un coeur CPU
memory: 512M # au maximum 512 Mo de RAM
reservations:
cpus: "0.25" # garantis : 25 % d un coeur reserve
memory: 256M # garantis : 256 Mo de RAM reserve
db:
image: mariadb:10.11
deploy:
resources:
limits:
cpus: "1.00" # au maximum 1 coeur complet
memory: 1G # au maximum 1 Go de RAM
reservations:
memory: 512MParamétrage des ressources
| Clé | Valeur | Effet |
|---|---|---|
limits.cpus | "0.50" | Le conteneur ne peut pas dépasser 50 % d’un cœur |
limits.memory | 512M, 1G | Le conteneur est tué (OOMKill) s’il dépasse cette limite |
reservations.cpus | "0.25" | Docker garantit cette capacité même sous charge |
reservations.memory | 256M | Mémoire réservée sur l’hôte au démarrage |
Docker Compose progressif¶
Ces exercices reprennent les architectures construites dans les pages précédentes et les traduisent en fichiers docker-compose.yml. L’objectif est de passer du pilotage manuel par docker run à un pilotage déclaratif reproductible.
01. Compose — WordPress + MariaDB sur un réseau personnalisé¶
Structure du répertoire :
compose-step1/
.env
docker-compose.ymlLes paramètres de configuration de la base de données sont dans un fichier .env.
MYSQL_ROOT_PASSWORD=rootpass
MYSQL_DATABASE=wordpress
MYSQL_USER=wp
MYSQL_PASSWORD=wppass
WORDPRESS_DB_HOST=db
WORDPRESS_DB_USER=wp
WORDPRESS_DB_PASSWORD=wppass
WORDPRESS_DB_NAME=wordpressConfiguration des volumes
Fichier docker-compose.yml :
services:
db:
image: mariadb:10.11
env_file:
- .env
networks:
- wp-net
restart: unless-stopped
wordpress:
image: wordpress:latest
env_file:
- .env
ports:
- "8080:80"
networks:
- wp-net
depends_on:
- db
restart: unless-stopped
networks:
wp-net:
driver: bridgeParamétrage des services
Commandes :
mkdir compose-step1 && cd compose-step1
# Creer .env et docker-compose.yml
docker-compose up -d
docker-compose ps
curl http://localhost:8080 | head -5
docker-compose exec wordpress ping -c 2 db
docker-compose down
cd .. && rm -rf compose-step1Avantage par rapport à docker run :
docker run | docker-compose |
|---|---|
| 2 commandes séparées | docker-compose up -d |
| Ordre manuel | depends_on |
| Réseau créé manuellement | Déclaré dans le fichier |
| Nettoyage en 4 commandes | docker-compose down |
02. Compose — WordPress + MariaDB avec volumes séparés et deux réseaux¶
Fichier docker-compose.yml :
services:
db:
image: mariadb:10.11
env_file:
- .env
volumes:
- wp-data:/var/lib/mysql # donnees persistantes
networks:
- wp-backend # backend uniquement : db non accessible depuis frontend
restart: unless-stopped
wordpress:
image: wordpress:latest
env_file:
- .env
volumes:
- wp-logs:/var/log/apache2 # logs Apache
ports:
- "8080:80"
networks:
- wp-frontend # reseau web
- wp-backend # reseau base de donnees
depends_on:
- db
restart: unless-stopped
volumes:
wp-data: # donnees MariaDB
wp-logs: # logs Apache
networks:
wp-frontend:
driver: bridge
wp-backend:
driver: bridgeVérifier l’isolation réseau :
# db inaccessible depuis wp-frontend
docker-compose exec wordpress ping -c 2 db # succes : wordpress est sur les deux reseaux
docker run --rm \
--network compose-step2_wp-frontend \
alpine ping -c 2 db # echec : pas de route vers dbLire les logs depuis le volume :
docker run --rm \
-v compose-step2_wp-logs:/logs \
alpine tail -5 /logs/access.logRedémarrage sans perte de données :
docker-compose down # stoppe et supprime les conteneurs, conserve les volumes
docker-compose up -d # les donnees MariaDB sont intactes
docker-compose down -v # supprime aussi les volumes03. Compose — Architecture complète avec Nginx en load balancer¶
Structure du répertoire :
compose-final/
.env
nginx.conf
docker-compose.ymlFichier nginx.conf : (identique à l’exercice final de la page précédente)
Fichier docker-compose.yml :
services:
db:
image: mariadb:10.11
env_file:
- .env
volumes:
- wp-data:/var/lib/mysql
networks:
- wp-backend
restart: unless-stopped
wordpress:
image: wordpress:latest
env_file:
- .env
volumes:
- wp-logs:/var/log/apache2
networks:
- wp-frontend
- wp-backend
depends_on:
- db
# pas de ports : seul nginx est expose
restart: unless-stopped
# wordpress2: # decommenter pour le load balancing
# image: wordpress:latest
# env_file:
# - .env
# volumes:
# - wp-logs:/var/log/apache2
# networks:
# - wp-frontend
# - wp-backend
# depends_on:
# - db
# restart: unless-stopped
nginx:
image: nginx:alpine
ports:
- "8080:80" # seul point d entree
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro # configuration en bind mount
networks:
- wp-frontend
depends_on:
- wordpress
restart: unless-stopped
volumes:
wp-data:
wp-logs:
networks:
wp-frontend:
driver: bridge
wp-backend:
driver: bridgeCommandes :
mkdir compose-final && cd compose-final
# Creer .env, nginx.conf et docker-compose.yml
docker-compose up -d
docker-compose ps
curl http://localhost:8080 | head -5
docker logs compose-final-nginx-1 # logs Nginx
docker-compose down -v
cd .. && rm -rf compose-finalPour le load balancing (step 4) :
# Decommenter wordpress2 dans docker-compose.yml
# Mettre a jour nginx.conf : ajouter server wordpress2:80
docker-compose up -d --scale wordpress=1 # wordpress2 demarre
docker-compose exec nginx nginx -s reload # recharger sans interruptionComparaison des étapes du fil directeur :
| Étape | Architecture | Nouveauté |
|---|---|---|
| EX-01 Compose | WordPress + MariaDB, 1 réseau | Translate docker run → Compose |
| EX-02 Compose | + volumes séparés, 2 réseaux | Persistance et isolation |
| EX-03 Compose | + Nginx LB, N WordPress | Reverse proxy, load balancing |
| EX-12 (suivant) | Compose complet avec variables | Administration et cycle de vie |
04. Docker Compose : application multi-conteneurs¶
Résultat attendu de docker-compose ps :
NAME IMAGE SERVICE STATUS PORTS
compose-db mariadb:10.11 db Up 1 minute 3306/tcp
compose-web nginx:alpine web Up 1 minute 0.0.0.0:8080->80/tcpRésultat attendu de SHOW DATABASES; :
+--------------------+
| Database |
+--------------------+
| appdb |
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+| Section | Rôle |
|---|---|
services | Définit chaque conteneur |
volumes | Volumes nommés partagés |
networks | Réseaux partagés entre services |
depends_on | Ordonne le démarrage |
env_file | Charge les variables depuis .env |
restart | Politique de redémarrage |
05. Administration en production¶
Résultat attendu de docker inspect sur la politique de redémarrage :
"RestartPolicy": {
"Name": "unless-stopped",
"MaximumRetryCount": 0
}Politiques de redémarrage disponibles :
| Politique | Comportement |
|---|---|
no (défaut) | Pas de redémarrage automatique |
always | Redémarre toujours, y compris au boot de l’hôte |
unless-stopped | Redémarre sauf si arrêté manuellement |
on-failure[:N] | Redémarre sur erreur, jusqu’à N fois |
Résultat attendu de docker system df :
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 5 2 312MB 180MB (57%)
Containers 1 1 0B 0B
Local Volumes 1 1 45MB 0B
Build Cache 0 0 0B 0B06. Swarm : clustering et orchestration¶
Résultat attendu de docker node ls :
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
abc123def456 * monhote Ready Active LeaderRésultat attendu après simulation de panne (étape 4) :
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE
aaaa svc-web.1 nginx:alpine monhote Running Running 2 min ago
bbbb svc-web.2 nginx:alpine monhote Running Running 2 min ago
cccc svc-web.3 nginx:alpine monhote Shutdown Failed 10 sec ago
dddd svc-web.3 nginx:alpine monhote Running Running 5 sec agoSwarm a détecté la disparition du réplica et en a automatiquement créé un nouveau.
Section deploy dans le Compose pour Swarm :
| Clé | Rôle |
|---|---|
replicas | Nombre d’instances du service |
restart_policy | Comportement en cas d’échec |
update_config | Stratégie de mise à jour rolling |
placement.constraints | Contraintes de placement sur les nœuds |
| Compose | Swarm | |
|---|---|---|
| Périmètre | 1 hôte | Multi-hôtes |
| Réplication | Non | Oui |
| Load balancing | Non | Intégré |
| Haute disponibilité | Non | Oui |
| Réseau inter-nœuds | bridge | overlay chiffré |
Pour des architectures plus complexes (autoscaling, rolling updates avancés, RBAC), considérer Kubernetes. Swarm reste pertinent pour des équipes souhaitant une orchestration simple avec les outils Docker existants.