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.
« Ç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
- Utilisez des tags d'image précis —
node:20.11.1-alpine, pasnode:latest. - Analysez les images pour détecter les vulnérabilités —
docker scout cves myapp:latest. - Définissez des limites de ressources — évitez qu'un seul conteneur n'affame les autres.
- Utilisez des systèmes de fichiers en lecture seule quand c'est possible —
read_only: truedans Compose. - Ne jamais exécuter en tant que root — ajoutez
USER nodeou l'équivalent. - 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.