## Introduction

Docker Compose simplifie le développement multi-conteneurs, mais les déploiements en production exigent plus qu’un simple `docker compose up` fonctionnel. Un fichier Compose mal configuré, une mauvaise correspondance de volumes ou une gestion des secrets non sécurisée peuvent provoquer des pannes, des pertes de données ou des failles de sécurité. Ce guide aborde les erreurs courantes de configuration de Docker Compose en production, avec des exemples pratiques et des étapes de récupération.

Vous apprendrez à identifier les problèmes de version et d’environnement, à valider les configurations avant le déploiement, à diagnostiquer les échecs et à effectuer un retour en arrière en toute sécurité. Chaque section comprend des commandes concrètes, les sorties attendues et les signaux d’échec pour vous aider à passer du problème observé au résultat vérifié.

L’objectif est la sécurité opérationnelle : observer avant de modifier, limiter le rayon d’impact, utiliser des variables d’environnement plutôt que des secrets en clair, vérifier le résultat et documenter les procédures de récupération avant qu’un incident ne force une décision précipitée.

## Inventaire des versions et de l’environnement

Avant toute modification, établissez précisément ce que vous exécutez. Un incident de production provient souvent d’une inadéquation entre le format du fichier Compose, le moteur Docker et la version du plugin Docker Compose. Vérifiez d’abord les versions installées :

```bash
docker --version
# Docker version 24.0.7, build afdd53b

docker compose version
# Docker Compose version v2.23.0-desktop.1
```

Si votre fichier Compose spécifie une clé `version:`, assurez-vous qu’elle est compatible avec votre plugin Compose. Depuis Compose v2, la clé `version` est obsolète et ignorée, mais la supprimer peut perturber les outils plus anciens. Maintenez le format de fichier à jour en utilisant le schéma le plus récent sans clé de version, sauf si vous devez prendre en charge des systèmes hérités.

Ensuite, faites l’inventaire des conteneurs en cours d’exécution et de leur état de santé :

```bash
docker compose ps
# NAME                IMAGE               COMMAND                  SERVICE             CREATED             STATUS              PORTS
# myapp-web-1         myapp/web:1.2.0     "nginx -g 'daemon of…"   web                 2 hours ago         Up 2 hours          0.0.0.0:8080->80/tcp
# myapp-db-1          postgres:16.1       "docker-entrypoint.s…"   db                  2 hours ago         Up 2 hours          5432/tcp
```

Si un conteneur est en mauvaise santé ou redémarre, inspectez-le. Utilisez le champ de statut de santé intégré de Docker pour un aperçu rapide, puis vérifiez le nombre de redémarrages séparément :

```bash
docker ps --filter name=myapp-web-1 --format '{{.Names}} {{.HealthStatus}}'
# myapp-web-1 healthy

docker inspect myapp-web-1 --format '{{.State.RestartCount}}'
# 0
```

Capturez les journaux pour identifier les erreurs :

```bash
docker compose logs web --tail 100
```

### Vérification de la persistance des données

Une erreur courante en production est de stocker les données applicatives dans le système de fichiers du conteneur. Lorsque le conteneur est recréé, les données sont perdues. Confirmez toujours où vivent les données :

```yaml
services:
  db:
    image: postgres:16.1
    volumes:
      - db_data:/var/lib/postgresql/data
volumes:
  db_data:
```

Ici, `db_data` est un volume nommé géré par Docker. Il persiste à travers les reconstructions de conteneurs. Alternativement, un montage de type bind `./data:/var/lib/postgresql/data` mappe un répertoire hôte mais peut introduire des problèmes de permissions et de portabilité.

Testez la persistance avec un redémarrage :

```bash
docker compose stop db
docker compose up -d db
docker compose exec db ls /var/lib/postgresql/data
# Si le répertoire est vide ou ne contient pas les fichiers attendus, les données n’ont pas été persistées correctement.
```

## Chemin de configuration sécurisé

La configuration de production doit être délibérée, versionnée et révisable. Évitez de modifier directement `docker-compose.yml` sur le serveur. Utilisez plutôt des fichiers de surcharge spécifiques à l’environnement et des variables d’environnement pour les valeurs qui changent entre les environnements.

### Utilisation des fichiers de surcharge

Une erreur courante consiste à maintenir plusieurs fichiers Compose presque identiques ou à coder en dur les valeurs de production dans le fichier de base. Utilisez un fichier de base avec des surcharges :

```yaml
# docker-compose.yml
services:
  web:
    image: nginx:1.25
    ports:
      - "80:80"
    environment:
      - LOG_LEVEL=info
```

```yaml
# docker-compose.prod.yml
services:
  web:
    environment:
      - LOG_LEVEL=warn
      - VIRTUAL_HOST=example.com
    deploy:
      replicas: 3
```

Déployez avec :

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

