## Introduction Docker Compose Watch offre aux développeurs une boucle de rétroaction rapide en reconstruisant et en redémarrant les services lorsque les fichiers sources changent. Mais dans tout projet non trivial, vous devez aussi savoir quand les choses tournent mal : un plantage de service, un échec de build, un montage mal configuré ou une limite de ressources. La surveillance et les alertes transforment Compose Watch en un composant fiable de votre flux de travail opérationnel. Ce guide détaille une mise en œuvre pratique de la surveillance, des alertes, des tableaux de bord et de la réponse aux incidents pour Docker Compose Watch. Il suppose que vous êtes à l'aise avec les bases de Docker et Compose, et se concentre sur la couche opérationnelle : quoi surveiller, comment détecter les problèmes et comment réagir en toute sécurité. Chaque section comprend des commandes exactes, des extraits de configuration, des sorties attendues et des étapes de récupération. L'objectif est la sécurité opérationnelle : observer avant de modifier, limiter le rayon d'impact, utiliser des espaces réservés au lieu de secrets, vérifier les résultats et documenter les chemins de récupération. Ne traitez pas ceci comme une liste de contrôle à copier-coller ; adaptez les exemples à votre environnement et à vos contraintes de version. ## Inventaire des versions et de l'environnement Avant de surveiller quoi que ce soit, sachez ce que vous exécutez. Une règle de surveillance qui suppose une mauvaise version ou topologie manquera des défaillances ou vous submergera de fausses alarmes. Commencez par capturer vos versions actuelles de Docker et Compose. Exécutez : ```bash docker version --format '{{.Server.Version}}' docker compose version ``` Exemple de sortie attendue : ```text 24.0.7 Docker Compose version v2.21.0 ``` Ici, `24.0.7` est la version du moteur Docker et `v2.21.0` est la version du plugin Compose. Compose Watch nécessite Docker Compose v2.17.0 ou ultérieur, et l'attribut `watch` n'est pleinement pris en charge qu'avec BuildKit et le format de fichier Compose v2 (généralement `compose.yaml`). Si vous voyez une version plus ancienne, mettez à niveau avant d'activer watch. Ensuite, listez les services de votre projet Compose et leur état : ```bash docker compose ps ``` Exemple de sortie : ```text NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS project-web-1 project-web:latest "gunicorn app:app" web 2 minutes ago Up 2 minutes 0.0.0.0:8000->8000/tcp project-db-1 postgres:15 "docker-entrypoint.s…" db 2 minutes ago Up 2 minutes 5432/tcp ``` Notez les noms de services (`web`, `db`), les noms de conteneurs et l'état de santé. Un `Up` manquant sous STATUS est le premier signal de défaillance. Pour une inspection en lecture seule d'un conteneur suspect, utilisez : ```bash docker inspect project-web-1 --format '{{json .State.Health}}' ``` Sortie attendue (si un healthcheck est défini) : ```json {"Status":"healthy","FailingStreak":0,"Log":[{"Start":"2024-01-01T00:00:00Z","End":"2024-01-01T00:00:05Z","ExitCode":0,"Output":"ok"}]} ``` Si aucun healthcheck n'est défini, le champ est `null`. Vous pourrez en ajouter un plus tard ; nous couvrons cela dans la section Vérification. Enfin, confirmez que vos montages de volumes sont corrects avant toute modification. La perte de données est une défaillance courante de Compose. Utilisez : ```bash docker inspect project-db-1 --format '{{json .Mounts}}' ``` Exemple de sortie : ```json [{"Type":"volume","Name":"project_pgdata","Source":"/var/lib/docker/volumes/project_pgdata/_data","Destination":"/var/lib/postgresql/data","Driver":"local","Mode":"z","RW":true}] ``` Cela montre un volume nommé lié à `/var/lib/postgresql/data`. Si vous attendiez un montage bind vers `./data`, c'est une incohérence. La corriger avant un redémarrage évite des heures de débogage plus tard. ## Chemin de configuration sûr La section `watch` de votre fichier Compose contrôle la façon dont les modifications sont synchronisées. Une règle watch mal configurée peut provoquer des boucles de reconstruction infinies, un va-et-vient des conteneurs ou des synchronisations manquées. Voici une configuration de départ sûre : ```yaml services: web: build: . ports: - "8000:8000" volumes: - .:/app watch: - action: sync path: ./app target: /app ignore: - node_modules/ - .venv/ - action: rebuild path: requirements.txt environment: FLASK_ENV: development ``` Points clés : - Utilisez `action: sync` pour les répertoires où seul le contenu des fichiers change, pas les dépendances. - Utilisez `action: rebuild` pour les fichiers manifestes comme `requirements.txt` ou les modifications du `Dockerfile`. - Incluez toujours une liste `ignore` pour les grands répertoires générés (`node_modules`, `.venv`, `__pycache__`) afin de réduire la charge de synchronisation. Pour vérifier que votre configuration watch est valide, exécutez : ```bash docker compose config --quiet ``` Si la configuration est invalide, cette commande se termine avec un statut non nul et affiche des erreurs sur stderr. Exemple d'erreur de syntaxe : ```text yaml: line 10: did not find expected key ``` Corrigez l'indentation YAML avant de continuer. Testez maintenant manuellement le chemin de synchronisation. Démarrez la pile : ```bash docker compose up --build -d ``` Surveillez les journaux pour le message de démarrage du watcher : ```bash docker compose logs -f web ``` Exemple de ligne de journal : ```text web-1 | [watch] watching /app for changes ``` Déclenchez une synchronisation en modifiant un fichier dans `./app`, par exemple : ```bash echo "print('hello')" >> app/main.py ``` Vous devriez voir le watcher journaliser le changement et synchroniser le fichier sans redémarrer le conteneur. Si au contraire le conteneur redémarre ou se reconstruit, vous avez le mauvais type d'`action`. ## Vérification et diagnostics Après avoir configuré watch, vérifiez que votre application se comporte correctement sous les actions de synchronisation et de reconstruction. La première étape consiste à définir un healthcheck à l'intérieur de votre service. Pour une application web Python, ajoutez à `compose.yaml` : ```yaml services: web: # ... healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 10s timeout: 5s retries: 3 start_period: 30s ``` Ce healthcheck exécute `curl -f` contre un endpoint `/health` toutes les 10 secondes, considère le conteneur comme non sain après 3 échecs consécutifs, et attend 30 secondes avant de commencer les vérifications au démarrage. Appliquez le changement et recréez le service : ```bash docker compose up -d web ``` Vérifiez l'état de santé : ```bash docker inspect --format='{{.State.Health.Status}}' project-web-1 ``` Sortie attendue : ```text healthy ``` Si elle indique `unhealthy`, inspectez les journaux du healthcheck : ```bash docker inspect --format='{{json .State.Health.Log}}' project-web-1 | jq ``` Cela montre chaque tentative de healthcheck avec les codes de sortie et la sortie. Une défaillance courante est que l'endpoint renvoie 404 parce que la route n'est pas définie. Pour des diagnostics plus approfondis, attachez-vous à un conteneur en cours d'exécution sans l'arrêter : ```bash docker compose exec web sh ``` Dans le conteneur, vérifiez que vos fichiers ont été correctement synchronisés : ```bash ls -la /app ``` Comparez les horodatages avec vos fichiers hôtes. Si un fichier est manquant ou obsolète, la synchronisation watch ignore peut-être le bon chemin. Revérifiez vos motifs `ignore` et le chemin `target`. Enfin, testez la persistance du système de fichiers du conteneur. Arrêtez le conteneur, recréez-le et voyez si les données survivent : ```bash docker compose stop web docker compose up -d web docker compose exec web ls /app/data ``` Si le répertoire est vide, vos données ont été écrites dans le système de fichiers éphémère du conteneur. Déplacez ce chemin vers un volume ou un montage bind comme décrit dans la section inventaire. ## Surveillance et métriques Docker Compose Watch lui-même n'expose pas de métriques, mais vous pouvez surveiller les conteneurs et les événements watch en combinant les métriques intégrées de Docker avec des alertes basées sur les journaux. Cette section montre une configuration minimale utilisant cAdvisor, Prometheus et Alertmanager, le tout exécuté via Compose. Ajoutez une pile de surveillance à votre `compose.yaml` : ```yaml services: cadvisor: image: gcr.io/cadvisor/cadvisor:v0.47.2 ports: - "8080:8080" volumes: - /:/rootfs:ro - /var/run:/var/run:ro - /sys:/sys:ro - /var/lib/docker/:/var/lib/docker:ro depends_on: - web prometheus: image: prom/prometheus:v2.47.2 ports: - "9090:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml depends_on: - cadvisor alertmanager: image: prom/alertmanager:v0.26.0 ports: - "9093:9093" volumes: - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml ``` Créez `prometheus.yml` avec une configuration de scrape pour cAdvisor : ```yaml global: scrape_interval: 15s scrape_configs: - job_name: 'cadvisor' static_configs: - targets: ['cadvisor:8080'] - job_name: 'node-exporter' static_configs: - targets: ['node-exporter:9100'] ``` Ajoutez une alerte de redémarrage de conteneur à `alertrules.yml` (chargé par Prometheus) : ```yaml groups: - name: container-alerts rules: - alert: ContainerKilled expr: time() - container_last_seen{name=~"project-web-.*"} > 60 for: 1m labels: severity: critical annotations: summary: "Container {{ $labels.name }} has been down for more than 1 minute" ``` Cette alerte se déclenche lorsqu'un conteneur correspondant à `project-web-.*` n'a pas été vu pendant 60 secondes, avec une période de grâce d'1 minute. Dans `alertmanager.yml`, routez les alertes vers un e-mail ou Slack. Testez l'alerte en arrêtant le conteneur web : ```bash docker compose stop web ``` En environ 2 minutes (60s de métrique plus la clause `for` d'1m), Prometheus affichera l'alerte dans `http://localhost:9090/alerts`, et Alertmanager enverra une notification. ## Tableau de bord et visualisation Un tableau de bord vous aide à repérer rapidement les anomalies. Utilisez Grafana pour visualiser les métriques de cAdvisor. Ajoutez Grafana à votre pile Compose : ```yaml grafana: image: grafana/grafana:10.1.5 ports: - "3000:3000" environment: GF_SECURITY_ADMIN_PASSWORD: admin volumes: - grafana-storage:/var/lib/grafana depends_on: - prometheus ``` Démarrez la pile et accédez à Grafana sur `http://localhost:3000` (connectez-vous avec `admin` / `admin`, changez-le immédiatement). Ajoutez Prometheus comme source de données avec l'URL `http://prometheus:9090`. Créez un nouveau tableau de bord et ajoutez les panneaux suivants en utilisant des requêtes Prometheus : 1. **Utilisation CPU par conteneur** : ```promql rate(container_cpu_usage_seconds_total{name=~"project-.*"}[5m]) ``` 2. **Utilisation mémoire** : ```promql container_memory_usage_bytes{name=~"project-.*"} ``` 3. **Nombre de redémarrages** (critique pour les reconstructions déclenchées par watch) : ```promql increase(container_restart_count{name=~"project-.*"}[1h]) ``` 4. **Utilisation du système de fichiers** (la synchronisation watch peut remplir le disque) : ```promql container_fs_usage_bytes{name=~"project-.*"} ``` Définissez des seuils d'alerte sur le tableau de bord. Par exemple, un nombre de redémarrages supérieur à 5 au cours de la dernière heure suggère une boucle de reconstruction watch ; enquêtez immédiatement. ## Modes de défaillance et récupération Voici les modes de défaillance courants avec Docker Compose Watch et comment les récupérer. ### 1. Le watch ne déclenche pas de synchronisations ou de reconstructions **Symptôme** : Vous modifiez un fichier, mais le contenu du conteneur ne change pas ; aucune entrée de journal du watcher. **Cause** : Généralement un chemin `watch` mal configuré ou un `target` manquant. Le chemin est relatif au fichier Compose, pas à la racine de l'hôte. De plus, le watcher peut ignorer le fichier à cause d'un motif `ignore`. **Diagnostic** : Exécutez `docker compose config --services` pour vérifier les services et confirmer que la section `watch` est présente. Inspectez le système de fichiers du conteneur par rapport à l'hôte : ```bash docker compose exec web sh -c 'stat /app/file.py' stat host/path/file.py ``` Si les horodatages diffèrent et que le contenu du fichier est obsolète, la synchronisation ne se produit pas. **Récupération** : Corrigez `path` et `target` pour qu'ils correspondent exactement. Supprimez les motifs d'ignore trop larges. Redémarrez le processus watch en exécutant `docker compose watch` au premier plan et observez les journaux. ### 2. Boucle de reconstruction infinie **Symptôme** : Le conteneur se reconstruit et redémarre constamment, consommant du CPU et provoquant des temps d'arrêt. **Cause** : Un fichier qui change pendant le processus de construction (par exemple, un artefact généré) est surveillé, de sorte que le watcher déclenche une autre construction. **Diagnostic** : Vérifiez les journaux watch pour des actions de reconstruction fréquentes : ```bash docker compose logs -f web | grep -i rebuild ``` Si vous voyez des reconstructions répétées, le fichier déclencheur change. **Récupération** : Déplacez les fichiers générés hors du répertoire surveillé ou ajoutez-les à la liste `ignore`. Pour les manifestes, utilisez `action: sync` lorsque c'est possible si une reconstruction n'est pas nécessaire. Alternativement, utilisez un `.dockerignore` pour empêcher le fichier d'être copié dans le contexte de construction. ### 3. Le conteneur se termine après synchronisation en raison d'une dépendance manquante **Symptôme** : Après une synchronisation, le conteneur se termine avec un code non nul. **Cause** : Le fichier synchronisé référence une nouvelle bibliothèque qui n'est pas installée dans l'image car la synchronisation a eu lieu avant la reconstruction. **Diagnostic** : Vérifiez le code de sortie du conteneur et les journaux : ```bash docker inspect project-web-1 --format='{{.State.ExitCode}}' docker logs project-web-1 --tail 50 ``` Si l'erreur est un `ModuleNotFoundError`, la dépendance est manquante. **Récupération** : Changez l'action watch en `rebuild` pour les fichiers qui modifient les dépendances, ou reconstruisez manuellement avec `docker compose up --build web` puis redémarrez le watch. ### 4. Perte de données après recréation du conteneur **Symptôme** : L'application perd son état après une reconstruction déclenchée par watch. **Cause** : Les données sont stockées dans la couche inscriptible du conteneur, qui est détruite lors de la reconstruction. Le service a écrit sur un chemin non sauvegardé par un volume ou un montage bind. **Diagnostic** : Comparez les données avant et après reconstruction. Inspectez les montages : ```bash docker inspect project-db-1 --format='{{json .Mounts}}' ``` Si le répertoire de données n'est pas listé, il est éphémère. **Récupération** : Ajoutez un volume à la définition du service et migrez les données. Arrêtez le conteneur, copiez les données si possible, ajoutez le volume et redémarrez. À l'avenir, assurez-vous que tous les chemins avec état sont des volumes. ## Liste de contrôle opérationnelle Utilisez cette liste de contrôle pour chaque service activé par watch avant et pendant le développement. Attribuez un responsable par élément pour éviter toute ambiguïté. | # | Élément de la liste | Responsable | Comment vérifier | Fréquence de révision | |---|---|---|---|---| | 1 | Confirmer que les versions de Docker et Compose répondent aux exigences minimales | Développeur principal (par ex., Priya Shah) | Exécuter `docker compose version` ; comparer aux requis | À chaque version | | 2 | Examiner la configuration `watch` pour les chemins et les motifs d'ignore corrects | Ingénieur DevOps (par ex., Marcus Chen) | `docker compose config --quiet` ; test manuel de synchronisation | Hebdomadaire | | 3 | S'assurer que des healthchecks sont définis pour tous les services avec état | Responsable backend (par ex., Ana Lopez) | `docker inspect --format='{{.State.Health.Status}}'` | À chaque PR | | 4 | Vérifier la persistance des données avec un test de redémarrage | Ingénieur QA (par ex., Tom Nguyen) | Arrêter, recréer, vérifier que les données existent | Avant chaque déploiement | | 5 | Surveiller les compteurs de redémarrage pour les boucles de reconstruction | SRE (par ex., Jordan Patel) | Requête Prometheus `increase(container_restart_count[1h])` | Quotidien | | 6 | Tester le routage des alertes de bout en bout | Ingénieur d'astreinte (rotation) | Déclencher une alerte de test, confirmer la notification | Mensuel | | 7 | Examiner les performances de synchronisation et de reconstruction (CPU, E/S disque) | Ingénieur DevOps | Tableau de bord Grafana ; vérifier les métriques cAdvisor | Hebdomadaire | **Note sur la responsabilité** : Le développeur principal est responsable de la configuration globale du watch et des définitions des actions watch. L'ingénieur DevOps est responsable de l'infrastructure de surveillance et d'alerte. Révisez la liste de contrôle lors d'une réunion hebdomadaire et mettez à jour les responsables si la composition de l'équipe change. **Contrôle des modifications** : Toute modification de la section `watch` ou des règles de surveillance doit passer par une pull request avec une révision par au moins un autre ingénieur. Après fusion, exécutez les étapes de vérification ci-dessus et consignez les résultats dans le journal de déploiement. ## Pièges courants Évitez ces erreurs qui piègent fréquemment les équipes utilisant Compose Watch. 1. **Surveiller trop de fichiers** - Inclure un grand répertoire comme `node_modules` dans le chemin de synchronisation peut submerger le watcher et provoquer des retards. Définissez toujours des motifs d'ignore. Exemple : ignorez `**/*.log`, `**/__pycache__`, `**/node_modules`. 2. **Confondre synchronisation et reconstruction** - Utiliser `rebuild` pour chaque changement va à l'encontre du but de watch ; utiliser `sync` pour les changements de dépendances laisse le conteneur dans un état cassé. Utilisez `sync` pour les fichiers sources, `rebuild` pour les manifestes et les modifications du Dockerfile. 3. **Ne pas définir de limites de ressources** - Les reconstructions pilotées par watch peuvent faire grimper le CPU et la mémoire. Définissez `deploy.resources.limits` pour les services en développement afin d'éviter de déstabiliser l'hôte : ```yaml services: web: deploy: resources: limits: cpus: '1.0' memory: 512M ``` 4. **Ignorer les journaux du watch** - Le watcher émet des informations utiles sur ce qu'il fait. Exécutez `docker compose logs -f` dans un terminal séparé pendant le développement ; ne les silencez pas. 5. **Supposer que watch fonctionne en production** - Compose Watch est conçu pour le développement. En production, utilisez des images immuables et l'orchestration. Si vous devez l'utiliser pour des déploiements à petite échelle, désactivez watch avec `docker compose up` (pas `watch`) et surveillez de près. 6. **Coder en dur des secrets dans du code déclenché par watch** - Une synchronisation peut copier des fichiers contenant des secrets dans le conteneur. Utilisez des variables d'environnement et des montages de secrets ; ne commitez jamais de secrets dans le dépôt. ## Conclusion Docker Compose Watch peut considérablement accélérer le développement, mais ce n'est pas un outil à configurer et oublier. Une surveillance et des alertes efficaces exigent de comprendre votre environnement, de configurer correctement les actions watch, de vérifier l'état du conteneur après chaque modification et de se préparer aux défaillances. Commencez par les sections inventaire et configuration sûre, puis ajoutez des healthchecks et des métriques. La liste de contrôle opérationnelle et les pièges courants fournissent un cadre pour maintenir votre configuration Compose Watch saine au fil du temps. N'oubliez pas de réviser régulièrement les seuils d'alerte et les attributions de responsabilité, car les applications et les équipes évoluent. Comme prochaine étape, mettez en œuvre un aspect de surveillance de ce guide : définissez un healthcheck pour votre service le plus critique, configurez une alerte de redémarrage ou créez un panneau de tableau de bord pour les compteurs de redémarrage. Documentez l'état actuel, exécutez la vérification et comparez avec le signal attendu. Ensuite, étendez au reste de votre pile. Une surveillance fiable du watch rend le développement plus rapide et plus sûr.