## Introduction

Les variables d'environnement sont le moyen le plus courant de configurer les services Docker Compose, mais des règles de priorité subtiles, la portée du fichier .env et les différences d'expansion du shell provoquent de fréquentes interruptions. Ce guide explique l'architecture des variables d'environnement Docker Compose, fournit des exemples pratiques pour transmettre des valeurs en toute sécurité et vous donne des commandes de diagnostic pour vérifier la configuration finale avant sa mise en production.

Vous apprendrez :

- Comment Compose résout les variables à partir du shell, du fichier .env, de `environment:`, de `env_file:` et des valeurs par défaut de l'image, ainsi que l'ordre de priorité exact.
- Comment inspecter l'environnement fusionné d'un conteneur en cours d'exécution, déboguer les valeurs manquantes ou incorrectes et tester les modifications sans redéploiement.
- Comment structurer la configuration pour plusieurs environnements, garder les secrets hors du contrôle de code source et éviter les erreurs courantes comme les collisions de noms de variables ou l'utilisation d'un mauvais fichier .env.
- Comment concevoir un plan de reprise et une liste de vérification qui rendent les défaillances visibles avant qu'elles n'affectent les utilisateurs.

Cet article s'adresse aux développeurs, consultants DevOps et équipes techniques de startups qui gèrent Docker Compose en développement, préproduction ou production. Nous mettons l'accent sur la sécurité opérationnelle : observer avant de modifier, limiter le rayon d'impact, utiliser des espaces réservés plutôt que des secrets, vérifier le résultat et documenter comment récupérer lorsque l'état attendu n'est pas atteint.

## Inventaire des versions et de l'environnement

Avant de modifier une configuration Compose, établissez une base de référence. Nommez les composants concernés, la plage de versions prise en charge, les prérequis, une observation en lecture seule, le plus petit changement justifié et la commande qui vérifie le résultat.

Commencez par ces commandes pour capturer l'état actuel :

```bash
docker version --format '{{.Server.Version}}'
docker compose version
```

Exemples de sortie attendue :
```
Docker version 24.0.6, build ed223bc
Docker Compose version v2.21.0
```

Vérifiez que la version de votre fichier Compose est compatible. Depuis Compose v2, la clé de niveau supérieur `version:` est facultative et ignorée, mais elle peut encore apparaître dans des projets plus anciens. Exécutez :

```bash
docker compose config --quiet
```
Si le fichier est valide, il n'y a pas de sortie et le code de sortie est 0. S'il y a une erreur de syntaxe, Compose imprime un message descriptif et se termine avec un code non nul.

Listez les conteneurs en cours d'exécution et leur état avec :

```bash
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
```

Pour un projet Compose, utilisez :

```bash
docker compose ps
```

Ces commandes montrent quels services sont en cours d'exécution, leur santé et les ports publiés. Elles sont en lecture seule et sûres à exécuter à tout moment.

Consultez les journaux d'un service spécifique avec :

```bash
docker compose logs -f app
```
Cela diffuse les derniers journaux du service `app`. Recherchez les erreurs liées à l'environnement telles que `database connection refused` ou `missing required variable`.

Inspectez l'environnement d'un conteneur en cours d'exécution sans rien modifier :

```bash
docker compose exec app printenv
```

Cela imprime toutes les variables d'environnement visibles à l'intérieur du conteneur, y compris les valeurs définies par Compose, l'image et toute redéfinition au moment de l'exécution. Utilisez-le pour vérifier que les variables sont présentes et ont les valeurs attendues.

Pour les données stockées sur fichier, confirmez où les volumes sont montés avant d'apporter des modifications. Utilisez :

```bash
docker inspect -f '{{ json .Mounts }}' app_container
```

ou pour un service Compose :

```bash
docker compose exec app sh -c 'df -h /var/lib/data && ls -la /var/lib/data'
```