Cela garde le fichier de base propre et les paramètres spécifiques à la production séparés.

### Variables d’environnement et secrets

Ne codez jamais en dur des secrets comme les mots de passe de base de données ou les clés API dans le fichier Compose, même s’il est dans un dépôt privé. Utilisez des variables d’environnement avec un fichier `.env` exclu du contrôle de version :

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

Créez un fichier `.env` (assurez-vous qu’il est dans `.gitignore`) :

```bash
DB_PASSWORD=strongpassword123
```

Pour des données plus sensibles, utilisez Docker secrets (en mode Swarm) ou des gestionnaires de secrets externes. Au minimum, évitez d’imprimer les variables d’environnement dans les journaux :

```bash
docker compose exec db env
# Cela affichera toutes les variables d’environnement, y compris les secrets. À éviter en production.
```

### Limites de ressources

Sans limites de ressources, un conteneur peut épuiser les ressources de l’hôte et affecter les autres services. Définissez des limites dans Compose :

```yaml
services:
  web:
    image: nginx:1.25
    deploy:
      resources:
        limits:
          cpus: '0.50'
          memory: 256M
        reservations:
          cpus: '0.25'
          memory: 128M
```

Notez que `deploy.resources` est ignoré par `docker compose up` et n’est appliqué qu’en mode Swarm (`docker stack deploy`). Pour Compose non-Swarm, utilisez les clés `mem_limit` et `cpus` (obsolètes mais toujours fonctionnelles) ou comptez sur une orchestration externe.

## Vérification et diagnostic

Après le déploiement, vérifiez que l’application fonctionne réellement, pas seulement que les conteneurs tournent.

### Contrôles de santé

Définissez des contrôles de santé pour les services à longue durée de vie afin que Docker puisse les marquer comme défaillants :

```yaml
services:
  web:
    image: nginx:1.25
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 30s
```

Vérifiez le statut :

```bash
docker compose ps
# NAME                STATUS
# myapp-web-1         Up 30 seconds (healthy)
```

Si un conteneur est en mauvaise santé, inspectez la sortie du contrôle de santé :

```bash
docker inspect --format '{{json .State.Health}}' myapp-web-1 | jq
```

### Test de connectivité réseau

Les conteneurs sur le même réseau Compose peuvent se joindre par nom de service. Vérifiez la connectivité depuis un conteneur :

```bash
docker compose exec web curl http://db:5432
# Devrait retourner une réponse ou une connexion refusée si la base de données n’écoute pas.
```

Si le nom de service ne se résout pas, vérifiez que les deux conteneurs sont sur le même réseau :

```bash
docker network inspect myapp_default
```

Tous les services définis dans le même fichier Compose sont automatiquement sur le même réseau par défaut, sauf indication contraire.

### Analyse des journaux

Utilisez les journaux pour diagnostiquer les problèmes. Pour un service spécifique :

```bash
docker compose logs db --since 10m
```

Pour le dépannage, vous pouvez vous attacher à un conteneur :

```bash
docker compose exec web sh
```

À l’intérieur, exécutez des commandes de diagnostic comme `curl`, `ping`, ou `env` (mais évitez d’exposer des secrets).

## Modes de défaillance et récupération

Les erreurs arrivent ; planifiez la récupération avant d’en avoir besoin.

### Retour en arrière de la configuration

Si un nouveau déploiement introduit un problème, le retour en arrière le plus rapide consiste à revenir à la version précédente du fichier Compose et à redéployer :

```bash
# En supposant que vous avez la version précédente dans git
git checkout <previous-commit> -- docker-compose.yml docker-compose.prod.yml
docker compose up -d --force-recreate
```

Alternativement, si vous utilisez des images taguées, revenez à l’étiquette d’image précédente :

```yaml
services:
  web:
    image: nginx:1.24  # version précédemment fonctionnelle
```

Puis exécutez `docker compose up -d`.

### Récupération des données

Si les données sont perdues ou corrompues, restaurez à partir des sauvegardes. Assurez-vous d’avoir des sauvegardes automatisées pour les volumes. Pour un volume nommé, vous pouvez le sauvegarder à l’aide d’un conteneur temporaire :

```bash
docker run --rm -v db_data:/data -v $(pwd):/backup alpine tar czf /backup/db_data_backup.tar.gz -C /data .
```

Restaurez :

```bash
docker run --rm -v db_data:/data -v $(pwd):/backup alpine sh -c "cd /data && tar xzf /backup/db_data_backup.tar.gz"
```

Testez régulièrement les restaurations.

### Pièges courants et comment les éviter

Voici les erreurs fréquentes de Docker Compose en production, leurs causes et les stratégies de récupération.

