09 - Docker Compose, les bases
Ce que tu vas apprendre
- Ce qu'est Docker Compose et pourquoi tu en as besoin
- Les directives principales : services, build, image, ports, depends_on, command
- Les commandes du quotidien : up, down, logs, ps
- La différence entre compose.yaml et docker-compose.yml
- Un vrai exemple avec app + base de donnees + redis
Prerequisites
- Avoir suivi la partie sur les images de base
- Docker Desktop installe avec le plugin Compose v2
Le jour ou tu lances ta première commande docker run avec 15 flags, tu te dis que ca ne va pas tenir. Et tu as raison. Docker Compose existe pour ca : decrire toute ton infrastructure locale dans un fichier YAML, et la démarrer en une commande.
Pourquoi Compose existe
Sur paltemps.fr, j'ai trois services qui tournent ensemble : un serveur Node, une base PostgreSQL et un cache Redis. Sans Compose, je devrais lancer trois docker run avec les bons réseaux, les bons volumes, les bonnes variables d'environnement. Et recommencer a chaque redemarrage.
Compose transforme ces commandes en un fichier declaratif. Tu decris ce que tu veux, Docker s'occupe du reste.
Le fichier compose.yaml
Docker a change le nom du fichier plusieurs fois. Aujourd'hui, la convention officielle c'est compose.yaml. Les anciens noms docker-compose.yml et docker-compose.yaml fonctionnent toujours, mais Compose v2 cherche compose.yaml en priorité.
Un fichier minimal :
yamlservices:
app:
build: .
ports:
- "3000:3000"
C'est tout. Un service nomme app, construit depuis le Dockerfile du répertoire courant, avec le port 3000 expose.
Les directives de base
build vs image
Tu as deux facons de spécifier d'ou vient ton conteneur :
yamlservices:
# Construire depuis un Dockerfile local
app:
build:
context: .
dockerfile: Dockerfile
# Utiliser une image existante
db:
image: postgres:16-alpine
build construit l'image. image la telecharge. Tu ne peux pas utiliser les deux sur le meme service (sauf si tu veux nommer l'image construite).
ports
Le mapping de ports suit le format host:container :
yamlservices:
app:
ports:
- "3000:3000" # host 3000 -> container 3000
- "9229:9229" # debugger Node
depends_on
depends_on dit a Compose de démarrer les services dans le bon ordre :
yamlservices:
app:
depends_on:
- db
- redis
db:
image: postgres:16-alpine
redis:
image: redis:7-alpine
Attention : depends_on attend que le conteneur démarré, pas qu'il soit pret. PostgreSQL peut mettre quelques secondes a accepter les connexions apres le démarrage du conteneur. Pour ca, tu peux ajouter une condition :
yamlservices:
app:
depends_on:
db:
condition: service_healthy
db:
image: postgres:16-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
command
command remplace le CMD du Dockerfile :
yamlservices:
app:
build: .
command: node --watch src/index.js
Pratique pour changer le comportement en dev sans modifier le Dockerfile.
Un vrai exemple : app + db + redis
Voici un compose.yaml complet et realiste :
yamlservices:
app:
build: .
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://postgres:secret@db:5432/myapp
REDIS_URL: redis://redis:6379
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: secret
POSTGRES_DB: myapp
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
volumes:
- redisdata:/data
volumes:
pgdata:
redisdata:
Remarque le DATABASE_URL : le hostname db correspond au nom du service. Compose créé un réseau interne et chaque service est accessible par son nom. On verra ca en détail dans l'article sur le networking.
Les commandes du quotidien
Démarrer les services
bashdocker compose up
Ca construit les images si besoin et démarré tout. Ajoute -d pour le mode detache (en arriere-plan) :
bashdocker compose up -d
Et --build pour forcer la reconstruction :
bashdocker compose up -d --build
Voir les logs
bashdocker compose logs # tous les services
docker compose logs app # un seul service
docker compose logs -f app # suivre en temps reel
Voir l'état des services
bashdocker compose ps
Ca affiche chaque service, son état, et les ports mappes.
Arreter tout
bashdocker compose down
Les conteneurs sont supprimes, mais les volumes sont conserves. Pour tout supprimer, y compris les volumes :
bashdocker compose down -v
J'utilise down -v rarement. Perdre les donnees de la base en dev, c'est souvent penible.
Redemarrer un service spécifique
bashdocker compose restart app
L'erreur classique du débutant
Je la vois tout le temps : utiliser docker-compose (avec un tiret) au lieu de docker compose (avec un espace). L'ancien binaire docker-compose est deprecated depuis Compose v2. La bonne commande, c'est docker compose, intégré directement dans la CLI Docker.
Si docker compose version ne renvoie rien, c'est que le plugin n'est pas installe. Avec Docker Desktop, il l'est par défaut.
Résumé
compose.yamldecrit tes services, leurs images, ports, dépendances et volumesbuildconstruit depuis un Dockerfile,imageutilise une image existantedepends_onaveccondition: service_healthyattend que le service soit vraiment pretdocker compose up -d --buildest la commande que tu vas taper 50 fois par jour- Les noms de services servent de hostnames dans le réseau interne
Navigation : Precedent : 08 - Images de base | Suivant : 10 - Compose avance
Sources
- Docker Compose documentation par Docker
- Compose file référencé par Docker
- Awesome Compose - sample apps par Docker