← Retour au blog
Outils Infrastructure

Docker — de la machine du développeur à la production

Docker a transformé la façon dont on développe et déploie des applications. Mais entre l'usage sur le poste du développeur et la prod, les enjeux sont différents. Tour complet des bonnes pratiques pour les deux contextes.

Avant Docker, le classique "ça marche sur ma machine" était une blague de développeur et un cauchemar d'ops. L'environnement de développement divergeait inévitablement de la production — versions de langage différentes, librairies systèmes absentes, variables d'environnement oubliées. Docker n'a pas inventé les conteneurs, mais il a rendu leur usage accessible à tous. En 2021, c'est un outil que tout développeur backend doit maîtriser.


Ce que Docker résout fondamentalement

Un conteneur Docker empaquète une application avec tout ce dont elle a besoin pour tourner : le code, le runtime, les librairies système, les variables d'environnement. Là où une machine virtuelle virtualise tout le matériel (lourd, lent), un conteneur partage le noyau du système hôte et n'isole que le processus (léger, rapide).

Le résultat : le même artefact tourne de la même façon sur votre laptop, en CI, en staging et en production. Pas de "mais sur mon poste ça marche", pas de drift entre environnements.


Docker pour le développeur

Démarrer des services tiers sans rien installer

C'est le premier bénéfice immédiat. Besoin de PostgreSQL pour ce projet ? Plus besoin d'installer Postgres localement, de gérer plusieurs versions, d'avoir des conflits entre projets.

docker run -d \
  --name postgres-dev \
  -e POSTGRES_PASSWORD=secret \
  -e POSTGRES_DB=myapp \
  -p 5432:5432 \
  postgres:14

Une commande, un service qui tourne. Même chose pour Redis, Elasticsearch, RabbitMQ, ou n'importe quelle dépendance.

Docker Compose — l'orchestrateur du développeur

Un fichier docker-compose.yml décrit l'ensemble des services de l'application et leurs dépendances. Un docker compose up lance tout. C'est le standard pour les environnements de développement.

version: '3.9'

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

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

volumes:
  postgres_data:

Le healthcheck sur la base de données est important : sans lui, l'application peut démarrer avant que Postgres soit prêt à accepter des connexions.

Hot reload et volumes

Le volume .:/app monte le code source local dans le conteneur. Toute modification de fichier est immédiatement visible dans le conteneur — le hot reload fonctionne sans reconstruire l'image.


Écrire un Dockerfile de qualité

Le Dockerfile est le blueprint de votre image. Un mauvais Dockerfile produit des images lourdes, lentes à construire, et potentiellement peu sûres.

Multi-stage build — la bonne pratique fondamentale

# Étape 1 : build
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

COPY . .
RUN npm run build

# Étape 2 : image finale légère
FROM node:18-alpine AS runner
WORKDIR /app

# Ne pas tourner en root
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules

EXPOSE 3000
CMD ["node", "dist/main.js"]

Ce pattern multi-stage garantit que les outils de build (compilateurs, devDependencies) ne se retrouvent pas dans l'image finale. Une image Node.js bien construite pèse 150–200 Mo au lieu de 1 Go+.

L'ordre des instructions compte

Docker met en cache chaque layer. Placez les instructions qui changent peu en haut, celles qui changent souvent en bas :

# Bon ordre : deps d'abord, code ensuite
COPY package*.json ./
RUN npm ci
COPY . .          # invalidé à chaque changement de code, mais pas le layer npm ci

.dockerignore

Indispensable. Sans lui, COPY . . embarque node_modules, .git, les fichiers de config locaux, parfois des secrets.

node_modules
.git
.env
.env.local
*.log
dist
coverage

Docker en production

En production, les enjeux changent : disponibilité, sécurité, observabilité, scalabilité.

Ne jamais tourner en root

Par défaut, les processus dans un conteneur tournent en root. Si le conteneur est compromis, l'attaquant a les droits root dans le conteneur — et potentiellement sur l'hôte via des mauvaises configurations. Toujours créer un utilisateur non-privilégié.

Images minimales

Préférez alpine ou distroless aux images complètes. Moins de packages installés = moins de surface d'attaque = moins de CVE à corriger.

Image Taille
node:18 ~950 Mo
node:18-slim ~240 Mo
node:18-alpine ~170 Mo

Gestion des secrets

Ne jamais mettre de secrets dans le Dockerfile ou dans les variables d'environnement en clair dans docker-compose.yml en production. Utilisez Docker Secrets, Vault, ou les mécanismes du cloud provider (AWS Secrets Manager, GCP Secret Manager).

# En prod : pas ça
environment:
  DATABASE_PASSWORD: supersecret  # visible dans docker inspect

# Préférer les secrets Docker Swarm ou un gestionnaire externe
secrets:
  db_password:
    external: true

Healthchecks

Un healthcheck dans le Dockerfile permet à l'orchestrateur (Docker Swarm, Kubernetes) de savoir si le conteneur est réellement prêt à recevoir du trafic.

HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD wget --quiet --tries=1 --spider http://localhost:3000/health || exit 1

Limites de ressources

Sans limites, un conteneur peut consommer toute la mémoire ou le CPU du nœud hôte.

deploy:
  resources:
    limits:
      cpus: '0.5'
      memory: 512M
    reservations:
      memory: 256M

Kubernetes : l'étape suivante

Pour les applications à fort trafic ou nécessitant haute disponibilité, Docker seul ne suffit pas. Kubernetes orchestre des clusters de conteneurs : scheduling, auto-scaling, self-healing, rolling deployments.

Mais Kubernetes a une courbe d'apprentissage abrupte. Pour beaucoup d'équipes, Docker Swarm (intégré à Docker) est un juste milieu — plus simple, suffisant pour orchestrer quelques dizaines de services.


En résumé

Docker n'est pas une technologie de déploiement réservée aux ops. C'est un outil de développement autant que de production. Maîtriser les bonnes pratiques — multi-stage builds, images légères, non-root, healthchecks, gestion des secrets — est ce qui distingue un usage naïf d'un usage professionnel.

La promesse initiale reste tenue : une image construite une fois, déployable partout, de la même façon.

Vous avez un projet en tête ?

Parlons de vos enjeux et voyons comment Gotan peut vous accompagner.

Contactez-nous