đł Module Docker â Semaine de consolidation
Backend · Frontend · Base de donnĂ©es â Dev & Prod
Utilisez les flĂšches, cliquez ou glissez pour naviguer
1. ConnaĂźtre les patterns Docker de production
Restart, logging, resource limits
2. Utiliser les profiles Docker Compose
Séparer dev et prod avec --profile
3. Configurer docker-compose.override.yml
Surcharge automatique pour le développement
4. Organiser un projet Docker dev/prod
Configurations distinctes et workflow
5. Synthétiser toutes les connaissances Docker de la semaine
docker run â Dockerfile â Compose â Volumes/RĂ©seaux â Multi-stage â Production
Récap rapide de la semaine
docker run â Dockerfile â Compose â Volumes/RĂ©seaux â Multi-stage
Patterns de production
Restart policies, logging, resource limits, labels
Docker Compose profiles
Séparer les services de dev (adminer, debug) et de prod
Dev vs Prod : deux configurations Compose
docker-compose.override.yml vs -f explicite
Mini-projet : Conteneuriser Bootcode Hub
Backend + Frontend + Base de données en dev ET prod
Module 1
docker run â Dockerfile â Compose â Volumes â Multi-stage
1
docker run
2
Dockerfile
3
Compose
4
Volumes & Réseaux
5
Multi-stage
Lancer un conteneur Ă partir d'une image
docker run -d --name mon-app -p 3000:3000 -e NODE_ENV=production mon-image
// -d = détaché, -p = port mapping, -e = variable d'env
đŠ Commandes essentielles
docker ps â lister les conteneursdocker logs -f â suivre les logsdocker exec -it â entrer dans un conteneurdocker stop / rm â arrĂȘter / supprimerđ Images essentielles
node:20-alpine â 120 Mopostgres:16-alpine â 160 Monginx:alpine â 25 MoChaque instruction crĂ©e une layer (couche)
FROM node:20-alpine
WORKDIR /app
# Copier les dépendances d'abord
COPY package*.json ./
RUN npm ci
# Puis le code source
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
Bonnes pratiques :
.dockerignore â exclure node_modulesUn fichier YAML pour lancer tous les services en une commande
# docker-compose.yml
services:
api:
build: ./backend
ports: ["3000:3000"]
db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
docker compose up -d
Tout lancer
docker compose logs -f
Suivre les logs
docker compose down
Tout arrĂȘter
đŸ Persistance des donnĂ©es
services:
db:
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
bind mount (dev) :
- ./src:/app/src
volume nommé (prod) :
- pgdata:/var/lib/postgresql/data
đ Communication entre services
services:
api:
networks:
- app-net
networks:
app-net:
Dans le code, on utilise le nom du service comme hostname :
postgresql://user:pass@db:5432/mydb
Un seul Dockerfile, deux images : builder + runtime
â Image finale optimisĂ©e
FROM node:20-alpine AS builder
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# --- seconde étape ---
FROM node:20-alpine
COPY --from=builder /app/dist ./dist
CMD ["node", "dist/server.js"]
đ RĂ©sultat
Sans multi-stage : ~1.2 Go
Avec multi-stage : ~150 Mo
đĄ Principe
Builder compile + installe les dĂ©pendances de dev â seule la sortie utile (dist/) va dans l'image finale
Module 2
Restart · Logging · Resource limits · Labels
La différence entre un service qui tient la route et un service qui crashe sans prévenir
Que se passe-t-il quand le conteneur crashe ?
services:
api:
restart: unless-stopped # â Ă utiliser en production
đ« Les 3 autres options
no â ne redĂ©marre pas (dĂ©faut)on-failure[:max] â seulement si code != 0always â toujours, mĂȘme aprĂšs docker stopâ La rĂšgle d'or
restart: unless-stopped
Redémarre aprÚs crash, mais respecte docker stop
L'admin arrĂȘte proprement â pas de restart. Crash â redĂ©marrage auto.
Les logs = la mémoire de votre application
services:
api:
logging:
driver: json-file
options:
max-size: "10m" # Rotation tous les 10 Mo
max-file: "3" # Garde 3 fichiers
đ json-file
Défaut, rotation configurable
đ syslog / gelf
Centralisation externe
đ« local / none
Pas de logs. à éviter en prod
â ïž Sans rotation, les logs peuvent remplir le disque et faire planter le serveur !
Un conteneur ne doit pas pouvoir tout consommer
services:
api:
deploy:
resources:
limits:
memory: 256M
cpus: "0.5"
reservations:
memory: 128M
â ïž Sans limites
Un bug mémoire peut saturer le CPU et faire tomber tous les autres services
â Bonnes pratiques
Organiser et documenter ses services
services:
api:
labels:
- "app.name=bootcode-hub"
- "app.environment=production"
- "app.team=backend"
- "traefik.enable=true"
đ·ïž Organisation
Filtrer / trier les conteneurs
đ Reverse proxy
Traefik / Nginx utilisent les labels
đ Monitoring
Prometheus, Grafana s'en servent
Module 3
Un seul docker-compose.yml, plusieurs configurations
Lancer certains services seulement en dev, d'autres en prod
Un service peut appartenir Ă un ou plusieurs profiles
services:
api:
image: bootcode-api
profiles: ["dev", "prod"]
adminer:
image: adminer
profiles: ["dev"] # â Dev seulement !
docker compose --profile dev up
Lance tous les services du profile "dev"
docker compose --profile prod up
Lance seulement les services de prod
Des outils qu'on ne veut PAS en production
đïž Adminer
Interface web pour PostgreSQL/MySQL
adminer:
image: adminer
profiles: ["dev"]
ports: ["8080:8080"]
đ§ MailHog
Capture les emails en dev (SMTP + UI)
mailhog:
image: mailhog/mailhog
profiles: ["dev"]
đ Debug tools
Redis Commander, pgAdmin, etc.
redis-commander:
profiles: ["dev"]
đ Hot Reload
Bind mounts + nodemon/vite watch
api:
volumes:
- ./backend:/app
command: npx nodemon
On peut activer plusieurs profiles Ă la fois
# Lancer la stack complĂšte de dev
docker compose --profile dev up -d
# Lancer seulement la prod
docker compose --profile prod up -d
# Lancer les deux (utile en CI)
docker compose --profile dev --profile prod up -d
đĄ Cas d'usage
En CI, on lance le profile "prod" pour builder et tester l'image finale. En local, on lance "dev" pour avoir tous les outils de debug.
Module 4
Deux configurations Compose pour deux contextes
Automatiquement chargĂ© par Docker Compose â parfait pour le dev !
đ docker-compose.yml
services:
api:
build: ./backend
ports: ["3000:3000"]
env_file: .env
đ docker-compose.override.yml
services:
api:
volumes:
- ./backend:/app
command: npx nodemon
â ïž L'override est chargĂ© automatiquement sans flag -f
Quand vous lancez docker compose up -d, Compose fusionne les deux fichiers
Un fichier séparé, chargé explicitement avec -f
# docker-compose.prod.yml
services:
api:
build:
context: ./backend
target: production # â multi-stage: Ă©tape prod
restart: unless-stopped
logging:
options:
max-size: "10m"
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
On ignore volontairement le fichier override
| CritĂšre | Dev | Prod |
|---|---|---|
| Build | Bind mount du code source | Multi-stage build, image figée |
| Hot reload | nodemon / vite | Non (process manager type PM2) |
| Restart | no (ou on-failure) | unless-stopped |
| Logs | Par défaut (stdout) | Rotation configurée (10 Mo) |
| Limites | Aucune | 256M RAM / 0.5 CPU |
| .env | .env.dev | .env.prod |
| Outils | Adminer, MailHog, debug | Aucun outil superflu |
Module 5 â Mini-projet
Backend + Frontend + Base de donnĂ©es â Dev ET Prod
đ Objectif : Une stack complĂšte, prĂȘte pour le dĂ©veloppement ET le dĂ©ploiement
đ Frontend
React / Vite
Port 5173
â
âïž Backend API
Node.js / Express
Port 3000
â
đïž PostgreSQL
Port 5432
đ frontend/
đ backend/
đ docker/
services:
backend:
build: ./backend
ports: ["3000:3000"]
depends_on:
db:
condition: service_healthy
env_file: .env
frontend:
build: ./frontend
ports: ["80:80"]
depends_on: [backend]
db:
image: postgres:16-alpine
volumes: [pgdata:/var/lib/postgresql/data]
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
volumes:
pgdata:
Automatiquement chargĂ© â bind mounts + hot reload + outils dev
services:
backend:
volumes:
- ./backend:/app
- /app/node_modules # ne pas écraser
command: npx nodemon src/server.js
env_file: .env.dev
frontend:
volumes:
- ./frontend:/app
command: npm run dev -- --host
ports: ["5173:5173"]
adminer:
image: adminer
ports: ["8080:8080"]
Explicitement chargé avec -f
services:
backend:
build:
context: ./backend
target: production
restart: unless-stopped
env_file: .env.prod
logging:
options:
max-size: "10m"
max-file: "3"
deploy:
resources:
limits:
memory: "256M"
cpus: "0.5"
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
Pas d'override, pas de bind mounts, pas d'outils dev
Cloner le projet
git clone ... && cd bootcode-hub
Copier .env.dev â .env
cp .env.dev .env && docker compose up -d
Coder avec hot reload
Les changements sont détectés via les bind mounts
Adminer sur http://localhost:8080
Pour inspecter la base de données
Builder les images
docker compose -f docker-compose.prod.yml build
Pousser vers le registry
docker tag bootcode-api registry.example.com/api:v1.0
docker push registry.example.com/api:v1.0
Déployer sur le serveur
scp docker-compose.prod.yml .env.prod server:/app/
ssh server "docker compose -f docker-compose.prod.yml up -d"
â ïž Toujours builder AVANT de dĂ©ployer ! Les bind mounts de dev ne marchent pas en prod.
â L'erreur
services:
api:
image: mon-api
# pas de restart policy
â Le service crashe Ă 3h du matin
â Personne ne le relance â downtime
â La solution
services:
api:
image: mon-api
restart: unless-stopped
â RedĂ©marrage automatique aprĂšs crash
â Et on peut toujours faire docker stop
â L'erreur
# .env (dev ET prod)
DB_PASSWORD=password123
â Dev utilise le mĂȘme mot de passe que prod
â Faille de sĂ©curitĂ© monumentale
â La solution
# .env.dev
DB_PASSWORD=dev_password_local
# .env.prod (jamais commité!)
DB_PASSWORD=aB7!xK9#mP2$
# .gitignore
.env.prod
Le scénario catastrophe
â La solution
â La confusion
Les étudiants pensent que override et -f sont interchangeables
docker compose -f docker-compose.override.yml up
// N'inclut PAS docker-compose.yml !
â La rĂ©alitĂ©
docker compose up
â Charge docker-compose.yml + override
docker compose -f docker-compose.prod.yml up
â Charge SEULEMENT le fichier prod
docker compose -f docker-compose.yml -f docker-compose.prod.yml up
â Charge les deux, PAS l'override
đ En production, toujours restart: unless-stopped
Le service redĂ©marre aprĂšs un crash, mais pas aprĂšs un arrĂȘt volontaire
đ Les profiles isolent les services de dev (adminer, mailhog)
Avec --profile dev / --profile prod
đ docker-compose.override.yml est chargĂ© automatiquement
Parfait pour les configs de dev sans avoir à spécifier de flag
đïž Workflow rĂ©el : dev avec bind mounts â CI avec multi-stage â prod avec compose
Chaque environnement a sa configuration adaptée
docker run
Lancer des conteneurs
-d, -p, -e, --name
Dockerfile
Construire des images
FROM, COPY, RUN, CMD
Compose
Orchestrer multi-services
YAML, services, networks
Volumes
Persister les données
Volumes nommés, bind mounts
Multi-stage
Images optimisées
Builder + Runtime
Production
Restart, logs, limits
Patterns professionnels
Conteneuriser Bootcode Hub avec deux configurations
1. Structure du projet
bootcode-hub/
âââ backend/
â âââ Dockerfile (multi-stage)
â âââ src/
âââ frontend/
â âââ Dockerfile (multi-stage)
â âââ src/
âââ docker-compose.yml
âââ docker-compose.override.yml
âââ docker-compose.prod.yml
âââ .env.dev
âââ .env.prod (ignorĂ© par git)
2. Contraintes
Vous savez maintenant dockeriser un projet complet
Rappel :
docker compose --profile dev up pour dev
docker compose -f docker-compose.prod.yml up pour prod