Docker : packager une application pour qu'elle tourne partout
Le problème 'ça marche sur ma machine' a une solution depuis 2013. Docker encapsule une application et toutes ses dépendances dans un conteneur portable.
Avant Docker, déployer une application impliquait de s'assurer que le serveur avait la bonne version de Node.js, les bonnes dépendances système, les bons variables d'environnement. Une différence entre dev et prod suffisait à tout casser. "Ça marche sur ma machine" était une blague qui n'amusait personne en production.
Docker résout ce problème en encapsulant l'application et tout son environnement dans un conteneur. Le conteneur tourne identiquement sur le laptop du développeur, dans la CI, et en production.
Comment ça fonctionne
Un conteneur Docker n'est pas une VM. Il partage le kernel Linux de l'hôte mais isole les processus, le système de fichiers et le réseau via des fonctionnalités kernel (namespaces et cgroups). Résultat : démarrage en secondes, consommation mémoire réduite, densité d'applications bien supérieure aux VMs traditionnelles.
Le point de départ est le Dockerfile : la recette de construction du conteneur.
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["npm", "start"]docker build -t monapp . construit l'image. docker run -p 3000:3000 monapp démarre le conteneur.
Multi-stage builds : réduire drastiquement la taille de l'image
Le Dockerfile précédent copie tout le code source dans l'image finale. Pour une app compilée, c'est du gaspillage — les outils de build n'ont pas leur place en production.
# Stage 1 : build
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2 : production (image finale)
FROM node:18-alpine AS runner
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
WORKDIR /app
COPY --from=builder --chown=nextjs:nodejs /app/dist ./dist
COPY --from=builder --chown=nextjs:nodejs /app/package*.json ./
RUN npm ci --only=production
USER nextjs
EXPOSE 3000
CMD ["node", "dist/server.js"]L'image builder peut faire 1.2 GB avec tous les outils de build. L'image finale descend à 50-100 MB parce qu'elle ne contient que ce qui est nécessaire au runtime. Le gain est immédiat sur le temps de déploiement et le stockage.
Docker Compose : orchestrer plusieurs services localement
Une application réelle ne tourne pas seule — elle a besoin d'une base de données, d'un cache, parfois d'un worker. Docker Compose décrit l'ensemble dans un fichier YAML.
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/myapp
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7-alpine
volumes:
- redisdata:/data
volumes:
pgdata:
redisdata:docker compose up -d # Démarrer en background
docker compose logs -f # Suivre les logs
docker compose down # Arrêter et supprimer les conteneursdocker compose up démarre toute la stack en une commande. Un développeur qui rejoint le projet n'a pas besoin d'installer PostgreSQL et Redis manuellement — Docker s'en charge.
Sécurité : les bonnes pratiques de base
Par défaut, les processus dans un conteneur tournent en root. C'est un risque si le conteneur est compromis — root dans le conteneur peut devenir root sur l'hôte dans certaines configurations.
La correction est simple : créer un utilisateur non-privilégié et l'utiliser.
RUN addgroup -g 1001 -S appgroup \
&& adduser -S appuser -u 1001 -G appgroup
USER appuserAutres bonnes pratiques :
# Limiter les ressources
docker run \
--memory 512m \
--cpus 0.5 \
--read-only \
myapp:latest# Scanner les vulnérabilités d'une image
docker scout cves monapp:latest
# Alternative avec Trivy
trivy image --severity HIGH,CRITICAL monapp:latestLes commandes du quotidien
# Construire une image
docker build -t monapp:v1 .
# Lister les images locales
docker images
# Démarrer un conteneur
docker run -d -p 3000:3000 --name monapp monapp:v1
# Voir les conteneurs en cours
docker ps
# Voir les logs
docker logs -f monapp
# Entrer dans un conteneur en cours
docker exec -it monapp sh
# Arrêter et supprimer
docker stop monapp && docker rm monapp
# Nettoyer les images et conteneurs inutilisés
docker system pruneDocker vs alternatives
Podman est la principale alternative — compatible Docker, sans daemon centralisé, et rootless par défaut (les conteneurs tournent avec les permissions de l'utilisateur). Sur RHEL/Fedora, c'est le choix par défaut. Les commandes sont quasi identiques : remplacez docker par podman.
Pour l'orchestration à grande échelle, Kubernetes (K8s) prend le relais de Docker Compose. Pour la plupart des projets, GitHub Actions suffit à automatiser le cycle build → test → deploy. K8s gère le scaling automatique, la distribution sur plusieurs machines, les rollouts progressifs et la récupération sur erreur. Mais c'est une couche de complexité significative — Docker Compose couvre la plupart des besoins pour un projet standard.
Le déploiement classique sur VPS passe par SSH avec des clés d'authentification — Docker rend l'artefact portable, SSH le livre.
Docker a changé la façon dont les équipes déploient. Pas parce que c'est une technologie compliquée, mais parce qu'elle résout un problème réel de façon élégante : votre application devient un artifact portable et reproductible.