Docker pour développeurs : images, conteneurs et Compose

DevOps2026-10-12TryQuickToolBox

Vous avez cloné un projet, suivi les instructions d'installation, et vous vous êtes heurté à un mur : une bibliothèque système manquante, une base de données qui refuse de démarrer, ou une version de Node incompatible. Docker existe pour éliminer ce type de problème. Au lieu d'installer des services directement sur votre machine, vous les décrivez une fois et les exécutez dans des conteneurs isolés qui se comportent de la même manière partout.

Ce guide explique les trois idées dont vous avez réellement besoin : les images, les conteneurs et Compose. Il reste pratique, avec des commandes que vous pouvez exécuter au fil de votre lecture.

Images et conteneurs : le modèle mental

Une image est un modèle en lecture seule. Elle contient un instantané de système de fichiers ainsi que des métadonnées comme la commande par défaut et les ports exposés. Un conteneur est une instance en cours d'exécution (ou arrêtée) de cette image, avec une fine couche inscriptible par-dessus.

Si vous venez de la programmation orientée objet, l'analogie est proche : une image est une classe, un conteneur est un objet. Vous pouvez démarrer plusieurs conteneurs à partir d'une seule image, et les modifications à l'intérieur d'un conteneur ne modifient pas l'image.

ConceptCe que c'estCommande typique
ImageModèle immuabledocker build, docker pull
ConteneurInstance en exécutiondocker run, docker ps
VolumeStockage persistantdocker volume create
ComposeDéfinition multi-conteneursdocker compose up

Votre première image avec un Dockerfile

Un Dockerfile est une recette. Chaque instruction crée une couche, et Docker met en cache les couches pour que les reconstructions soient rapides quand rien n'a changé. Voici un petit exemple Node.js :

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

Deux habitudes comptent ici. Premièrement, copiez les manifestes de dépendances avant le reste du code source pour que la couche npm ci soit mise en cache lorsque seul le code applicatif change. Deuxièmement, préférez une image de base légère comme alpine pour réduire la taille et la surface d'attaque.

Construisez et exécutez-la :

docker build -t myapp:1.0 .
docker run --rm -p 3000:3000 myapp:1.0

L'option -p 3000:3000 mappe le port 3000 de l'hôte vers le port 3000 du conteneur. --rm supprime le conteneur lorsqu'il s'arrête, ce qui garde votre machine propre pendant le développement.

Les commandes de conteneur au quotidien

Elles couvrent la plupart du travail quotidien :

Lorsqu'un conteneur s'arrête immédiatement, lisez d'abord les logs. Les causes les plus courantes sont un CMD incorrect, une variable d'environnement manquante, ou le processus qui se lie à 127.0.0.1 au lieu de 0.0.0.0 à l'intérieur du conteneur.

Pourquoi Compose existe

Une application réelle nécessite généralement plus d'un processus : une API, une base de données, peut-être un cache. Exécuter trois commandes docker run avec de longues listes d'options est source d'erreurs. Docker Compose vous permet de déclarer tous les services dans un seul fichier YAML et de les démarrer ensemble.

services:
  api:
    build: .
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://app:secret@db:5432/app
    depends_on:
      - db
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: app
    volumes:
      - db_data:/var/lib/postgresql/data
volumes:
  db_data:

Remarquez que l'API se connecte à db, pas à localhost. Compose crée un réseau privé où chaque service est joignable par son nom de service. C'est la source de confusion la plus courante pour les débutants.

Démarrez tout avec docker compose up, ou docker compose up -d pour exécuter en arrière-plan. Reconstruisez après des modifications de code avec docker compose up --build. Arrêtez avec docker compose down, et ajoutez -v si vous voulez aussi supprimer les volumes nommés.

Volumes, montages de liaison et rechargement à chaud

Les conteneurs sont éphémères ; les données qu'ils contiennent disparaissent lorsqu'ils sont supprimés. Deux mécanismes résolvent ce problème :

  1. Volumes nommés — gérés par Docker, idéaux pour les fichiers de base de données. Ils persistent à travers les redémarrages de conteneurs et sont déclarés dans la section volumes:.
  2. Montages de liaison (bind mounts) — mappent un répertoire de l'hôte dans le conteneur, idéaux pour le code source pendant le développement.
services:
  api:
    build: .
    volumes:
      - ./src:/app/src

Avec un montage de liaison, modifier des fichiers sur votre hôte se reflète à l'intérieur du conteneur. Combinez cela avec un observateur de fichiers (nodemon, uvicorn --reload, air) et vous obtenez un rechargement à chaud sans reconstruire l'image.

Un flux de travail de développement pratique

  1. Écrivez un Dockerfile pour votre application et gardez-le minimal.
  2. Ajoutez un docker-compose.yml avec l'application et ses dépendances.
  3. Utilisez des montages de liaison pour le code source et des volumes nommés pour les données.
  4. Gardez les secrets hors du fichier ; utilisez un fichier .env et référencez les variables avec ${VAR}.
  5. Ajoutez un .dockerignore contenant node_modules, .git et les artefacts de build pour accélérer les constructions.
  6. Lancez docker compose up --build et itérez.

Si votre service produit des logs que vous devez inspecter plus tard, rappelez-vous que les logs de conteneur ne sont que du texte. Les outils qui analysent les logs serveur, comme un analyseur de logs nginx, s'associent bien avec les conteneurs car vous pouvez rediriger ou copier les logs sans rien installer sur l'hôte.

Pièges courants

FAQ

Quelle est la différence entre une image et un conteneur ?

Une image est un modèle immuable contenant un système de fichiers et des métadonnées. Un conteneur est une instance en cours d'exécution de cette image avec une couche inscriptible ajoutée. Vous pouvez démarrer plusieurs conteneurs à partir d'une seule image.

Ai-je besoin de Docker Compose pour un seul service ?

Non. Une seule commande docker run suffit pour un conteneur. Compose devient utile lorsque vous avez plusieurs services, des réseaux partagés, ou des variables d'environnement que vous voulez déclarer au même endroit.

Comment les conteneurs communiquent-ils entre eux ?

Compose place tous les services sur un réseau partagé où chaque service est joignable par son nom de service. Utilisez ce nom comme nom d'hôte, par exemple db:5432, au lieu de localhost.

Docker récompense un petit investissement initial. Une fois que les images, les conteneurs et Compose font tilt, intégrer un collègue ou changer de machine cesse d'être un rituel d'installation et devient une seule commande.