Introduction
Docker Compose est un outil puissant pour définir et exécuter des applications multi-conteneurs. Avec un seul fichier YAML, vous pouvez configurer des services, des réseaux et des volumes, et tout démarrer avec une seule commande. Mais lorsque les variables d'environnement sont mal configurées, les résultats peuvent être déroutants : les conteneurs ne démarrent pas, les services se connectent à la mauvaise base de données ou des secrets fuient dans les journaux.
Cet article se concentre sur les erreurs concrètes et réalistes que rencontrent les développeurs et les opérateurs lorsqu'ils utilisent des variables d'environnement dans Docker Compose. Plutôt que de la théorie abstraite, vous trouverez des commandes précises, des extraits de configuration et des sorties attendues. Chaque section cible un mode de défaillance courant, explique pourquoi il se produit et montre comment le corriger en toute sécurité. À la fin, vous disposerez d'un flux de travail de diagnostic reproductible qui va de l'observation à la résolution vérifiée, sans suppositions.
Nous aborderons l'inventaire des versions et de l'environnement, les chemins de configuration sûrs, la vérification et le diagnostic, les modes de défaillance et la récupération, une liste de contrôle opérationnelle complète et les pièges courants. Tout au long, l'accent est mis sur la sécurité opérationnelle : observer avant de modifier, limiter le rayon d'impact, protéger les secrets, vérifier les résultats et documenter les chemins de récupération.
Inventaire des versions et de l'environnement
Avant de modifier quoi que ce soit, sachez exactement ce que vous exécutez. La syntaxe et le comportement de Docker Compose ont évolué ; une variable qui fonctionne dans une version peut se comporter différemment dans une autre. Commencez par enregistrer les versions exactes et inspecter l'état actuel de votre projet.
Vérifier les versions de Docker et Compose
Exécutez :
docker --version
docker compose version
Sortie attendue :
Docker version 24.0.7, build afdd53b
Docker Compose version v2.23.0-desktop.1
Les anciennes versions de Compose (le binaire autonome docker-compose) utilisent une syntaxe de commande différente et peuvent ne pas prendre en charge les fonctionnalités plus récentes comme env_file avec interpolation ou certaines options de vérification de l'état de santé. Si vous êtes en version 1.x, envisagez de migrer vers le plugin Compose v2 (docker compose) pour une meilleure compatibilité et des performances accrues.
Inventorier l'environnement actuel des conteneurs
Pour voir ce qui est réellement en cours d'exécution, utilisez :
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
Exemple de sortie :
NAMES STATUS PORTS
web Up 2 minutes 0.0.0.0:8080->80/tcp
db Up 2 minutes 5432/tcp
Pour un examen plus approfondi des variables d'environnement d'un conteneur spécifique, exécutez :
docker inspect <conteneur> --format '{{range .Config.Env}}{{println .}}{{end}}'
Cela affiche les variables exactement telles que Docker les voit, y compris celles qui ont été substituées par Compose. Si vous avez un projet Compose en cours d'exécution, utilisez :
docker compose ps
docker compose logs -f <service>
docker compose exec <service> sh
La commande exec vous donne un shell à l'intérieur du conteneur pour inspecter directement les variables, par exemple echo $DATABASE_URL.
Persistance des données : volumes vs montages liés
Une erreur courante consiste à perdre des données parce qu'elles ont été écrites dans la couche inscriptible du conteneur au lieu d'un volume. Avant de modifier la configuration, confirmez où résident les données.
- Un volume nommé, par exemple
app_data:/var/lib/app, est géré par Docker et persiste lors de la recréation des conteneurs. - Un montage lié, par exemple
./data:/var/lib/app, mappe directement un répertoire hôte et est utile pour le développement, mais peut souffrir de problèmes de permissions lorsque le chemin hôte n'existe pas ou a un mauvais propriétaire.
Exécutez un test de redémarrage pour vérifier la persistance :
docker compose stop
docker compose up -d
# Vérifiez si les données sont toujours là
docker compose exec app ls /var/lib/app
Si les données sont manquantes, le service écrivait dans la couche du conteneur ; définissez un volume dans votre fichier Compose et refaites le test.
Rayon d'impact et récupération
Documentez la modification envisagée dans un endroit visible par vos collègues (un ticket, une branche git, un commentaire dans le fichier Compose). Effectuez toujours une modification ciblée à la fois et vérifiez avant de continuer. Par exemple, si vous soupçonnez qu'une variable est incorrecte, modifiez uniquement cette variable, puis exécutez docker compose up -d ; ne modifiez pas simultanément les ports, les réseaux et les politiques de redémarrage.
Chemin de configuration sûr
De nombreuses erreurs liées aux variables proviennent d'un placement incorrect des valeurs ou d'une mauvaise syntaxe. Cette section présente la manière sûre de définir et d'utiliser les variables d'environnement dans Compose.
Où les variables peuvent être définies
Docker Compose prend en charge plusieurs sources pour les variables d'environnement, avec une priorité spécifique (de la plus élevée à la plus basse) :
- Variables d'environnement du shell (définies dans le terminal avant d'exécuter
docker compose) - La section
environmentdu fichier Compose - L'option
env_file - Un fichier
.envdans le répertoire du projet - Les valeurs par défaut de
docker-compose.yml(par exemple${VAR:-défaut})
Une erreur courante est de s'attendre à ce qu'une valeur d'une source soit visible alors qu'une autre source la remplace. Par exemple, si vous définissez POSTGRES_PASSWORD dans votre shell et le définissez également dans la section environment, la valeur du shell ne l'emporte que si la section environment ne le définit pas également. En réalité, Compose v2 résout les variables au moment de l'analyse en utilisant l'environnement du shell et le fichier .env ; les valeurs de environment sont transmises au conteneur telles quelles après interpolation. Soyons précis : les entrées environment: peuvent référencer ${VAR} et seront substituées en utilisant l'environnement du shell ou le fichier .env.
Bonnes pratiques pour une configuration sûre
- Utilisez un fichier
.envpour le développement local et l'intégration continue (CI). Cela garde les variables hors du fichier Compose principal et peut être ignoré par git s'il contient des données sensibles. - Ne committez jamais de véritables identifiants. Utilisez des espaces réservés dans les fichiers d'exemple (par exemple
DB_PASSWORD=change-me) et documentez comment les définir. - Utilisez
env_filepour de grands ensembles de variables partagées entre services, mais sachez que les variables deenv_fileremplacent celles deenvironment(l'opposé des variables du shell). - Préférez le mappage explicite dans
environmentpour les paramètres critiques afin de les rendre visibles dans le fichier Compose.
Un exemple de configuration sûre
Supposons que vous ayez un service web qui a besoin d'une chaîne de connexion à une base de données. Une configuration fragile ressemble à ceci :
services:
web:
image: myapp:latest
environment:
DATABASE_URL: postgres://user:secret@db:5432/mydb
Coder en dur des identifiants dans YAML est dangereux et empêche la réutilisation. Une meilleure approche :
À la racine du projet, créez un fichier .env :
DB_USER=appuser
DB_PASSWORD=changeme
DB_HOST=db
DB_PORT=5432
DB_NAME=mydb
Dans votre docker-compose.yml, utilisez l'interpolation :
services:
web:
image: myapp:latest
environment:
DATABASE_URL: postgres://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}
db:
image: postgres:15
environment:
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ${DB_NAME}
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
Exécutez docker compose config pour prévisualiser la configuration entièrement rendue :
docker compose config
Cela devrait afficher le YAML avec les valeurs réelles substituées. Vérifiez que DATABASE_URL montre la bonne chaîne. Si une variable est manquante, Compose générera une erreur ou substituera une chaîne vide, ce qui peut entraîner des échecs subtils.
Variables d'environnement et secrets
Pour les valeurs sensibles comme les mots de passe de base de données ou les clés API, Docker recommande d'utiliser des secrets. Dans Compose, vous pouvez définir des secrets dans la section secrets et les référencer dans le conteneur sous forme de fichiers sous /run/secrets/. Par exemple :
services:
db:
image: postgres:15
secrets:
- db_password
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
db_password:
file: ./db_password.txt
Cela évite de mettre le mot de passe directement dans l'environnement ou le fichier Compose. L'image Postgres prend en charge la variante _FILE pour plusieurs variables, ce qui est plus sécurisé.
Vérification et diagnostic
Après toute modification, vous devez vérifier que la variable a l'effet escompté à l'intérieur du conteneur en cours d'exécution. Cette section présente des commandes de diagnostic concrètes et comment interpréter leur sortie.
Inspecter les variables dans un conteneur en cours d'exécution
Le contrôle le plus direct est d'exécuter env dans le conteneur :
docker compose exec web env | sort
Recherchez la variable que vous avez définie. Par exemple, vous devriez voir DATABASE_URL=postgres://appuser:changeme@db:5432/mydb. Si vous voyez une valeur vide ou le littéral ${DB_USER}, l'interpolation a échoué car la variable n'était pas définie dans le shell ou le fichier .env.
Consulter les journaux pour les erreurs de configuration
Les conteneurs échouent souvent au démarrage lorsque des variables requises sont manquantes. Utilisez :
docker compose logs --tail=50 web
Messages d'erreur courants :
Error: Database is uninitialized and superuser password is not specified.(Postgres)panic: environment variable DATABASE_URL must be set(applications Go)KeyError: 'SECRET_KEY'(applications Python)
Si vous voyez de telles erreurs, le conteneur s'est probablement arrêté. Vérifiez son état avec docker compose ps ; un conteneur arrêté affiche Exited (1) dans la colonne d'état.
Utiliser docker inspect pour un diagnostic approfondi
docker inspect vous donne le tableau d'environnement exact :
docker inspect <id-conteneur> --format '{{range .Config.Env}}{{println .}}{{end}}'
Cela est utile lorsque vous soupçonnez que Compose ne substitue pas les variables comme prévu. La sortie est une liste plate de paires KEY=value ; notez que les valeurs ne sont pas masquées, alors faites attention à ne pas exposer de secrets dans les journaux ou les captures d'écran.
Vérifications de l'état de santé et de l'état de préparation
Un conteneur peut démarrer mais échouer à se connecter à une dépendance parce que celle-ci n'est pas prête. Utilisez des vérifications de l'état de santé pour rendre vos services résilients. Exemple pour un service web :
services:
web:
image: myapp:latest
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 5
Ensuite, vérifiez l'état de santé :
docker compose ps
Un service sain affiche Up (healthy) dans la colonne d'état.
Test de redémarrage pour la persistance
Comme mentionné précédemment, redémarrez le conteneur pour vous assurer que la configuration persiste :
docker compose restart
Vérifiez ensuite que l'application voit toujours les fichiers et variables attendus. Si une variable est définie uniquement dans le shell et que vous redémarrez sans elle, la valeur sera perdue. Définissez toujours les variables dans le fichier Compose ou .env pour des redémarrages cohérents.
Modes de défaillance et récupération
Cette section décrit des modes de défaillance spécifiques liés aux variables d'environnement, comment les reconnaître et comment les récupérer.
Défaillance 1 : Variable non substituée - ${VAR} littéral apparaît
Symptôme : Les journaux de l'application montrent littéralement DATABASE_URL=postgres://${DB_USER}:..., ou le conteneur échoue avec « chaîne de connexion invalide ».
Cause : La variable DB_USER n'est pas définie dans le shell ou le fichier .env, et aucune valeur par défaut n'a été fournie dans le fichier Compose. Compose laisse la chaîne intacte.
Récupération :
- Assurez-vous que le fichier
.envexiste et contient la variable. - Exécutez
docker compose configpour vérifier l'interpolation. Si vous voyez${DB_USER}dans la sortie, la variable n'est pas définie. - Exportez la variable dans le shell ou ajoutez-la au
.env, puis exécutez à nouveaudocker compose up -d.
Défaillance 2 : Mauvaise valeur en raison de la priorité
Symptôme : Une variable a une valeur différente de celle attendue, provoquant des échecs de connexion ou un comportement erroné.
Cause : La même variable est définie à plusieurs endroits (shell, .env, environment, env_file), et la priorité est mal comprise.
Récupération :
- Exécutez
docker compose configpour voir les valeurs résolues. - Tracez la source de la valeur en utilisant la chaîne de priorité. Supprimez les définitions en double pour simplifier.
- Documentez la source prévue pour chaque variable dans un README.
Défaillance 3 : Secrets exposés dans le fichier Compose ou l'environnement
Symptôme : Les identifiants sont visibles dans docker inspect ou dans le fichier Compose, qui est commité dans git.
Cause : Secrets codés en dur.
Récupération :
- Déplacez les secrets vers un fichier séparé (par exemple
.envou les secrets Docker). - Référencez-les via l'interpolation ou les variables
_FILE. - Faites pivoter immédiatement les identifiants exposés.
- Ajoutez
.envau.gitignores'il contient des secrets, et fournissez unsample.envavec des espaces réservés.
Défaillance 4 : Variable requise manquante - le conteneur se termine immédiatement
Symptôme : docker compose up démarre, mais le service se termine avec le code 1 et les journaux montrent une erreur de variable manquante.
Cause : L'application attend une variable d'environnement qui n'est pas fournie.
Récupération :
- Vérifiez
docker compose logs <service>pour le message d'erreur. - Ajoutez la variable à la section
environmentou au fichier.env. - Redémarrez :
docker compose up -d. - Vérifiez avec
docker compose exec <service> env.
Défaillance 5 : Variable définie mais le service ne parvient toujours pas à se connecter
Symptôme : L'application ne peut pas atteindre une base de données ou un autre service même si la variable semble correcte.
Cause : Problèmes de réseau, service non prêt ou mauvais nom d'hôte.
Récupération :
- Assurez-vous que le nom du service dans le fichier Compose correspond au nom d'hôte utilisé dans la chaîne de connexion. Les noms de service Compose sont résolubles par DNS.
- Ajoutez
depends_onavec des vérifications de l'état de santé pour imposer l'ordre de démarrage. - Vérifiez l'isolation réseau : les services sur le réseau par défaut devraient pouvoir se joindre par nom. Si vous avez défini des réseaux personnalisés, assurez-vous que les deux services sont sur le même réseau.
- Depuis l'intérieur du conteneur, testez la connectivité :
docker compose exec web ping db(si ping est disponible) ou utiliseznc -zv db 5432.
Pièges courants et comment les éviter
Au-delà des défaillances spécifiques, plusieurs erreurs récurrentes trompent même les utilisateurs expérimentés. Comprendre ces pièges fait gagner du temps et prévient les incidents en production.
Piège 1 : Mélanger les variables .env et du shell de manière incohérente
Pourquoi cela arrive : Les développeurs définissent des variables dans leur shell pour une session et oublient de mettre à jour .env pour les autres. Lorsque la personne suivante exécute le projet, les variables sont manquantes.
Comment éviter : Utilisez .env comme source unique de vérité pour le développement local. Documentez que les développeurs doivent exécuter source .env si nécessaire, mais mieux vaut s'appuyer sur le chargement automatique de .env par Compose depuis le répertoire du projet. Pour la CI, définissez les variables dans l'environnement de la CI.
Piège 2 : Utiliser env_file de manière incorrecte
Pourquoi cela arrive : Les utilisateurs pensent que env_file est identique à .env, mais ils ont des rôles différents. env_file injecte des variables dans le conteneur au moment de l'exécution ; .env est utilisé par Compose pour l'interpolation dans le fichier Compose lui-même.
Comment éviter : Utilisez env_file uniquement lorsque vous devez passer un ensemble de variables à un conteneur depuis un fichier. Utilisez .env pour les valeurs qui doivent être interpolées dans le fichier Compose. Gardez-les séparés pour éviter toute confusion. Si vous avez besoin des deux, vous pouvez spécifier plusieurs entrées env_file.
Piège 3 : Oublier de citer les valeurs avec des caractères spéciaux
Pourquoi cela arrive : YAML est sensible aux caractères spéciaux comme #, :, {}, [], *, &, etc. Une valeur non citée peut être analysée de manière incorrecte.
Exemple :
environment:
- PASSWORD=pa$$word # faux, $$ peut être interprété
- PASSWORD: 'pa$$word' # correct
Comment éviter : Citez toujours les valeurs qui contiennent des caractères spéciaux. Utilisez des guillemets simples pour empêcher toute expansion de variable dans YAML, ou des guillemets doubles si vous avez besoin de séquences d'échappement. Mieux encore, utilisez un fichier .env où les guillemets ne sont pas nécessaires.
Piège 4 : Dépendre des variables d'environnement de l'hôte en production
Pourquoi cela arrive : Les développeurs testent avec des variables exportées dans leur shell, puis déploient en production sans les définir, provoquant des échecs.
Comment éviter : En production, définissez toutes les variables requises dans l'orchestrateur (par exemple, fichier Docker Compose, secrets Kubernetes ou système de gestion de configuration). Ne dépendez jamais des exports du shell dans un environnement de production. Utilisez un pipeline CI/CD qui injecte les variables depuis un magasin de secrets.
Piège 5 : Ne pas valider le fichier Compose avant de l'appliquer
Pourquoi cela arrive : Les développeurs modifient le YAML et exécutent docker compose up, pour voir une erreur de syntaxe ou un comportement inattendu.
Comment éviter : Exécutez toujours docker compose config après avoir modifié le fichier Compose. Cela valide la syntaxe et montre le résultat interpolé. S'il y a une erreur, elle sera signalée immédiatement. De plus, vous pouvez utiliser docker compose config --quiet pour supprimer la sortie et vérifier uniquement les erreurs.
Piège 6 : Ignorer la politique de redémarrage et les changements d'environnement
Pourquoi cela arrive : Modifier les variables d'environnement dans le fichier Compose ne recrée pas automatiquement les conteneurs s'ils sont déjà en cours d'exécution ; vous devez exécuter docker compose up -d pour appliquer les changements, et même là, Compose peut ne pas recréer le conteneur s'il pense que rien n'a changé. Les changements d'environnement déclenchent la recréation, mais si vous utilisez docker compose start à la place, les variables ne sont pas appliquées.
Comment éviter : Après avoir modifié les variables, exécutez docker compose up -d et vérifiez que le conteneur a été recréé (regardez l'ID du conteneur ou la durée de fonctionnement). Sinon, utilisez docker compose up --force-recreate -d pour forcer la recréation.
Liste de contrôle opérationnelle
Utilisez cette liste de contrôle comme procédure reproductible pour diagnostiquer les problèmes de variables d'environnement dans Docker Compose. Chaque élément est une action concrète avec une commande de vérification.
Phase 1 : Observer et inventorier
- [ ] Exécutez
docker --versionetdocker compose versionet enregistrez la sortie. - [ ] Exécutez
docker compose pspour voir l'état des services. - [ ] Pour un conteneur spécifique, exécutez
docker inspect <conteneur> --format '{{range .Config.Env}}{{println .}}{{end}}'pour lister les variables d'environnement. (Faites attention aux secrets ; masquez-les si vous les journalisez.) - [ ] Vérifiez le fichier Compose et tous les fichiers
.envdans le répertoire du projet. Exécutezdocker compose configpour voir la configuration complète rendue.
Phase 2 : Identifier le problème
- [ ] Comparez la valeur attendue de la variable avec la valeur réelle de
docker compose configoudocker inspect. - [ ] Vérifiez les journaux pour les erreurs de variables manquantes :
docker compose logs --tail=100 <service>. - [ ] Déterminez si la variable est définie à plusieurs endroits et quelle source a la priorité.
Phase 3 : Effectuer une modification ciblée
- [ ] Modifiez uniquement la variable en question. Utilisez la source la plus sûre :
.envpour l'interpolation,environmentpour les valeurs directes du conteneur, ou les secrets pour les identifiants. - [ ] Si vous utilisez des secrets, assurez-vous que le fichier de secret existe et est référencé correctement.
- [ ] Validez la modification avec
docker compose config.
Phase 4 : Appliquer et vérifier
- [ ] Appliquez la modification :
docker compose up -d(ou--force-recreatesi nécessaire). - [ ] Vérifiez l'état du service :
docker compose ps. - [ ] Vérifiez la variable à l'intérieur du conteneur :
docker compose exec <service> printenv <VAR>. - [ ] Testez la fonctionnalité de l'application qui dépend de la variable (par exemple, se connecter à la base de données).
Phase 5 : Documenter et récupérer
- [ ] Enregistrez la modification dans un fichier sous contrôle de version (par exemple, mettez à jour
.env.examplesi applicable). - [ ] Mettez à jour les procédures ou la documentation avec le bon paramètre de variable.
- [ ] Si la modification casse quelque chose, revenez en arrière : restaurez la valeur précédente, exécutez
docker compose up -det vérifiez le comportement d'origine. - [ ] Informez l'équipe de la modification et des actions requises (par exemple, ils peuvent avoir besoin de récupérer le dernier
.env).
Chaque étape doit être suivie dans l'ordre, et aucune étape ne doit être sautée. Cette liste de contrôle peut être adaptée au flux de travail de votre équipe, mais le principe de base reste : observer, modifier une chose, vérifier, documenter.
Conclusion
Les variables d'environnement sont une partie petite mais critique de la configuration de Docker Compose. Une seule variable manquante ou incorrecte peut faire tomber toute une pile, pourtant ces problèmes résultent souvent d'erreurs simples et évitables. En suivant les procédures de diagnostic et de récupération décrites ici, vous pouvez résoudre rapidement et en toute sécurité les problèmes liés aux variables.
Les points clés à retenir :
- Commencez toujours par un inventaire des versions et de l'état : sachez ce qui s'exécute et d'où viennent les variables.
- Utilisez un chemin de configuration sûr : préférez
.envpour l'interpolation et les secrets pour les identifiants. - Vérifiez chaque modification avec
docker compose config, les journaux etprintenvà l'intérieur du conteneur. - Comprenez les modes de défaillance : variable non substituée, mauvaise priorité, secrets exposés, variables manquantes et problèmes de connectivité.
- Évitez les pièges courants : sources incohérentes, citation YAML, dépendance à l'hôte et saut de validation.
- Suivez la liste de contrôle opérationnelle pour standardiser votre réponse.
N'oubliez pas que la sécurité opérationnelle est primordiale : ne faites pas plusieurs modifications à la fois, protégez les valeurs sensibles et ayez toujours un chemin de récupération documenté. Avec de la pratique, vous serez capable de diagnostiquer et de corriger les erreurs de variables d'environnement dans Docker Compose avec confiance, réduisant les temps d'arrêt et la frustration.
Comme prochaine étape, choisissez l'un de vos projets Compose existants et parcourez la liste de contrôle. Comparez la configuration rendue avec vos attentes et corrigez toute divergence. Ensuite, mettez en place une simple vérification de l'état de santé et un test de redémarrage pour vous assurer que vos services sont robustes. Enfin, examinez votre approche de gestion des secrets et sortez les identifiants des variables d'environnement en clair lorsque c'est possible. Ce faisant, vous renforcerez votre configuration Compose et prendrez l'habitude de vérifier avant de faire confiance.