Un volume nommé tel que `app_data:/var/lib/data` est géré par Docker et est plus facile à réutiliser lors des reconstructions de conteneurs. Un montage de type bind tel que `./data:/var/lib/data` mappe un répertoire hôte et est utile pour le développement local, mais peut causer des problèmes de permissions, de portabilité et de sauvegarde si le chemin n'est pas identique sur chaque machine.

Un petit test local de type production doit inclure un test de redémarrage :

```bash
docker compose stop app
docker compose up -d app
docker compose exec app printenv DBPASSWORD
```

Si les données disparaissent ou si la variable change après le redémarrage, le service écrivait probablement dans la couche inscriptible du conteneur ou la variable n'était définie que dans une session shell ponctuelle. Confirmez la persistance avec les commandes ci-dessus avant de vous fier à la configuration.

## Chemin de configuration sûr

Les variables d'environnement dans Compose sont résolues à partir de plusieurs sources, et l'ordre de priorité est critique. Compose fusionne les valeurs dans cet ordre, de la priorité la plus basse à la plus haute :

1. Environnement par défaut de l'image, le cas échéant (défini par l'instruction `ENV` du Dockerfile).
2. Valeurs d'un `env_file` listé dans la définition du service (plusieurs fichiers peuvent être listés ; les fichiers ultérieurs remplacent les précédents).
3. Valeurs de l'environnement shell où vous exécutez `docker compose`.
4. Valeurs d'un fichier `.env` dans le répertoire du projet (le même répertoire que le fichier Compose).
5. Valeurs définies explicitement dans le `environment:` du service ou `environment:` avec la syntaxe de mappage.

