Developer Tools

Docker pour les développeurs : conteneurs, Compose et workflows concrets

Un guide pratique sur les concepts Docker, les bonnes pratiques de Dockerfile et l'utilisation de Docker Compose pour faire tourner des environnements de développement multi-services.

9 min de lecture

Salle de serveurs avec éclairage bleu

« Ça marche sur ma machine » — cette phrase a causé des milliers d'échecs de déploiement. Docker résout ce problème en empaquetant votre application et toutes ses dépendances dans un conteneur — un environnement isolé et reproductible qui s'exécute de façon identique partout, de votre ordinateur portable à la production.

Conteneurs vs. machines virtuelles

Machine Virtuelle Conteneur
Isolation OS complet Niveau processus
Temps de démarrage Minutes Secondes
Taille Go Mo
Surcharge Élevée (hyperviseur) Quasi nulle
Cas d'usage Isolation OS complète Packaging d'app

Les conteneurs partagent le noyau de l'hôte mais isolent le système de fichiers, les processus et le réseau. C'est ce qui les rend si légers.

Concepts fondamentaux de Docker

Image — Un modèle en lecture seule pour un conteneur. Considérez-la comme la définition d'une classe.

Conteneur — Une instance en cours d'exécution d'une image. Considérez-le comme un objet créé à partir de la classe.

Registry — Un système de stockage et de distribution d'images. Docker Hub est le registre public par défaut ; GitHub Container Registry et AWS ECR sont des alternatives courantes.

Volume — Un stockage persistant qui survit aux redémarrages du conteneur. Les données écrites à l'intérieur d'un conteneur sans volume sont perdues à l'arrêt de celui-ci.

Écrire un bon Dockerfile

# Utilisez une version précise — jamais "latest" en production
FROM node:20-alpine

# Définir le répertoire de travail
WORKDIR /app

# Copier les fichiers de dépendances en premier (exploite le cache des couches)
COPY package.json package-lock.json ./
RUN npm ci --only=production

# Copier le code de l'application
COPY . .

# Construire l'application
RUN npm run build

# Exécuter en tant qu'utilisateur non-root pour la sécurité
USER node

# Documenter le port (ne le publie pas)
EXPOSE 3000

# Utiliser la forme exec pour une gestion correcte des signaux
CMD ["node", "server.js"]

Cache des couches : la clé de builds rapides

Chaque instruction dans un Dockerfile crée une couche. Docker met les couches en cache — si rien n'a changé dans une couche ou ses prédécesseurs, Docker réutilise le cache.

Copiez les fichiers de dépendances avant le code de l'application. Les dépendances changent bien moins souvent que votre code. Si vous copiez tout d'un coup, une modification d'une seule ligne dans index.js invalide le cache d'installation des dépendances et force un npm install complet.

Builds multi-étapes

Utilisez les builds multi-étapes pour garder les images de production légères :

# Étape 1 : Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Étape 2 : Production (sans dépendances de dev, sans sources)
FROM node:20-alpine AS runner
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
USER node
CMD ["node", "dist/server.js"]

L'image finale ne contient que le résultat compilé — pas votre code source, vos fichiers de test ni vos dépendances de développement.

Docker Compose pour le développement local

Docker Compose orchestre les applications multi-conteneurs. Un seul fichier docker-compose.yml définit l'ensemble de votre stack locale :

version: "3.9"

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

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: myapp
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user"]
      interval: 5s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

volumes:
  postgres_data:

Générez la structure de votre stack avec notre Docker Compose Generator — choisissez vos services et obtenez un docker-compose.yml prêt pour la production en quelques secondes.

Commandes Compose essentielles

# Démarrer tous les services en arrière-plan
docker compose up -d

# Afficher les logs (mode suivi)
docker compose logs -f app

# Exécuter une commande dans un conteneur en cours d'exécution
docker compose exec app sh

# Arrêter et supprimer les conteneurs (conserve les volumes)
docker compose down

# Arrêter et supprimer les conteneurs ET les volumes
docker compose down -v

# Reconstruire les images après des modifications du Dockerfile
docker compose up -d --build

Variables d'environnement et secrets

Ne codez jamais en dur des identifiants dans votre Dockerfile ou votre fichier Compose. Utilisez un fichier .env :

# .env (à ajouter dans .gitignore !)
DATABASE_URL=postgresql://user:pass@db:5432/myapp
REDIS_URL=redis://redis:6379
JWT_SECRET=your-super-secret-key

Compose charge automatiquement le fichier .env depuis le répertoire du projet. Référencez les variables avec ${VARIABLE_NAME} dans votre YAML.

Utilisez notre Env Generator pour générer des fichiers .env avec des valeurs par défaut sensées et des templates .env.example pour votre équipe.

Réseau dans Docker

Compose crée un réseau par défaut pour votre stack. Les services peuvent se joindre mutuellement en utilisant le nom du service comme nom d'hôte — c'est pourquoi l'application utilise db comme hôte de base de données, et non localhost.

app → se connecte à "db:5432"
app → se connecte à "redis:6379"

Seuls les ports explicitement mappés avec ports: sont accessibles depuis la machine hôte.

Health checks et ordre de démarrage

depends_on attend uniquement qu'un conteneur démarre, pas qu'il soit prêt. Un conteneur de base de données démarre en quelques secondes, mais Postgres peut nécessiter quelques secondes supplémentaires avant d'accepter des connexions. Utilisez healthcheck + condition: service_healthy pour attendre que le service soit réellement opérationnel.

Considérations pour la production

  1. Utilisez des tags d'image précisnode:20.11.1-alpine, pas node:latest.
  2. Analysez les images pour détecter les vulnérabilitésdocker scout cves myapp:latest.
  3. Définissez des limites de ressources — évitez qu'un seul conteneur n'affame les autres.
  4. Utilisez des systèmes de fichiers en lecture seule quand c'est possible — read_only: true dans Compose.
  5. Ne jamais exécuter en tant que root — ajoutez USER node ou l'équivalent.
  6. Configurez Nginx comme reverse proxy devant votre application — utilisez notre Nginx Config Generator pour obtenir une configuration éprouvée.

Référence rapide

# Images
docker images                    # lister les images locales
docker pull nginx:alpine         # télécharger une image
docker rmi myimage               # supprimer une image

# Conteneurs
docker ps                        # conteneurs en cours d'exécution
docker ps -a                     # tous les conteneurs
docker stop <id>                 # arrêter proprement
docker rm <id>                   # supprimer un conteneur arrêté
docker logs <id> -f              # suivre les logs

# Nettoyage
docker system prune              # supprimer tout ce qui est inutilisé
docker volume prune              # supprimer les volumes inutilisés

Docker élimine toute une catégorie de bugs liés à l'environnement et rend l'intégration de nouveaux développeurs remarquablement simple. Maîtrisez les bases présentées ici et vous aurez une solide fondation pour Kubernetes, les pipelines CI/CD et les déploiements cloud.