3.4 · Variables, profils et surcharges par environnement

Niveau 3 · Docker Compose

3.4Variables, profils et surcharges par environnement

Objectif : décliner un compose en dev / prod sans dupliquer le fichier.
Temps estimé : 12 min · lecture autonome · Si vous n'avez que 5 min : lisez « L'essentiel en 30s » + le schéma.

L'essentiel en 30 secondes

  • Le .env : une valeur, plusieurs visages : ${PORT:-3000} lit la variable ou son défaut — un fichier .env par environnement, un seul compose pour N visages.
  • Les surcharges : socle + variante : compose.override.yml auto-chargé en dev, -f compose.yml -f compose.prod.yml en prod — chaque fichier ne décrit que sa différence.
  • Les profils : services opt-in : profiles: [dev] rend adminer absent par défaut, présent avec --profile dev — le stack par défaut est minimal et sûr.

Mini-cas filé — Idir unifie dev et prod

Idir, devops junior à Alger, maintient deux compose.yml copiés (dev avec adminer, prod sans) — ils divergent, et un jour la console dev part en production. Il refond : un socle unique avec ${PORT:-3000}, adminer sous profiles: [dev], .env par environnement non commité. Dev : --profile dev up -d ; prod : up -d, sobre par défaut. Une seule source de vérité, deux visages — la prod ne contient plus jamais les outils de dev.

Ce même cas revient dans le cours, le schéma, le script et le défi 48h.

1. Interpolation et .env : paramétrer sans dupliquer

