## Introduction Mettre à niveau Docker Compose ne se limite pas à installer un nouveau binaire. Une mise à niveau sécurisée consiste à passer d’un problème observé à un résultat vérifié, sans perdre de données, sans casser les services dépendants et sans faire de suppositions sur le comportement en cours d’exécution. Ce guide fournit des étapes pratiques pour la mise à niveau, la migration, la restauration, le changement de version et la validation de Docker Compose, avec des commandes concrètes et les sorties attendues. Cet article s’adresse aux développeurs, aux consultants DevOps et aux équipes techniques de startups qui gèrent des applications conteneurisées en développement, en préproduction ou en production. Il se concentre sur le flux opérationnel : vérifier les prérequis, capturer l’état actuel, appliquer un changement minimal, vérifier le résultat et savoir comment récupérer en cas de problème. L’objectif est la sécurité opérationnelle. Observez avant de modifier, limitez le rayon d’impact, utilisez des variables d’environnement plutôt que des secrets dans les fichiers de configuration, vérifiez chaque étape et documentez les commandes de récupération avant d’en avoir besoin. Chaque section comprend un exemple pratique pour que vous puissiez suivre sur vos propres systèmes. ## Inventaire des versions et de l’environnement Avant de toucher à un service en cours d’exécution, vous devez disposer d’un inventaire clair de la version de Docker Compose installée, de l’état actif du projet et de l’environnement de déploiement. Cet inventaire vous aide à choisir la bonne voie de mise à niveau et à anticiper les problèmes de compatibilité. ### Vérifier la version actuelle de Docker Compose Exécutez la commande suivante pour voir la version actuellement installée : ```bash docker compose version ``` Exemple de sortie : ```text Docker Compose version v2.24.5 ``` Si vous utilisez l’ancien binaire autonome `docker-compose` (v1), vérifiez avec : ```bash docker-compose version ``` Exemple de sortie : ```text docker-compose version 1.29.2, build 5becea4c ``` Savoir si vous êtes sur la v1 ou la v2 est important car la syntaxe des commandes diffère. Docker Compose v2 est un plugin invoqué sous la forme `docker compose`, tandis que la v1 est un binaire distinct. La plupart des systèmes modernes utilisent la v2, mais les anciens serveurs peuvent encore avoir la v1. Le processus de mise à niveau de la v1 vers la v2 implique l’installation du plugin et éventuellement l’ajustement des scripts qui appellent `docker-compose`. ### Inspecter l’état du projet en cours d’exécution Listez les conteneurs actuels et leur statut : ```bash docker compose ps ``` Exemple de sortie : ```text NAME COMMAND SERVICE STATUS PORTS web-1 "docker-entrypoint.s…" web running 0.0.0.0:8080->80/tcp db-1 "docker-entrypoint.s…" db running 5432/tcp ``` Cela montre les noms des services, les noms des conteneurs et les mappages de ports. Comparez avec votre `docker-compose.yml` pour vous assurer que l’état en cours correspond à la configuration prévue. Consultez les journaux récents pour détecter tout problème en cours : ```bash docker compose logs --tail 50 web ``` Recherchez les messages d’erreur ou les avertissements qui pourraient affecter la mise à niveau. ### Identifier les volumes et le stockage des données La sécurité des données est essentielle lors d’une mise à niveau. Déterminez où sont stockées les données de votre application en inspectant les volumes : ```bash docker volume ls ``` Exemple de sortie : ```text DRIVER VOLUME NAME local myapp_db_data local myapp_uploads ``` Inspectez ensuite un volume pour voir son point de montage et ses étiquettes : ```bash docker volume inspect myapp_db_data ``` Exemple de sortie (partielle) : ```json [ { "CreatedAt": "2024-03-01T12:00:00Z", "Driver": "local", "Labels": { "com.docker.compose.project": "myapp", "com.docker.compose.volume": "db_data" }, "Mountpoint": "/var/lib/docker/volumes/myapp_db_data/_data", "Name": "myapp_db_data", "Options": null, "Scope": "local" } ] ``` Si votre `docker-compose.yml` utilise un montage de type bind, le chemin apparaîtra sous `Mounts` dans `docker inspect` pour le conteneur : ```bash docker inspect db-1 --format '{{ json .Mounts }}' ``` Exemple de sortie : ```json [{"Type":"bind","Source":"/home/user/myapp/data","Destination":"/var/lib/postgresql/data","Mode":"rw","RW":true,"Propagation":"rprivate"}] ``` Notez tous les volumes et montages bind. Lors d’une mise à niveau, les conteneurs peuvent être recréés et si les données sont stockées dans des couches éphémères de conteneur, elles seront perdues. ### Vérifier la persistance des données avec un test de redémarrage Avant toute mise à niveau, effectuez un test de redémarrage contrôlé pour confirmer que les données persistent lors de la recréation du conteneur. Arrêtez et redémarrez un service : ```bash docker compose stop db docker compose start db ``` Vérifiez ensuite que l’application peut toujours lire ses données. Par exemple, s’il s’agit d’une base de données PostgreSQL, exécutez : ```bash docker compose exec db psql -U myuser -c "SELECT count(*) FROM mytable;" ``` Sortie attendue : ```text count ------- 123 (1 row) ``` Si le compte est nul ou si la table est absente, les données étaient probablement stockées dans la couche du conteneur et vous devez corriger la configuration du volume avant de continuer. ## Parcours de configuration sécurisé Un parcours de configuration sécurisé signifie modifier votre `docker-compose.yml` en comprenant clairement l’effet de chaque changement et en ayant un plan de restauration. Évitez d’apporter plusieurs modifications sans rapport à la fois. ### Sauvegarder la configuration actuelle Faites une copie horodatée de votre `docker-compose.yml` actuel et de tout fichier `.env` associé : ```bash cp docker-compose.yml docker-compose.yml.bak.$(date +%Y%m%d%H%M%S) ``` Exemple : ```text docker-compose.yml.bak.20250315120000 ``` Sauvegardez également tout fichier `.env` : ```bash cp .env .env.bak.$(date +%Y%m%d%H%M%S) ``` Cela vous permet de restaurer la configuration précédente rapidement si nécessaire. ### Mettre à jour la clé de version du fichier Compose (le cas échéant) Pour les anciens fichiers Compose, la clé de premier niveau `version` était utilisée pour spécifier la version du schéma. Dans Docker Compose v2, cette clé est obsolète mais toujours acceptée pour la compatibilité ascendante. Si vous migrez de la v1 vers la v2, vous pouvez supprimer la clé `version` ou la laisser ; elle sera ignorée. Exemple d’ancien fichier : ```yaml version: '3.8' services: web: image: nginx:1.25 ports: - "8080:80" ``` Vous pouvez supprimer en toute sécurité la ligne `version`. Le nouveau fichier commencerait directement par `services:`. ### Valider la configuration avant de l’appliquer Utilisez la commande config pour analyser et valider votre fichier Compose : ```bash docker compose config ``` Cela affiche la configuration normalisée. S’il y a des erreurs de syntaxe, elles seront signalées. Exemple de sortie réussie (tronquée) : ```yaml name: myapp services: web: image: nginx:1.25 ports: - mode: ingress target: 80 published: "8080" protocol: tcp networks: default: name: myapp_default ``` Vérifiez s’il y a des avertissements ou des changements inattendus dans la sortie. Exécutez également : ```bash docker compose config --quiet ``` Si cette commande se termine avec le code 0 et sans sortie, la configuration est valide. ### Gérer les variables d’environnement en toute sécurité Ne codez jamais en dur des secrets dans `docker-compose.yml`. Utilisez un fichier `.env` pour les variables d’environnement. Par exemple, dans votre fichier Compose : ```yaml services: db: image: postgres:16 environment: POSTGRES_PASSWORD: ${DB_PASSWORD} ``` Créez un fichier `.env` avec la valeur réelle (mais ne validez jamais ce fichier dans le contrôle de version) : ```text DB_PASSWORD=change_me_strong_password ``` Validez que la variable est substituée correctement : ```bash docker compose config | grep POSTGRES_PASSWORD ``` La sortie attendue montre la valeur réelle. Pour éviter d’exposer les secrets dans les journaux, envisagez d’utiliser les secrets Docker en production (Swarm) ou une gestion de secrets externe. ### Appliquer le changement avec une mise à jour progressive ou une recréation Pour un simple changement comme la mise à jour d’une balise d’image, vous pouvez exécuter : ```bash docker compose up -d --no-deps web ``` Cela recrée uniquement le service `web` sans toucher aux dépendances. Si vous devez forcer la recréation : ```bash docker compose up -d --force-recreate web ``` Observez la sortie : ```text [+] Running 1/1 ✔ Container myapp-web-1 Recreated ``` Vérifiez ensuite que le service est sain : ```bash docker compose ps ``` ### Exemple de migration de la v1 vers la v2 Si vous utilisez l’ancien binaire `docker-compose`, migrez vers le plugin v2. Tout d’abord, vérifiez si la v2 est installée : ```bash docker compose version ``` Si elle n’est pas installée, suivez le guide d’installation officiel de Docker pour votre système d’exploitation. Sur Ubuntu, installez le paquet `docker-compose-plugin` : ```bash sudo apt-get update sudo apt-get install docker-compose-plugin ``` Après l’installation, mettez à jour tous les scripts qui appellent `docker-compose` pour utiliser `docker compose` (espace au lieu du trait d’union). Testez avec votre projet : ```bash cd /path/to/project docker compose up -d ``` ## Vérification et diagnostic Après avoir appliqué un changement de configuration ou une mise à niveau, vérifiez que l’application fonctionne correctement. Cela implique de vérifier la santé des services, les journaux et la connectivité. ### Vérifier l’état et la santé des services Utilisez `docker compose ps` pour voir l’état : ```bash docker compose ps ``` Exemple : ```text NAME COMMAND SERVICE STATUS PORTS web-1 "docker-entrypoint.s…" web running (healthy) 0.0.0.0:8080->80/tcp db-1 "docker-entrypoint.s…" db running (healthy) 5432/tcp ``` L’indicateur `(healthy)` apparaît si le conteneur a une vérification de santé définie. Si vos services n’ont pas de vérifications de santé, ajoutez-les à votre fichier Compose pour une meilleure observabilité. Exemple de vérification de santé pour un service web : ```yaml services: web: image: nginx:1.25 healthcheck: test: ["CMD", "curl", "-f", "http://localhost/"] interval: 30s timeout: 10s retries: 3 ``` Après l’ajout, recréez le service : ```bash docker compose up -d web ``` Vérifiez à nouveau. ### Examiner les journaux pour détecter les erreurs Affichez les journaux de services spécifiques : ```bash docker compose logs --tail 100 web ``` Recherchez les erreurs de démarrage, les échecs de connexion ou les erreurs de configuration. Par exemple, une erreur de connexion à la base de données peut apparaître comme : ```text web-1 | [error] 23#23: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.18.0.1, server: localhost, request: "GET / HTTP/1.1", upstream: "http://172.18.0.2:5432/" ``` Cela indique que le service web ne peut pas atteindre la base de données, probablement en raison d’un changement de réseau ou de nom de service. ### Tester la connectivité et les points de terminaison des services Pour les applications web, utilisez `curl` depuis l’hôte ou à l’intérieur d’un autre conteneur. Depuis l’hôte : ```bash curl -I http://localhost:8080 ``` Sortie attendue : ```text HTTP/1.1 200 OK Server: nginx/1.25.3 Date: Sat, 15 Mar 2025 12:00:00 GMT Content-Type: text/html ``` Si vous devez tester depuis le réseau, exécutez un conteneur temporaire : ```bash docker run --rm --network myapp_default curlimages/curl curl -s http://web:80 ``` Remplacez `myapp_default` par le nom du réseau de votre projet (vérifiez avec `docker network ls`). ### Valider la configuration par rapport à l’état en cours d’exécution Comparez la configuration actuelle avec l’état déployé : ```bash docker compose config --services ``` Cela liste tous les services définis. Comparez ensuite avec `docker compose ps --services` pour voir lesquels sont en cours d’exécution. Toute divergence peut indiquer un problème. ### Vérifier l’utilisation des ressources et les performances Utilisez `docker stats` pour surveiller la consommation des ressources : ```bash docker stats --no-stream ``` Exemple de sortie (partielle) : ```text CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS abc123def456 web-1 0.50% 25.5MiB / 1.95GiB 1.28% 1.2kB / 0B 0B / 0B 3 def456abc123 db-1 2.10% 102.4MiB / 1.95GiB 5.12% 850kB / 1.1MB 9.8MB / 12MB 27 ``` Une utilisation anormalement élevée du processeur ou de la mémoire peut indiquer un service mal configuré après la mise à niveau. ## Modes de défaillance et récupération Chaque mise à niveau doit être planifiée en tenant compte des défaillances. Voici les modes de défaillance courants et les étapes de récupération spécifiques. ### Erreur de syntaxe de configuration Si `docker compose up` échoue avec une erreur YAML, revenez à la configuration de sauvegarde. Exemple d’erreur : ```text yaml: line 5: could not find expected ':' ``` Récupération : restaurez le fichier de sauvegarde : ```bash cp docker-compose.yml.bak.YYYYMMDDHHMMSS docker-compose.yml ``` Validez à nouveau : ```bash docker compose config --quiet ``` ### Version d’image incompatible Si la nouvelle version de l’image ne démarre pas en raison de dépendances manquantes ou d’un point d’entrée modifié, vérifiez les journaux puis annulez la balise de l’image. Exemple : vous avez changé `image: myapp:2.0` en `myapp:3.0` et le conteneur se termine avec une erreur. Les journaux montrent : ```text web-1 | Error: Cannot find module 'express' ``` Récupération : remettez la balise d’image à la version précédente dans `docker-compose.yml`, puis exécutez : ```bash docker compose up -d --force-recreate web ``` ### Défaillance de dépendance de service Si un service dépendant ne démarre pas parce qu’un autre service n’est pas sain, vérifiez les vérifications de santé et l’ordre de démarrage. Compose v2 prend en charge `depends_on` avec conditions : ```yaml services: web: depends_on: db: condition: service_healthy ``` Assurez-vous que le service db passe sa vérification de santé. Sinon, inspectez les journaux de db et corrigez le problème sous-jacent. ### Perte de volume ou de données Si après une mise à niveau l’application signale des données manquantes, vérifiez les montages de volume. Utilisez `docker inspect` pour voir les points de montage : ```bash docker inspect db-1 --format '{{ json .Mounts }}' ``` Si le volume est manquant ou pointe vers un emplacement différent, restaurez les données à partir des sauvegardes. Prenez toujours des sauvegardes de volume avant des changements majeurs. Exemple de sauvegarde pour un volume PostgreSQL : ```bash docker run --rm -v myapp_db_data:/data -v $(pwd):/backup alpine tar czf /backup/db_data_backup.tar.gz -C /data . ``` Restauration : ```bash docker run --rm -v myapp_db_data:/data -v $(pwd):/backup alpine sh -c "cd /data && tar xzf /backup/db_data_backup.tar.gz" ``` ### Procédure de restauration Une procédure de restauration générale : 1. Arrêtez les services affectés : ```bash docker compose stop web db ``` 2. Restaurez la configuration précédente à partir de la sauvegarde : ```bash cp docker-compose.yml.bak.TIMESTAMP docker-compose.yml ``` 3. Recréez les services avec l’ancienne configuration : ```bash docker compose up -d --force-recreate ``` 4. Vérifiez que l’application est saine. ## Liste de contrôle opérationnelle Utilisez cette liste de contrôle pour garantir une mise à niveau ou une migration Docker Compose sécurisée. Remplissez les valeurs spécifiques à votre environnement. | Étape | Commande / Action | Résultat attendu | Notes | |------|------------------|-----------------|-------| | 1. Enregistrer la version actuelle | `docker compose version` | La sortie affiche la version (par ex., v2.24.5) | Notez v1 vs v2 | | 2. Capturer l’état en cours | `docker compose ps --services` | Liste des services en cours d’exécution | Comparer à la config | | 3. Sauvegarder la config et l’env | `cp docker-compose.yml docker-compose.yml.bak.$(date +%Y%m%d%H%M%S)` | Fichier créé | Sauvegarder aussi .env | | 4. Sauvegarder les volumes (le cas échéant) | `docker run --rm -v VOLUME:/data -v $(pwd):/backup alpine tar czf /backup/volume_backup.tar.gz -C /data .` | Archive tar créée | Remplacer VOLUME par le nom réel | | 5. Valider la config | `docker compose config --quiet` | Code de sortie 0, aucune sortie | Corriger les erreurs | | 6. Appliquer le changement | `docker compose up -d` ou service spécifique | Services recréés | Utiliser `--no-deps` pour limiter | | 7. Vérifier l’état | `docker compose ps` | Tous les services en cours d’exécution, sains si vérifications définies | Rechercher les redémarrages | | 8. Vérifier les journaux | `docker compose logs --tail 50 SERVICE` | Aucune erreur fatale | Enquêter sur les avertissements | | 9. Tester la fonctionnalité | `curl -I http://localhost:PORT` ou commande appropriée | HTTP 200 ou réponse attendue | Vérifier les points de terminaison critiques | | 10. Surveiller les ressources | `docker stats --no-stream` | CPU et mémoire dans la plage normale | Surveiller les fuites | | 11. Confirmer la persistance des données | Test de redémarrage : `docker compose stop` puis `start` | Données intactes | Si perdues, corriger les volumes | | 12. Documenter le plan de restauration | Écrire les commandes de restauration | Étapes claires sauvegardées | Tester la restauration en préproduction si possible | ### Exemple de liste de contrôle remplie pour un projet exemple Supposons un projet nommé `myapp` avec les services `web` et `db`, utilisant un volume nommé `myapp_db_data`, et mettant à niveau la balise d’image de `web:1.0` à `web:2.0`. 1. Version actuelle : `docker compose version` renvoie `Docker Compose version v2.24.5`. 2. Services en cours : `docker compose ps --services` renvoie `web` et `db`. 3. Sauvegarde de la configuration : `cp docker-compose.yml docker-compose.yml.bak.20250315120000`. 4. Sauvegarde du volume : `docker run --rm -v myapp_db_data:/data -v $(pwd):/backup alpine tar czf /backup/myapp_db_data_backup.tar.gz -C /data .` 5. Valider la configuration : `docker compose config --quiet` ne renvoie aucune erreur. 6. Appliquer le changement : modifier la balise d’image en `web:2.0`, puis `docker compose up -d web`. 7. Vérifier l’état : `docker compose ps` montre `web` en cours et sain. 8. Vérifier les journaux : `docker compose logs --tail 50 web` montre le succès du démarrage. 9. Tester la fonctionnalité : `curl -I http://localhost:8080` renvoie `HTTP/1.1 200 OK`. 10. Surveiller les ressources : `docker stats --no-stream` montre web utilisant 30 Mo de RAM, normal. 11. Confirmer la persistance des données : `docker compose stop` puis `docker compose start`, puis `docker compose exec db psql -U myuser -c "SELECT count(*) FROM mytable;"` renvoie 123. 12. Documenter la restauration : `cp docker-compose.yml.bak.20250315120000 docker-compose.yml && docker compose up -d --force-recreate`. ## Conclusion La mise à niveau et la migration de Docker Compose sont des opérations courantes mais risquées. Une approche systématique réduit les temps d’arrêt et les pertes de données. En inventoriant votre environnement, en sauvegardant la configuration et les données, en validant les changements et en vérifiant la fonctionnalité après chaque étape, vous gardez le contrôle sur le processus. N’oubliez pas de définir la portée de chaque recommandation en fonction de la version, d’observer avant de modifier et d’avoir toujours un plan de restauration. Commencez par une vérification à faible risque sur un environnement de préproduction ou un service non critique, enregistrez l’état actuel, appliquez le changement et comparez le résultat au signal attendu. Avec ces pratiques, les mises à niveau de Docker Compose deviennent prévisibles et sûres, même en production. Utilisez la liste de contrôle comme un document vivant qui évolue avec votre infrastructure et l’expérience de votre équipe. Pour approfondir, explorez la documentation officielle de Docker sur la référence du fichier Compose, la mise en réseau et les volumes, et envisagez d’automatiser ces étapes avec des pipelines CI/CD dans votre flux de travail de développement.