Introduction
Les variables d'environnement sont le principal moyen de configurer les conteneurs dans Docker Compose sans modifier les images. Elles contrôlent les identifiants de base de données, les indicateurs de fonctionnalités, les points de terminaison d'API et les limites de ressources. Lorsque des variables sont manquantes, mal orthographiées ou exposées, les services échouent au démarrage ou divulguent des secrets dans les journaux. Ce guide décrit les commandes et les modèles nécessaires pour observer, définir, valider et récupérer les variables d'environnement dans les projets Docker Compose. Il s'adresse aux développeurs, aux ingénieurs DevOps et aux équipes de plateforme qui exécutent des applications multi-conteneurs en local et en production.
Vous apprendrez à inspecter la version et le projet Compose actuel, à comprendre la précédence et la substitution des variables, à utiliser les fichiers d'environnement en toute sécurité, à transmettre des variables au moment de la construction et de l'exécution, à effectuer des vérifications en lecture seule, à diagnostiquer les échecs courants et à mettre en œuvre une liste de contrôle opérationnelle reproductible. Chaque section comprend des commandes concrètes avec leur sortie attendue, les signes d'échec et les étapes de récupération.
Inventaire de la version et de l'environnement
Avant de modifier une variable, établissez ce que vous exécutez et où se trouve la configuration. Commencez par des observations en lecture seule. Exécutez docker compose version pour confirmer la version de l'interface en ligne de commande :
docker compose version
La sortie attendue ressemble à :
Docker Compose version v2.24.6
Les anciens projets v1 peuvent utiliser docker-compose (avec un trait d'union). Si vous voyez command not found, vous utilisez soit une ancienne installation, soit le plugin est manquant. Utilisez docker compose version pour confirmer la v2. Pour les projets qui doivent prendre en charge la v1, la syntaxe des variables d'environnement est presque identique, mais Compose v2 offre une meilleure interpolation et des profils nommés.
Confirmez le nom du projet actif et les fichiers de configuration avec :
docker compose ls
Cela répertorie les projets Compose en cours d'exécution, leur statut et les chemins des fichiers de configuration. Si le nom du projet est inattendu, vérifiez la variable COMPOSE_PROJECT_NAME ou l'option -p. Le nom du projet affecte les noms de réseau, de volume et de conteneur, il est donc important pour le dépannage.
Inspectez la configuration résolue sans appliquer de modifications :
docker compose config
Cela affiche le YAML entièrement fusionné avec toutes les substitutions de variables appliquées. Il ne démarre pas les conteneurs. Comparez cela à votre docker-compose.yml pour voir exactement quelles valeurs seront utilisées. Pour un service spécifique, exécutez docker compose config <service>. Si la commande échoue avec invalid interpolation ou required variable is not set, une variable manquante doit être traitée avant le démarrage de tout conteneur.
Listez toutes les variables d'environnement actuellement visibles par un conteneur en cours d'exécution :
docker compose exec <service> env
ou, sans entrer dans le conteneur :
docker inspect <container> --format '{{range .Config.Env}}{{println .}}{{end}}'
Cette sortie comprend les variables provenant de l'image, du fichier Compose, de l'environnement shell et des fichiers d'environnement. Utilisez-la pour vérifier si des secrets sont involontairement exposés. N'imprimez jamais de valeurs sensibles dans les journaux CI ; utilisez docker inspect avec un modèle filtré ou une comparaison des fichiers d'environnement à la place.
Enregistrez les versions de Docker et Compose, le nom du projet, le chemin du fichier de configuration et un horodatage avant toute modification. Une séquence de commandes d'inventaire simple peut ressembler à :
docker version --format '{{.Server.Version}}'
docker compose version
docker compose ls
docker compose config --quiet
date -u +"%Y-%m-%dT%H:%M:%SZ"
Enregistrez cette sortie dans un fichier temporaire ou un canal partagé. C'est votre base de référence pour la restauration.
Chemin de configuration sûr
Docker Compose résout les variables d'environnement à partir de plusieurs sources dans un ordre strict. Connaître cet ordre évite les remplacements inattendus.
La précédence, de la plus élevée à la plus basse, dans Compose v2 :
- Variables d'environnement du shell (celles déjà exportées dans la session en cours)
- Variables du fichier
.envdans le répertoire du projet (pour--env-file, voir ci-dessous) - Variables définies dans la section
environment:du service - Variables définies dans une liste
env_file:(les fichiers ultérieurs remplacent les précédents, et elles sont injectées dans le conteneur mais pas utilisées pour l'interpolation dans le fichier Compose lui-même) - Instructions
ENVdu Dockerfile dans l'image
Un exemple pratique :
Étant donné un docker-compose.yml :
services:
web:
image: nginx:alpine
environment:
- API_URL=http://api:8080
- DEBUG=false
env_file:
- ./common.env
Et common.env :
API_URL=http://localhost:3000
DEBUG=true
Si vous exécutez docker compose config, vous verrez que API_URL prend la valeur http://api:8080 car environment: remplace env_file:. Cependant, à l'intérieur du conteneur en cours d'exécution, la variable DEBUG sera true provenant de common.env à moins qu'elle ne soit également dans environment:. Cette dualité déroute de nombreux opérateurs : environment: est uniquement pour l'interpolation et l'exécution du conteneur, tandis que env_file: injecte uniquement des valeurs dans le conteneur ; il ne les rend pas disponibles pour la substitution ${VAR} dans le fichier Compose.
Pour rendre la substitution explicite et éviter les surprises, utilisez un fichier .env situé à côté de docker-compose.yml (ou référencé via --env-file). Le fichier .env par défaut est utilisé uniquement pour l'interpolation dans le fichier Compose ; il n'est pas automatiquement injecté dans les conteneurs. Pour que les variables soient disponibles à la fois pour l'interpolation et à l'intérieur du conteneur, vous pouvez soit :
- Les définir dans le shell avant d'exécuter
docker compose up - Les référencer explicitement dans
environment:en utilisant${VAR} - Utiliser plusieurs entrées
env_file:pour les variables d'exécution et un.envséparé pour l'interpolation du fichier Compose
Exemple de fichier .env pour l'interpolation :
POSTGRES_VERSION=16.2
APP_PORT=8080
Et dans docker-compose.yml :
services:
db:
image: postgres:${POSTGRES_VERSION}
ports:
- "${APP_PORT}:5432"
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
Ici, DB_PASSWORD doit également être dans le fichier .env ou le shell, sinon docker compose config échoue. Si vous devez transmettre des valeurs sensibles, utilisez les secrets Docker ou des magasins de secrets externes, pas des fichiers d'environnement en clair versionnés dans le contrôle de source.
Un flux de travail sûr lors de la modification d'une variable d'environnement :
- Copiez le
docker-compose.ymlet le.envactuels vers un emplacement de sauvegarde. - Exécutez
docker compose configpour voir la sortie résolue. Redirigez-la vers un fichier avec> /tmp/compose-resolved.ymlet inspectez-la pour détecter les remplacements de variables involontaires ou les secrets exposés. - Modifiez une variable à la fois. Si plusieurs variables interagissent, documentez la dépendance. Par exemple, changer
DATABASE_URLpeut nécessiter de changerREDIS_URLsi elles partagent un nom d'hôte. - Appliquez la modification avec
docker compose up -d --force-recreate <service>uniquement après quedocker compose configa réussi. - Vérifiez avec un contrôle de santé ou une inspection des journaux (voir Vérification et diagnostics).
Ne modifiez jamais le fichier .env directement sur un serveur de production sans contrôle de version. Utilisez un processus de déploiement contrôlé qui applique la même modification d'abord en préproduction, puis en production, avec un plan de restauration (par exemple, annuler le fichier et exécuter à nouveau docker compose up -d).
Vérification et diagnostics
Après avoir modifié les variables d'environnement, vérifiez que le service a bien pris en compte les nouvelles valeurs. Ne supposez pas que docker compose up -d sans erreur signifie succès ; un service peut démarrer et être mal configuré.
Tout d'abord, vérifiez l'état du conteneur :
docker compose ps
Sortie saine attendue :
NAME COMMAND SERVICE STATUS PORTS
myapp-web-1 "nginx -g 'daemon of…" web running (healthy) 0.0.0.0:8080->80/tcp
Si l'état est restarting, unhealthy ou exited, inspectez immédiatement les journaux :
docker compose logs --tail=50 <service>
Pour une variable d'environnement mal configurée, les messages de journal typiques comprennent :
panic: runtime error: invalid memory address or nil pointer dereference(courant dans les applications Go lorsqu'une variable d'environnement requise est vide)Error: connect ECONNREFUSED 127.0.0.1:5432(hôte ou port de base de données incorrect à partir deDATABASE_URL)The server requested authentication method unknown to the client(incompatibilité de variable d'authentification Postgres)Error: Missing required environment variable: API_KEY
Utilisez docker compose exec pour inspecter la valeur de variable en direct à l'intérieur du conteneur :
docker compose exec web printenv DEBUG
Si le conteneur redémarre trop rapidement, utilisez docker inspect sur l'ID du conteneur :
docker inspect <container-id> --format '{{.State.Status}} {{.State.ExitCode}}'
Pour les conteneurs PostgreSQL, vous pouvez également vérifier le mot de passe configuré en vous connectant :
docker compose exec db psql -U postgres -c "SELECT current_user, current_database();"
Si l'authentification échoue, la variable POSTGRES_PASSWORD n'a probablement pas atteint le conteneur. Vérifiez à nouveau la sortie de docker compose config.
Pour diagnostiquer les problèmes de précédence des variables, comparez la configuration résolue à l'environnement réel du conteneur :
# Environnement Compose résolu pour le service web :
docker compose config web | grep -A5 "environment"
# Environnement réel du conteneur :
docker inspect $(docker compose ps -q web) --format '{{range .Config.Env}}{{println .}}{{end}}'
Toute incohérence indique un remplacement par env_file, le shell ou les valeurs par défaut de l'image.
Exécutez un test de redémarrage pour confirmer la persistance de la configuration pilotée par l'environnement. Pour un service avec état comme une base de données, arrêtez et recréez le conteneur, puis vérifiez que les données et la configuration restent :
docker compose stop db
docker compose rm -f db
docker compose up -d db
# Après le démarrage, vérifiez une variable connue :
docker compose exec db printenv POSTGRES_DB
Si la variable est vide ou si la base de données ne démarre pas, la variable n'a pas été définie dans le fichier Compose mais peut-être dans une session shell précédente ou dans la valeur par défaut de l'image. C'est un échec courant lors du passage du local à l'intégration continue.
Modes d'échec et récupération
Plusieurs erreurs courantes causent des problèmes de variables d'environnement dans Docker Compose. Comprendre pourquoi elles se produisent et comment les récupérer permet de gagner du temps et d'éviter des incidents de production.
1. L'interpolation de variable échoue lors de docker compose up
Symptôme :
ERROR: The interpolation of '${DB_PASSWORD}' in 'services.db.environment.POSTGRES_PASSWORD' is not valid. Required variable DB_PASSWORD is missing.
Pourquoi : Vous avez référencé ${DB_PASSWORD} dans le fichier Compose, mais il n'est pas défini dans l'environnement shell ni dans le fichier .env. Compose v2 ne lit que le fichier .env dans le répertoire du projet (ou spécifié par --env-file), pas les entrées env_file:.
Récupération :
- Ajoutez la variable à
.envdans le même répertoire quedocker-compose.yml. - Ou exportez-la dans le shell avant d'exécuter Compose :
export DB_PASSWORD=yourpassword. - Ou passez-la explicitement :
docker compose --env-file ./config/secrets.env up -d. - Évitez de versionner des secrets dans
.env; utilisez un gestionnaire de secrets CI et écrivez le fichier lors du déploiement.
2. Les variables de env_file ne sont pas utilisées pour la substitution
Symptôme : Vous définissez DATABASE_URL=postgres://user:pass@db:5432/mydb dans env_file, mais le fichier Compose affiche toujours ${DATABASE_URL} non résolu dans cmd ou entrypoint.
Pourquoi : env_file injecte des variables dans le conteneur au moment de l'exécution ; il n'est pas disponible pour l'analyseur du fichier Compose. L'analyseur n'utilise que les variables d'environnement du shell et le fichier .env.
Récupération : Déplacez la variable vers le fichier .env si vous en avez besoin pour l'interpolation, ou référencez-la directement dans la commande avec une valeur codée en dur. N'oubliez pas que les variables .env ne sont pas automatiquement injectées dans les conteneurs ; vous devez également les lister sous environment: ou env_file: si l'application en a besoin.
3. Fuite de variables sensibles via docker inspect ou docker compose config
Symptôme : L'exécution de docker inspect affiche des mots de passe, des jetons ou des clés API dans la liste d'environnement. Ces valeurs peuvent se retrouver dans les journaux CI, les bundles de support ou les tableaux de bord de surveillance.
Pourquoi : Transmettre des secrets via environment: ou env_file: les rend visibles à toute personne ayant accès à l'API Docker sur l'hôte. Ils sont également stockés dans les métadonnées du conteneur.
Récupération :
- Utilisez les secrets Docker si vous êtes en mode Swarm, ou des fichiers de secrets montés par liaison pour les projets Compose. Par exemple :
services:
web:
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt
- Au minimum, utilisez un gestionnaire de secrets externe et injectez les secrets via le point d'entrée du conteneur à partir d'un fichier monté.
- Évitez d'imprimer la sortie
envdans la CI. Utilisezdocker inspect --format '{{range .Config.Env}}{{println .}}{{end}}' | grep -v 'PASSWORD\|TOKEN\|KEY'pour filtrer les clés sensibles, mais ne faites jamais confiance aux filtres seuls ; la valeur peut apparaître dans les lignes de commande ou les contrôles de santé.
4. L'environnement hôte remplace .env de manière inattendue
Symptôme : Dans la CI ou sur la machine d'un développeur, le même fichier Compose résout une variable différemment que sur une autre machine. docker compose config affiche une valeur différente de celle du .env.
Pourquoi : Les variables d'environnement du shell ont une précédence plus élevée que les variables du fichier .env. Si un développeur a DEBUG=true exporté dans son shell, cela remplace DEBUG=false dans .env. Cela conduit à un comportement incohérent entre les environnements.
Récupération :
- Exécutez
docker compose configlocalement et dans l'environnement pour comparer. Si vous avez besoin d'une construction déterministe, désactivez les variables en conflit ou utilisezenv -i docker compose configpour voir la base de référence. - Documentez quelles variables peuvent être remplacées par le shell et lesquelles doivent provenir de
.envou des secrets CI. - Envisagez d'utiliser un répertoire de projet dédié sans variables shell héritées.
5. Les modifications de .env ne sont pas prises en compte après docker compose up
Symptôme : Vous modifiez .env, exécutez docker compose up -d, mais les conteneurs en cours d'exécution utilisent toujours les anciennes valeurs.
Pourquoi : Les variables d'environnement sont fixées à la création du conteneur. Mettre à jour .env seul ne recrée pas les conteneurs existants. docker compose up -d ne recrée que les conteneurs avec une image ou une configuration de service modifiée ; il peut ne pas détecter un changement dans l'environnement résolu si le fichier Compose lui-même n'a pas changé.
Récupération :
- Forcer la recréation du service affecté :
docker compose up -d --force-recreate <service>. - Ou arrêtez et supprimez les conteneurs, puis redémarrez :
docker compose down && docker compose up -d. - Avant de forcer la recréation, exécutez
docker compose configpour confirmer les nouvelles valeurs résolues.
6. Utilisation incorrecte des modificateurs :ro ou :rw dans les chemins env_file
Symptôme : Compose ne parvient pas à analyser une entrée env_file comme ./env/common.env:ro.
Pourquoi : env_file ne prend pas en charge les modificateurs de montage ; cette syntaxe est uniquement pour les volumes. C'est une erreur courante de copier-coller.
Récupération : Supprimez le modificateur : - ./env/common.env. Si vous avez besoin que le fichier soit en lecture seule à l'intérieur du conteneur, placez-le dans un montage lié et sourcez-le via env_file en utilisant le chemin du conteneur.
Liste de contrôle opérationnelle
Utilisez cette liste de contrôle avant et après toute modification des variables d'environnement Docker Compose. Elle suppose d'abord un environnement de préproduction similaire à la production, puis la production. Chaque élément a un responsable et une fréquence de révision.
Avant la modification (responsable : ingénieur DevOps ou propriétaire du service ; révision : à chaque déploiement)
- [ ] Enregistrez la sortie actuelle de
docker compose versionetdocker compose configdans un fichier journal daté. - [ ] Identifiez tous les services affectés par la modification de variable à l'aide de
docker compose config --services. - [ ] Confirmez que la variable n'est pas codée en dur dans l'image ou remplacée par une source de précédence plus élevée.
- [ ] Vérifiez l'utilisation de
${VAR}dans les sectionscommand:,entrypoint:,healthcheck:ouenvironment:. - [ ] Assurez-vous que les secrets ne sont pas actuellement dans
.envouenv_fileversionné dans le contrôle de source. - [ ] Définissez la valeur attendue et une commande de validation pour chaque variable (par exemple,
docker compose exec web env | grep API_URLdoit renvoyerhttp://api:8080). - [ ] Sauvegardez le fichier Compose actuel et
.envdans un emplacement versionné (par exemple, une étiquette Git ou un magasin d'artefacts).
Après la modification (responsable : même ingénieur ; vérifier dans les 30 minutes suivant le déploiement)
- [ ] Exécutez
docker compose configet comparez avec la sortie attendue. - [ ] Démarrez ou recréez le service avec
docker compose up -d --force-recreate <service>. - [ ] Vérifiez l'état du service avec
docker compose ps(recherchezrunning (healthy)). - [ ] Inspectez les journaux pour détecter les erreurs liées aux variables manquantes ou invalides.
- [ ] Exécutez la commande de validation pour la variable modifiée.
- [ ] Effectuez un test de redémarrage :
docker compose stop <service> && docker compose start <service>et revalidez. - [ ] Confirmez qu'aucune valeur sensible n'apparaît dans la sortie de
docker inspectou les journaux. - [ ] Mettez à jour les manuels d'exploitation ou la documentation avec la nouvelle variable et sa source de vérité.
Plan de restauration (responsable : ingénieur d'astreinte ; à exécuter si les vérifications post-modification échouent)
- [ ] Annulez les modifications du fichier
.envet Compose à partir du contrôle de version. - [ ] Exécutez
docker compose up -d --force-recreateavec la configuration précédente. - [ ] Vérifiez que les valeurs de variable précédentes connues comme bonnes sont restaurées.
- [ ] Informez l'équipe et enregistrez le calendrier de l'incident.
Cette liste de contrôle ne remplace pas les tests CI. Ajoutez une étape de pipeline qui exécute docker compose config --quiet et un test de fumée qui vérifie qu'un service peut récupérer une variable connue. Par exemple, un conteneur Nginx peut exposer un en-tête avec add_header X-App-Env $APP_ENV;, et le test vérifie que l'en-tête est égal à staging ou production.
Pièges courants et comment les éviter
Les pièges suivants apparaissent de manière répétée dans les projets Compose du monde réel. Chacun comprend un exemple concret et une mesure préventive.
Piège 1 : Supposer que les variables env_file sont disponibles pour l'interpolation Compose
Comme indiqué, env_file est uniquement pour l'exécution. Les développeurs écrivent souvent :
services:
app:
image: myapp
env_file:
- ./app.env
environment:
- LOG_LEVEL=${LOG_LEVEL}
Ils s'attendent à ce que ${LOG_LEVEL} soit résolu à partir de app.env. Ce n'est pas le cas. La bonne approche est de mettre LOG_LEVEL dans .env ou de l'exporter dans le shell, et éventuellement de le lister également dans env_file si l'application en a besoin à l'intérieur du conteneur. Un modèle plus sûr est d'éviter env_file pour les variables utilisées dans le fichier Compose ; utilisez .env pour l'interpolation et environment: pour les valeurs d'exécution explicites.
Piège 2 : Mélanger les fichiers .env de développement et de production
Utiliser un seul .env pour tous les environnements entraîne des fuites de secrets dans les conteneurs de développement ou des valeurs de production dans les tests locaux. Utilisez plutôt des fichiers spécifiques à l'environnement :
.env.staging
.env.production
Déployez avec docker compose --env-file .env.production up -d. Conservez ces fichiers dans un magasin sécurisé, pas dans le référentiel Git.
Piège 3 : Remplacer une variable dans environment: mais oublier la dépendance dans un autre service
Supposons que les services web et worker aient tous deux besoin de API_URL. Vous modifiez API_URL uniquement pour web. Le worker conserve silencieusement l'ancienne URL, provoquant un comportement incohérent. Pour éviter cela, définissez des variables partagées dans un .env commun et référencez-les dans les deux services, ou utilisez des ancres YAML et une source unique de vérité. Exécutez docker compose config et recherchez le nom de la variable pour voir toutes les occurrences :
docker compose config | grep -n "API_URL"
Piège 4 : Ne pas mettre entre guillemets les valeurs de variable avec des caractères spéciaux
L'analyse YAML peut mal interpréter les valeurs contenant :, #, - ou des espaces. Par exemple :
environment:
- GREETING=Hello, World! # échoue car la virgule et l'espace sont acceptables ? En fait la virgule est acceptable, mais le `!` peut causer des problèmes dans certains analyseurs YAML. Mieux vaut mettre entre guillemets :
- GREETING="Hello, World!"
- DSN=postgres://user:pass@db:5432/mydb?sslmode=disable # le deux-points peut causer des problèmes ? En fait le deux-points est acceptable s'il n'y a pas d'espace après. Mais `#` pourrait commenter le reste.
Mettez toujours entre guillemets les valeurs contenant des caractères spéciaux, y compris *, ?, [, ], {, }, #, &, !, |, >, %, @ et les accents graves. Utilisez des guillemets simples pour une interprétation littérale et des guillemets doubles lorsque vous devez inclure une interpolation. Exemple :
environment:
- "PASSWORD=pa$$w0rd" # les guillemets doubles empêchent $ d'interpoler
- 'REGEX=[0-9]+'
Piège 5 : S'appuyer sur les valeurs par défaut sans vérifier
Compose autorise les valeurs par défaut avec ${VAR:-default}. Cela peut masquer les fautes de frappe. Si vous vous attendez à ce que POSTGRES_USER soit admin mais que le .env contient POSTGRES_USR=admin (faute de frappe), la variable se résout par défaut postgres, ce qui peut fonctionner mais avec le mauvais utilisateur. Évitez les valeurs par défaut pour les variables critiques, ou ajoutez une étape de validation :
environment:
- POSTGRES_USER=${POSTGRES_USER:?POSTGRES_USER is required}
La syntaxe :? force une erreur si la variable est vide, rendant les erreurs visibles.
Piège 6 : Stocker des secrets dans docker-compose.override.yml et le versionner
Le fichier de remplacement est pratique pour les remplacements locaux mais contient souvent des secrets comme les mots de passe de base de données. S'il est versionné dans le contrôle de source, les secrets fuient. Utilisez un .gitignore pour les fichiers de remplacement contenant des secrets, ou mieux, ne mettez jamais de secrets dans les fichiers Compose ; utilisez les secrets Docker (Swarm) ou des fichiers montés par liaison depuis un emplacement sécurisé.
Conclusion
Les variables d'environnement sont le plan de contrôle des applications conteneurisées. Dans Docker Compose, les gérer correctement nécessite de comprendre l'ordre de résolution, de séparer la configuration au moment de la construction de celle au moment de l'exécution, et de vérifier les modifications avec des commandes observables. Les commandes de cet article fournissent un flux de travail reproductible : inventorier l'état actuel, apporter une modification ciblée, valider la configuration résolue, observer le conteneur en cours d'exécution et disposer d'un chemin de restauration.
Commencez par une modification de variable à faible risque dans un environnement hors production. Exécutez docker compose config pour voir l'effet, recréez le service et confirmez que le conteneur voit la valeur attendue à l'aide de docker compose exec. Au fur et à mesure que vous gagnez en confiance, étendez la liste de contrôle à toute la configuration pilotée par l'environnement.
Le principe fondamental est la sécurité opérationnelle : n'injectez jamais de secrets à partir de fichiers non chiffrés, ne modifiez jamais plusieurs variables interdépendantes à la fois et vérifiez toujours avec une commande concrète que le conteneur en cours d'exécution correspond à la configuration déclarée. Avec ces pratiques, les variables d'environnement deviennent un mécanisme de configuration fiable, vérifiable et réversible.