Dans compose.yml, ${PORT:-3000} lit la variable PORT ou 3000 par défaut : le compose devient PARAMÉTRABLE. Un fichier .env à côté du compose fixe les valeurs par environnement (dev : ports publiés + adminer ; prod : autres valeurs, pas d'adminer) — chargé automatiquement. Un fichier, N visages : la même image, la même structure, des valeurs qui changent.

Règle d'hygiène : le .env contenant des secrets n'est JAMAIS commité — on versionne un .env.example factice qui documente les clés attendues. Et les défauts ${X:-…} sont choisis prod-sûrs : sans variable, le stack démarre dans sa forme la plus sobre, pas la plus ouverte.

2. Surcharges -f et profils : variantes et opt-in

Les SURCHARGES : on garde un compose.yml SOCLE et on ajoute des variantes — compose.override.yml, chargé automatiquement en dev (bind mounts, debug), ou compose.prod.yml appelé explicitement (-f compose.yml -f compose.prod.yml). Chaque fichier ne décrit que sa DIFFÉRENCE ; de gauche à droite, chaque -f surcharge le précédent. Fini la duplication intégrale par environnement.

Les PROFILS : profiles: [dev] sur adminer le rend OPT-IN — absent par défaut, présent avec --profile dev. Fini le « j'ai oublié d'enlever la console en prod » : par défaut, le stack est minimal et sûr, les outils dev s'activent explicitement. Socle minimal, options en profils, défaut prod-sûr.

Erreur d'interprétation fréquente : « Un compose par environnement, c'est plus clair, et les profils dev peuvent rester actifs par défaut ». Non, deux fois. Deux fichiers copiés DIVERGENT — toute correction doit être portée deux fois, et un jour la console dev part en prod. Et un profil actif par défaut n'est plus un profil : l'opt-in n'existe que si le défaut est sobre. Un socle, des surcharges, des opt-in.
Décliner sans dupliquer Socle, valeurs, variantes, opt-in Socle versionnécompose.yml + ${VAR:-défaut prod-sûr}+Valeurs par env.env local non commité + .env.example+Variantes + opt-inSurcharges -f, override dev, profiles Par défaut : minimal et sûr ; le dev s'active explicitement.
Socle, valeurs, variantes, opt-in
Version texte du schéma (SEO / lecteurs d'écran / traduction) : 1) Socle : Idir écrit un compose unique avec ${PORT:-3000} au lieu de deux fichiers copiés. 2) Valeurs : .env par environnement non commité, .env.example versionné, défauts prod-sûrs. 3) Variantes : override auto en dev, -f prod explicite, adminer en profil dev — sobre par défaut. Leçon : un socle, des valeurs, des différences en surcharge.

🔎 Exemple concret — Dev riche, prod sobre : même socle, deux visages

Idir paramètre le port, met adminer en profil dev, et lance chaque environnement.

# compose.yml (socle)
services:
  api:
    build: ./api
    ports: ["${PORT:-3000}:3000"]
    networks: [appnet]
  adminer:
    image: adminer:4.8
    profiles: [dev]
    ports: ["8081:8080"]
    networks: [appnet]
networks:
  appnet:
# .env (dev, NON commité) : PORT=3000
# Dev  : docker compose --profile dev up -d
# Prod : PORT=80 docker compose up -d

Lecture : même socle, adminer seulement en dev, port par variable.

Leçon : la prod ne contient jamais les outils de dev — sobre par défaut.

Vocabulaire de la section

Interpolation
${VAR:-défaut} résolu depuis l'environnement ou le .env : le compose paramétrable.

Exemple simple : Le ${PORT:-3000} d'Idir, 3000 sans variable.

Ce que ce n'est pas : un port en dur dupliqué dans deux fichiers.

Réflexe : défaut prod-sûr après chaque :-.

Surcharge
Fichier -f supplémentaire qui modifie le socle : chaque -f surcharge le précédent, de gauche à droite.

Exemple simple : -f compose.yml -f compose.prod.yml en production.

Ce que ce n'est pas : un second compose copié à 95 % identique.

Réflexe : chaque variante ne décrit que sa différence.

override
Surcharge dev (compose.override.yml) chargée automatiquement : binds, debug, sans toucher au socle.

Exemple simple : Les montages live d'Idir en dev uniquement.

Ce que ce n'est pas : des binds de dev qui fuient en production.

Réflexe : dev dans l'override, jamais dans le socle.

Profil
Groupe opt-in (profiles: [dev]) activé par --profile : service absent par défaut.

Exemple simple : Adminer présent seulement avec --profile dev.

Ce que ce n'est pas : la console dev qui part en prod par oubli.

Réflexe : outils dev en profils, stack sobre par défaut.

.env
Fichier local de valeurs à côté du compose, chargé auto — non commité s'il contient des secrets.

Exemple simple : Le .env d'Idir avec PORT et mots de passe locaux.

Ce que ce n'est pas : un .env avec secrets poussé au dépôt.

Réflexe : versionner .env.example, jamais les secrets.

En pratique — Dev/prod sans duplication

  1. Ajoutez ${PORT:-3000} et un profil dev (adminer) à votre compose socle.
  2. Lancez sans profil : vérifiez qu'adminer est absent (stack sobre).
  3. Relancez avec --profile dev : adminer apparaît — opt-in explicite.
  4. Changez PORT via l'environnement et relancez : le port suit, sans toucher au fichier.
Un seul socle sert tous les environnements : valeurs par env, différences en surcharge, outils en opt-in.

Script prêt à dire — justifier le socle unique (30 s)

« Un seul compose socle : le port vient d'une variable, la console dev d'un profil opt-in, les différences de la prod d'une surcharge. Dev riche avec --profile dev, prod sobre par défaut — plus aucun fichier copié qui diverge, plus aucun outil dev qui fuit en prod. »

À dire en revue d'architecture ; montrer le diff vide entre dev et prod.

Modèle copier-coller — socle paramétré + profil dev

# Socle : dev riche en opt-in, prod sobre par défaut.
services:
  api:
    build: ./api
    ports:
      - "${PORT:-3000}:3000"
    environment:
      DATABASE_URL: ${DATABASE_URL}
    networks:
      - appnet
  adminer:
    image: adminer:4.8
    profiles:
      - dev
    ports:
      - "8081:8080"
    networks:
      - appnet

networks:
  appnet:
# Dev  : docker compose --profile dev up -d
# Prod : docker compose -f compose.yml -f compose.prod.yml up -d

Indépendant

Socle + .env.example et chaque client décline sans toucher au fichier.

PME à Alger

Idir unifie dev et prod : un socle, deux .env, zéro divergence.

Équipe projet

Imposer socle minimal + profils opt-in + défauts prod-sûrs dans la charte.

Débutant

Cette semaine : une variable ${PORT:-3000} + un service en profil dev.

Prudence : Jamais de .env avec secrets commité : versionnez un .env.example factice, gardez les vraies valeurs en local (ou secret managé en prod). Les défauts ${X:-…} restent prod-sûrs — le stack sans variable démarre sobre, jamais ouvert.

✓ Bonnes pratiques

  • Gardez le socle minimal, mettez les options en profils opt-in.
  • Choisissez des défauts prod-sûrs après chaque :- (${X:-…}).
  • Versionnez un .env.example, jamais les secrets réels.

✗ Pièges fréquents

  • Dupliquer tout le fichier par environnement : les copies divergent.
  • Profils dev actifs par défaut : l'opt-in n'existe plus, la console fuit en prod.
  • Committer un .env avec mots de passe : secret exposé dans l'historique.

Points clés à retenir

  • ${VAR:-défaut} rend le compose paramétrable : un fichier, N visages.
  • SURCHARGES pour les différences (-f, override dev) : jamais de duplication.
  • PROFILS opt-in pour les outils : absent par défaut, --profile dev pour activer.
  • DÉFAUT = prod sûre ; .env.example versionné, secrets jamais commités.

Défi 48h — appliquez demain

Fusionnez 2 compose copiés en 1 socle + 1 profil dev + 1 surcharge, et prouvez que la prod démarre sobre.

Checklist sortie de section
  • Mon socle unique sert dev et prod sans copier-coller.
  • Mes outils dev sont en opt-in, sobres par défaut.
  • Mes secrets sont hors du dépôt, mes défauts prod-sûrs.
Auto-évaluation 1-5 : combien de compose quasi-identiques me reste-t-il ?est-ce que ma prod démarre sobre sans aucune variable ?

Questions fréquentes

Où placer le .env, et comment le garder hors du dépôt ?

À CÔTÉ du compose.yml : chargé automatiquement, un seul par environnement. S'il contient des secrets, jamais commité (ajoutez-le au .gitignore) — fournissez un .env.example versionné avec des valeurs factices documentant chaque clé. En prod, les valeurs viennent de l'environnement ou d'un secret managé.

Plusieurs -f, dans quel ordre, et override ou prod ?

De GAUCHE À DROITE : chaque -f surcharge le précédent — le socle d'abord, la variante ensuite (-f compose.yml -f compose.prod.yml). compose.override.yml est l'exception : chargé AUTOMATIQUEMENT (sans -f), il porte le dev (binds, debug). Règle : dev = override auto, prod = -f explicite, et chaque fichier ne décrit que sa différence.

Vérifiez votre compréhension

Adminer ne doit exister qu'en dev. Quelle mécanique ?

Ressources supplémentaires (optionnel, pour aller plus loin)

Examen du niveau 3Questions inédites et durcies pour valider vos acquis