infra / docker-compose
Premier docker-compose.yml : services, image, ports
Explication
Ce que vous allez apprendre
- Déclarer un service Compose avec une image, des ports et des variables d'environnement
- Comprendre le mapping de ports
host:containeret pourquoi les deux nombres peuvent différer - Distinguer
docker compose up(service durable) dedocker compose run(commande ponctuelle) - Vérifier la configuration résolue avant de démarrer avec
docker compose config - Éviter le piège classique des ports mal quotés dans un fichier YAML
Dans quel contexte ?
Un développeur reprend le projet boutique-api : il doit exposer l'API sur le port 3000 de sa machine, la base PostgreSQL sur 5432 et un cache Redis sur 6379, sans qu'aucun de ces ports n'entre en conflit avec d'autres projets déjà lancés sur son poste. Cette leçon construit exactement ce type de fichier, service par service.
Repartir de zéro : qu'est-ce qu'un service ?
D'abord, il faut comprendre ce qu'est un "service" dans le vocabulaire de Compose. C'est simplement l'équivalent d'une commande docker run : une image à utiliser, un point d'entrée, des ports, des variables. La différence, c'est que cette configuration est écrite une fois dans un fichier, au lieu d'être retapée à chaque fois dans le terminal.
Le problème avec docker run tout seul
Avec docker run, la configuration existe seulement dans l'historique de ton terminal. Difficile à partager avec un collègue, difficile à relire, impossible à versionner proprement dans Git. Il fallait un moyen de figer cette configuration quelque part.
La solution : décrire plutôt qu'exécuter
C'est là qu'intervient l'idée déclarative de Compose. Au lieu d'exécuter des étapes, on décrit un état voulu : quelle image, quel port exposé, quelles variables. Compose se charge ensuite lui-même d'atteindre cet état, exactement comme un fichier de configuration d'infrastructure classique.
Zoom sur les ports, une notion à bien comprendre
Une fois que le service est déclaré, il reste souvent une question : comment y accéder depuis ta machine ? C'est le rôle du mapping "host:container". Par exemple 3000:3000 relie le port 3000 de ta machine au port 3000 à l'intérieur du conteneur.
Les deux nombres peuvent être différents
Il faut bien réaliser que ces deux nombres n'ont pas besoin d'être identiques. On pourrait très bien écrire 8080:3000 : ta machine écoute alors sur le port 8080, mais redirige vers le port 3000 du conteneur. C'est utile quand plusieurs services internes utilisent le même port par défaut.
| Clé du service | Rôle | Exemple |
|---|---|---|
image | Image à tirer depuis un registre | postgres:16 |
ports | Mapping host:container | "3000:3000" |
environment | Variables injectées dans le conteneur | NODE_ENV: production |
working_dir | Dossier de travail dans le conteneur | /app |
command | Commande exécutée au démarrage | ["node", "server.js"] |
Piège fréquent
Écrire ports: - 8080:80 sans guillemets peut, selon le parseur YAML, être interprété comme une valeur numérique inattendue plutôt qu'un texte "host:container". Prends le réflexe systématique de toujours entourer un mapping de ports par des guillemets doubles, comme "8080:80".
Une commande pour vérifier avant de se tromper
Une fois ton fichier écrit, il reste une étape importante avant de foncer : vérifier ce que Compose va réellement faire. La commande docker compose config affiche la configuration finale résolue, avec toutes les valeurs interpolées — un bon réflexe avant chaque déploiement.
Les pièges à connaître
Premier piège classique : oublier les guillemets autour des ports. Écrire 8080:80 sans guillemets peut être mal interprété par le parseur YAML, qui le lit parfois comme un nombre au lieu d'un texte. Deuxième piège : confondre up, qui démarre un service durable, avec run, qui exécute une commande ponctuelle et jetable, hors de la stack normale.
Maintenant que tu sais déclarer un service avec une image existante, la leçon suivante va plus loin : comment construire sa propre image à partir de son code, au lieu d'utiliser uniquement des images toutes faites.
Commandes & code
Premier docker-compose.yml
Un fichier Compose déclare une liste de services, chacun étant l'équivalent d'un docker run.
services:
api:
image: node:20-alpine
working_dir: /app
command: ["node", "server.js"]
ports:
- "3000:3000" # host:container
environment:
NODE_ENV: production
db:
image: postgres:16
ports:
- "5432:5432"
environment:
POSTGRES_PASSWORD: changeme
POSTGRES_DB: app_db
cache:
image: redis:7-alpine
ports:
- "6379:6379"# Démarrer un seul service et ses dépendances
docker compose up -d db
# Exécuter une commande ponctuelle dans un conteneur du projet
docker compose exec db psql -U postgres -d app_db
# Lancer un conteneur "jetable" (pas dans la stack persistante)
docker compose run --rm api node -v
# Voir la configuration résolue (interpolation, defaults, merges)
docker compose config# Convention "short syntax" vs "long syntax" pour les ports
services:
web:
ports:
- "8080:80" # short syntax
- target: 80 # long syntax (plus explicite)
published: 8080
protocol: tcp
mode: hostRésumé
- Chaque clé sous
services:est un conteneur nommé. ports: "host:container"publie un port sur la machine hôte.docker compose configvalide et affiche le YAML final résolu.run --rmsert aux commandes ponctuelles,up -daux services durables.
Exercices pratiques
Mission : republier boutique-api sur un port libre sans casser le déploiement
Objectif : Corriger un fichier Compose mal quoté et distinguer un service durable d'une commande ponctuelle.
Contexte
Sur le projet boutique-api, un développeur a écrit ports: - 8080:80 sans guillemets dans son docker-compose.yml, et un collègue affirme avoir "démarré l'API" avec docker compose run --rm api node -v, avant de s'étonner que plus rien ne tourne quelques secondes plus tard. Le port 3000, déjà utilisé par un autre projet sur sa machine, doit en plus être remplacé par le port hôte 8080.
Corrige ces problèmes et explique-les, sans copier une réponse toute faite.