Guide complet Docker pour développeurs web : de l'initiation à la production

Docker a profondément changé la façon dont on déploie le web. Avant, le fameux « ça marche sur ma machine » était un running gag douloureux. Aujourd'hui, c'est devenu une exception. Docker 27 — la version stable au moment où j'écris — et Compose v2 ont rendu la conteneurisation accessible à n'importe quel développeur web.

Les concepts de base — image, conteneur, Dockerfile — sont simples. Une image est un modèle en lecture seule qui contient tout ce dont votre application a besoin. Un conteneur est une instance en cours d'exécution de cette image. Le Dockerfile est la recette pour construire l'image.

On construit une image une fois, on la partage via un registre (Docker Hub, GitHub Container Registry), et on lance autant de conteneurs que nécessaire. Chaque conteneur est éphémère, reproductible et isolé des autres processus. La magie opère quand on réalise qu'on peut reproduire exactement le même environnement en local, sur le serveur de staging et en production.

Premiers pas : un Dockerfile pour Node.js

Prenons un exemple concret. Si vous avez suivi notre guide sur les API REST FastAPI, vous pouvez conteneuriser le backend de la même manière — ici avec Node.js :

FROM node:20-alpine AS builder

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .

EXPOSE 3000

CMD ["node", "server.js"]

L'astuce qu'on apprend avec l'expérience : copier d'abord package.json et installer les dépendances avant de copier le reste du code. Docker met en cache chaque couche du Dockerfile. Tant que package.json ne change pas, la couche d'installation est réutilisée — le build passe de 30 secondes à 2.

Docker Compose : le vrai game-changer

Une application web moderne n'est jamais un service unique. Vous avez une base de données, un cache, un serveur Nginx. Docker Compose orchestre tout ça dans un fichier YAML :

version: "3.9"

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/app
    depends_on:
      - db

  db:
    image: postgres:16-alpine
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: app

volumes:
  pgdata:

docker compose up -d et tout tourne. L'astuce : le fichier se versionne dans Git. Chaque membre de l'équipe a le même environnement, qu'il soit sur macOS, Windows ou Linux. Finie la chasse aux dépendances manquantes.

Ce que j'aurais aimé savoir plus tôt sur la production

Un Dockerfile qui marche en dev ne passe pas forcément en prod. Quelques règles :

Images multi-étapes. Une étape de build avec TypeScript, tests, dépendances de dev. Une étape finale avec seulement les artefacts compilés et les dépendances d'exécution. L'image passe de 1.2 Go à 180 Mo. Le déploiement est plus rapide, la surface d'attaque réduite.

Exécution non-root. Docker exécute en root par défaut. En production, c'est une mauvaise pratique :

RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

Healthchecks. Sans healthcheck, Docker ne sait pas si votre app tourne vraiment ou si elle est plantée silencieusement :

HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost:3000/health || exit 1

.dockerignore. Si votre build envoie node_modules dans le contexte, vous perdez 30 secondes et vous risquez de fuiter des infos sensibles. Un fichier de 3 lignes règle le problème.

Volumes : ce qui persiste, ce qui disparaît

Un conteneur redémarre, les données s'envolent. C'est le principe. Pour les bases de données, les uploads, les logs, on monte des volumes (recommandé, géré par Docker) ou des bind mounts (utile en dev pour le hot reload). La différence est subtile mais cruciale : un volume survit à la suppression du conteneur, un bind mount expose un dossier de l'hôte.

Au final, Docker n'est pas le sujet le plus glamour du développement web. Mais c'est celui qui vous sauve un vendredi soir à 18h quand le serveur de staging refuse de reproduire le bug que vous voyez en local. Maîtrisez-le, et vous gagnerez des heures — et votre santé mentale.