Dans `environment:`, les variables définies sans interpolation (par exemple, `DBHOST: db`) ont toujours la priorité sur celles du shell ou du `.env`. Si vous utilisez la forme abrégée `DBHOST` sans valeur, Compose cherche `DBHOST` dans l'environnement shell ou le fichier `.env` et utilise cette valeur ; s'il ne la trouve pas, la variable est supprimée ou définie sur une chaîne vide selon la version de Compose (dans la v2, elle est supprimée à moins qu'une valeur par défaut ne soit spécifiée).

Voici un exemple concret de priorité :

Fichier Compose `docker-compose.yml` :
```yaml
services:
  web:
    image: nginx:1.25
    env_file:
      - common.env
    environment:
      GREETING: "hello from compose file"
      DBHOST: db
    ports:
      - "8080:80"
```

`common.env` :
```
GREETING=hello from env_file
DBHOST=old_db
DBPORT=5432
```

Shell avant d'exécuter `docker compose up` :
```bash
export GREETING="hello from shell"
export DBHOST="shell_db"
```

Fichier `.env` dans le répertoire du projet :
```
GREETING=hello from dotenv
DBHOST=dotenv_db
```

Après `docker compose up -d`, inspectez le conteneur :

```bash
docker compose exec web printenv GREETING
```
Sortie :
```
hello from compose file
```

Parce que `GREETING` est défini explicitement dans `environment:`, il gagne. La variable `DBHOST` est également explicitement définie sur `db`, donc elle gagne aussi sur le shell et le `.env`. La variable `DBPORT` n'est présente que dans `common.env`, donc elle devient `5432` à l'intérieur du conteneur.

L'utilisation de `env_file:` est utile pour garder de nombreuses variables dans un fichier séparé, mais sachez qu'elle s'applique à un seul service, pas à l'ensemble du projet. Le fichier `.env` à la racine du projet est utilisé uniquement pour la substitution de variables dans le fichier Compose, et non automatiquement transmis aux conteneurs.

Pour les secrets comme les mots de passe et les clés API, ne les mettez pas dans le fichier Compose ni dans un `env_file` ordinaire versionné. Utilisez plutôt les secrets Docker (pour Swarm) ou un fichier `.env` dédié qui est ignoré par Git. Un motif plus sûr :

```yaml
services:
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
```

Définissez ensuite `DB_PASSWORD` dans votre fichier `.env` local (non versionné) ou dans votre gestionnaire de secrets CI/CD. Cela garde le secret hors du dépôt et permet des valeurs par environnement.

Pour des tests locaux de type production, utilisez un fichier de surcharge :

```bash
docker compose -f docker-compose.yml -f docker-compose.override.yml up -d
```

Où `docker-compose.override.yml` contient des surcharges spécifiques à l'environnement. Validez la configuration fusionnée finale avant de l'appliquer :

```bash
docker compose config
```

Cela imprime le fichier Compose entièrement résolu, y compris toutes les substitutions de variables d'environnement et les fichiers fusionnés. Examinez-le attentivement pour détecter les secrets divulgués ou les valeurs incorrectes.

## Vérification et diagnostics

Les commandes de cette section vous aident à détecter et diagnostiquer les problèmes de variables d'environnement sans causer de perturbations supplémentaires.

Pour voir l'environnement à l'intérieur d'un conteneur en cours d'exécution, utilisez `docker compose exec` :

```bash
docker compose exec web env
```

Cela montre toutes les variables d'environnement et leurs valeurs. Filtrez pour une variable spécifique :

```bash
docker compose exec web env | grep DBHOST
```

Inspectez la configuration du conteneur pour voir les variables d'environnement telles qu'enregistrées par Docker :

```bash
docker inspect --format '{{range .Config.Env}}{{println .}}{{end}}' web_container
```

Cela est utile lorsque le conteneur a été démarré avec `docker run` ou via d'anciennes versions de Compose, et que `exec` n'est pas disponible.

Vérifiez les journaux pour les échecs de démarrage liés à l'environnement :

```bash
docker compose logs web | grep -i "error\|fatal\|denied"
```

Si l'application le permet, essayez de vous connecter aux dépendances depuis l'intérieur du conteneur :

```bash
docker compose exec web sh -c 'nc -zv db 5432'
```

Remplacez `nc` par `telnet` ou `curl` selon l'image. Cela vérifie que le nom d'hôte `db` se résout et que le port est accessible, ce qui dépend souvent de `DBHOST` et `DBPORT`.

Lors du dépannage de la priorité des variables, exécutez `docker compose config` pour voir le bloc d'environnement exact qui sera transmis au conteneur :

```bash
docker compose config | grep -A 10 "environment:"
```

Cela montre les valeurs résolues, vous aidant à identifier quelle source a fourni une variable. Si une variable est totalement absente, vérifiez qu'elle est définie dans la source attendue et orthographiée correctement (y compris la casse).

Enfin, testez une modification proposée avant de l'appliquer en utilisant `docker compose run` avec une surcharge temporaire :

```bash
docker compose run --rm -e DBHOST=test_db web sh -c 'echo $DBHOST'
```

Cela exécute un conteneur ponctuel avec l'environnement modifié et imprime la valeur, sans affecter le service en cours d'exécution.

## Modes de défaillance et reprise

Même avec une planification minutieuse, des défaillances surviennent. Voici les modes de défaillance courants liés aux variables d'environnement et comment récupérer.

**Variable manquante au démarrage du conteneur**

Cause : La variable n'est définie dans aucune source, ou le fichier `.env` est manquant ou mal nommé.

Détection : Le service se termine immédiatement ; les journaux affichent `required environment variable` ou `connection refused`.

Reprise :
1. Exécutez `docker compose logs <service>` pour identifier la variable manquante.
2. Vérifiez `docker compose config` pour voir si la variable apparaît dans le bloc d'environnement.
3. Ajoutez la variable à la source appropriée (`.env`, `environment:` ou gestionnaire de secrets).
4. Recréez le service avec `docker compose up -d --force-recreate <service>`.

**Valeur incorrecte due à la priorité**

Cause : La variable est définie à plusieurs endroits, et une source de priorité supérieure écrase la valeur prévue.

Détection : Le conteneur fonctionne mais se comporte de manière inattendue (par exemple, se connecte à une base de données de préproduction en production).

Reprise :
1. Exécutez `docker compose exec <service> printenv <VARIABLE>` pour voir la valeur réelle.
2. Exécutez `docker compose config` et retracez la variable jusqu'à sa source.
3. Supprimez ou ajustez la source de priorité inférieure, ou définissez explicitement la variable dans `environment:` avec la valeur correcte.
4. Redémarrez le service.

**Secrets accidentellement validés dans le contrôle de version**

Cause : Un fichier `.env` contenant des secrets a été ajouté à Git, ou un secret a été codé en dur dans `docker-compose.yml`.

Détection : Découvert lors d'une revue de code, d'une analyse de sécurité ou après une fuite de justificatifs.

Reprise :
1. Faites pivoter immédiatement le secret divulgué.
2. Supprimez le secret du fichier et ajoutez des entrées `.gitignore` appropriées (par exemple, `.env`, `*.env`).
3. Utilisez un outil de gestion des secrets ou les secrets Docker pour les valeurs sensibles.
4. Purgez le secret de l'historique Git si nécessaire (par exemple, en utilisant `git filter-repo`).

**Emplacements de fichiers `.env` incohérents**

Cause : Différents membres de l'équipe ou pipelines CI/CD exécutent `docker compose` à partir de répertoires différents, donc le fichier `.env` n'est pas trouvé ou un autre est utilisé.

Détection : Les configurations diffèrent entre les environnements malgré des fichiers Compose identiques.

Reprise :
1. Standardisez le placement de `.env` dans le même répertoire que le fichier Compose.
2. Utilisez le drapeau `--env-file` pour spécifier un chemin explicite : `docker compose --env-file ./config/prod.env up -d`.
3. Documentez les emplacements de fichiers attendus dans le README du projet.

**Collision de noms de variables entre les services Compose**

Cause : Plusieurs services définissent le même nom de variable avec des valeurs différentes, et en raison des surcharges ou du comportement de fusion, la mauvaise valeur est transmise.

Détection : Un service échoue alors qu'un autre fonctionne, et les journaux montrent que la variable a une valeur inattendue.

Reprise :
1. Inspectez chaque service séparément : `docker compose exec <service> printenv <VAR>`.
2. Utilisez des noms de variables uniques par service ou exploitez les profils Compose et les fichiers de surcharge pour segmenter les configurations.
3. Mettez à jour les définitions de service et redéployez.

**Environnement hôte affectant involontairement Compose**

Cause : Le shell où vous exécutez `docker compose` contient de nombreuses variables exportées, dont certaines sont utilisées par Compose pour la substitution dans le fichier Compose, modifiant ainsi les valeurs de manière inattendue.

Détection : `docker compose config` montre des valeurs substituées qui diffèrent de ce que vous attendiez.

Reprise :
1. Désactivez la variable incriminée dans le shell : `unset <VAR>`.
2. Soyez explicite dans le fichier Compose : utilisez `${VAR:-default}` pour fournir une valeur de repli.
3. Utilisez un shell propre ou un script wrapper qui n'exporte que les variables requises.

## Liste de vérification opérationnelle

Utilisez cette liste pour vérifier et maintenir votre configuration de variables d'environnement Docker Compose. Chaque élément comprend la commande ou l'observation, le rôle responsable et la fréquence de révision.

| # | Tâche | Commande / Observation | Rôle responsable | Fréquence de révision |
|---|---|---|---|---|
| 1 | Vérifier les versions de Docker et Compose | `docker version && docker compose version` | Ingénieur plateforme | Trimestrielle |
| 2 | Valider la syntaxe du fichier Compose et résoudre les variables | `docker compose config > /dev/null && echo Valid` | Développeur | Avant chaque fusion |
| 3 | Inspecter l'environnement du conteneur en cours d'exécution | `docker compose exec <service> printenv` | Développeur | À chaque déploiement ou changement de configuration |
| 4 | Vérifier que les secrets ne sont pas dans les journaux ou la sortie de configuration | `docker compose config | grep -i 'password\|secret\|key'` | Responsable sécurité | Hebdomadaire |
| 5 | Confirmer la persistance des données et de la configuration après redémarrage | `docker compose stop && docker compose up -d && docker compose exec <service> ls /data` | Ingénieur DevOps | Mensuelle |
| 6 | Examiner le contenu et les permissions d'accès du fichier `.env` | `ls -la .env && cat .env` (avec prudence) | Chef d'équipe | Bi-hebdomadaire |
| 7 | Tester la reprise après un scénario de variable manquante | Retirer intentionnellement une variable en préproduction, observer l'échec, puis restaurer et vérifier la correction | Ingénieur QA | Avant chaque mise en production |
| 8 | Auditer les règles de priorité des variables d'environnement avec l'équipe | Revoir la documentation et exécuter un test rapide de priorité | Rédacteur technique / Chef | Annuelle |

Exemple de propriété : Priya Shah, responsable de l'ingénierie, est responsable de la revue finale des changements de variables d'environnement avant le déploiement en production, et elle réexamine les résultats de la liste lors de la revue opérationnelle mensuelle.

## Pièges courants et comment les éviter

Voici des nuances supplémentaires qui font trébucher les praticiens.

**Utiliser `.env` pour l'environnement du conteneur**

Une erreur répandue consiste à supposer que les variables du fichier `.env` du projet sont automatiquement transmises à tous les services. Ce n'est pas le cas. Le fichier `.env` est utilisé uniquement pour l'interpolation dans le fichier Compose. Pour transmettre des variables aux conteneurs, utilisez `environment:` ou `env_file:`.

**Ne pas mettre entre guillemets les valeurs des variables dans `environment:`**

YAML peut interpréter incorrectement les valeurs contenant des caractères spéciaux (comme `:`, `#`, `*`). Mettez toujours les valeurs entre guillemets, surtout si elles contiennent des espaces ou de la ponctuation.

**Mélanger `env_file` et `environment` sans comprendre l'ordre de fusion**

`env_file` est appliqué en premier, puis `environment` écrase. Si vous devez remplacer une seule valeur du fichier, listez-la dans `environment:`.

**Oublier que `docker compose up` ne recharge pas automatiquement les changements de `.env`**

Si vous modifiez `.env` ou `env_file` après que les conteneurs sont en cours d'exécution, vous devez recréer les conteneurs pour que les nouvelles valeurs prennent effet : `docker compose up -d --force-recreate`.

**Utiliser le même nom de variable avec des significations différentes dans différents services**

Cela peut causer de la confusion et des surcharges accidentelles. Utilisez un préfixe de service, par exemple `WEB_DBHOST` vs `WORKER_DBHOST`.

**Dépendre des variables d'environnement de l'hôte dans CI/CD**

Les exécuteurs CI peuvent avoir des variables d'environnement définies qui interfèrent. Utilisez `--env-file` explicite ou définissez toutes les variables nécessaires dans le pipeline, et évitez de dépendre de l'environnement de l'hôte.

## Conclusion

Comprendre l'architecture des variables d'environnement Docker Compose est essentiel pour des déploiements fiables. En connaissant l'ordre de priorité, en utilisant des chemins de configuration sûrs et en vérifiant systématiquement avec des commandes comme `docker compose config` et `docker compose exec printenv`, vous pouvez prévenir de nombreuses défaillances.

Adoptez les pratiques opérationnelles de ce guide : observez toujours l'état actuel, limitez les changements à une variable à la fois, utilisez des espaces réservés et la gestion des secrets, et ayez un plan de reprise. Incluez la liste de vérification opérationnelle dans la routine de votre équipe pour garder les configurations sécurisées et cohérentes.

Prochaine étape : choisissez un service dans votre projet Compose actuel et effectuez les étapes de l'« Inventaire des versions et de l'environnement ». Comparez l'environnement réel avec ce que vous attendiez et corrigez toute divergence. Documentez ensuite les sources de variables correctes pour votre équipe.

Un flux de travail technique fiable rend les défaillances visibles, protège les valeurs sensibles, limite les changements à la ressource prévue et définit la vérification de la reprise avant qu'un incident ne force la décision.