| Erreur | Pourquoi cela arrive | Comment éviter ou récupérer |
|---|---|---|
| Utiliser l’étiquette d’image `latest` en production | Suppose que la dernière version est stable ; peut introduire des changements cassants de façon inattendue | Épinglez les étiquettes d’image à des versions spécifiques ou des empreintes ; utilisez `docker compose pull` seulement après des tests |
| Exposer des ports de débogage (par exemple 5432 pour PostgreSQL) sur internet | Mauvaise configuration du mappage `ports` | Liez les ports à localhost uniquement : `127.0.0.1:5432:5432` |
| Stocker des secrets en texte clair dans le fichier Compose ou `.env` commité dans git | Commodité, manque de gestion des secrets | Utilisez Docker secrets, des coffres-forts externes, ou au moins `.env` avec des permissions restreintes |
| Exécuter avec `privileged: true` ou des capacités inutiles | Mauvaise compréhension des exigences de sécurité | Évitez le mode privilégié ; n’ajoutez que les capacités requises avec `cap_add` |
| Ignorer la politique `restart: always` | Les conteneurs sortent sur erreur mais ne sont pas redémarrés | Définissez des politiques de redémarrage appropriées : `restart: unless-stopped` pour les services qui doivent toujours fonctionner |
| Ne pas définir de limites de ressources | Un conteneur peut consommer tout le CPU/mémoire | Définissez `deploy.resources.limits` (Swarm) ou `mem_limit`/`cpus` (Compose) |
| Utiliser `docker compose down` sans l’option `-v` pendant le débogage | `down` supprime les conteneurs et réseaux mais pas les volumes par défaut ; supprimer manuellement les volumes entraîne une perte de données | Spécifiez toujours `-v` uniquement lorsque vous avez l’intention de supprimer les volumes ; sauvegardez d’abord |
| Écraser des fichiers hôtes avec des montages bind | Des erreurs de chemin de montage bind peuvent écraser des répertoires hôtes | Utilisez des volumes nommés pour la persistance, des montages bind uniquement pour le code/config que vous partagez intentionnellement |

## Liste de vérification des opérations

Utilisez cette liste avant et après chaque déploiement en production pour détecter les erreurs courantes.

Avant le déploiement :

- [ ] Vérifiez les versions de Docker et Compose : `docker version && docker compose version`
- [ ] Exécutez `docker compose config` pour valider la syntaxe du fichier Compose et fusionner les surcharges
- [ ] Vérifiez les secrets codés en dur ; remplacez-les par des variables d’environnement ou des secrets
- [ ] Confirmez que les étiquettes d’image sont épinglées (pas `latest`)
- [ ] Révisez les montages de volumes et assurez-vous que les chemins de persistance des données sont corrects
- [ ] Définissez des limites de ressources pour chaque service
- [ ] Définissez des contrôles de santé pour les services critiques
- [ ] Sauvegardez les données existantes (surtout si vous modifiez des volumes)
- [ ] Ayez un plan de retour en arrière (étiquette d’image précédente ou version du fichier Compose)

Après le déploiement :

- [ ] Exécutez `docker compose ps` et confirmez que tous les services sont opérationnels et en bonne santé
- [ ] Vérifiez les journaux : `docker compose logs --tail=200`
- [ ] Vérifiez la fonctionnalité de l’application depuis un point de terminaison externe (le cas échéant)
- [ ] Surveillez l’utilisation des ressources : `docker stats`
- [ ] Confirmez qu’aucun port inattendu n’est exposé : `docker port <container>`
- [ ] Testez un redémarrage de conteneur pour vous assurer de la persistance des données : `docker compose restart <service>`
- [ ] Documentez tout écart et mettez à jour les procédures

### Responsabilité et cadence de révision

Pour chaque décision majeure (par exemple, promotion d’étiquette d’image, rotation des secrets, changement de limites de ressources), assignez un responsable unique. Par exemple :

- Promotion d’étiquette d’image : Priya Shah, responsable ingénierie - révisée chaque semaine
- Rotation des secrets : John Doe, membre de l’équipe DevOps - révisée chaque mois
- Ajustements des limites de ressources : Maria Garcia, ingénieure infrastructure - révisés chaque trimestre

Ces responsables sont chargés de vérifier le changement et de mettre à jour la documentation.

## Conclusion

Éviter les erreurs de configuration de Docker Compose en production exige une approche disciplinée : comprendre votre environnement, utiliser des pratiques de configuration sûres, vérifier rigoureusement et planifier la récupération. Les commandes et exemples de ce guide constituent un point de départ pour construire des déploiements résilients.

Commencez par appliquer une seule pratique, comme l’épinglage des étiquettes d’image ou l’ajout de contrôles de santé, et observez l’impact. Ensuite, élargissez à une liste de vérification complète du déploiement. Rappelez-vous que la sécurité en production repose sur l’observabilité, le principe du moindre privilège et des procédures de retour en arrière documentées.

Avec ces outils, vous pouvez déployer en toute confiance et récupérer rapidement lorsque les choses tournent mal.