Docker Compose simplifie le déploiement d'applications multi-conteneurs, mais son observabilité intégrée se limite à l'état de base des conteneurs et aux journaux. Les charges de travail en production exigent des métriques structurées, des alertes actionnables et des tableaux de bord qui font surface les problèmes avant que les utilisateurs ne les remarquent. Ce guide détaille une pile de monitoring complète pour les environnements Docker Compose utilisant Prometheus, Grafana, Alertmanager et cAdvisor, avec des exemples de configuration concrets, des règles d'alerting et des procédures opérationnelles que vous pouvez adapter à votre stack.
Architecture et Sélection des Composants
Une pile de monitoring pratique pour Docker Compose comprend quatre services principaux :
- Prometheus récupère les métriques depuis les exporteurs et les points de terminaison d'application, stocke les données de séries temporelles et évalue les règles d'alerting.
- Alertmanager déduplique, regroupe et route les alertes vers les canaux de notification tels que Slack, PagerDuty ou courriel.
- Grafana visualise les métriques à travers des tableaux de bord et offre des capacités de requêtage ad hoc.
- cAdvisor expose l'utilisation des ressources au niveau conteneur (CPU, mémoire, disque, réseau) pour chaque conteneur sur l'hôte.
Des ajouts optionnels mais recommandés incluent Node Exporter pour les métriques au niveau hôte (disque, réseau, charge système) et des exporteurs spécifiques aux applications (par exemple nginx-prometheus-exporter, redis_exporter, postgres_exporter) pour les signaux dorés au niveau service.
Tous les composants s'exécutent comme des conteneurs définis dans un seul fichier docker-compose.monitoring.yml, déployés aux côtés de votre stack applicative ou sur un hôte d'observabilité dédié. Cela maintient le plan de monitoring indépendant des déploiements applicatifs tout en partageant le même réseau Docker pour la découverte de services.
Structure d'Exemple du Fichier Compose
version: "3.8"
services:
prometheus:
image: prom/prometheus:v2.53.0
command:
- "--config.file=/etc/prometheus/prometheus.yml"
- "--storage.tsdb.path=/prometheus"
- "--storage.tsdb.retention.time=30d"
- "--web.enable-lifecycle"
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./prometheus/rules:/etc/prometheus/rules:ro
- prometheus_data:/prometheus
ports:
- "9090:9090"
networks:
- monitoring
restart: unless-stopped
alertmanager:
image: prom/alertmanager:v0.27.0
command:
- "--config.file=/etc/alertmanager/alertmanager.yml"
- "--storage.path=/alertmanager"
volumes:
- ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
- alertmanager_data:/alertmanager
ports:
- "9093:9093"
networks:
- monitoring
restart: unless-stopped
grafana:
image: grafana/grafana:10.4.0
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD__FILE=/run/secrets/grafana_admin_password
- GF_INSTALL_PLUGINS=grafana-piechart-panel
volumes:
- ./grafana/provisioning:/etc/grafana/provisioning:ro
- ./grafana/dashboards:/var/lib/grafana/dashboards:ro
- grafana_data:/var/lib/grafana
secrets:
- grafana_admin_password
ports:
- "3000:3000"
networks:
- monitoring
restart: unless-stopped
cadvisor:
image: gcr.io/cadvisor/cadvisor:v0.49.1
command:
- "--docker_only=true"
- "--housekeeping_interval=10s"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
- /dev/disk/:/dev/disk:ro
ports:
- "8080:8080"
networks:
- monitoring
restart: unless-stopped
node-exporter:
image: prom/node-exporter:v1.7.0
command:
- "--path.rootfs=/host"
pid: host
volumes:
- /:/host:ro
- /sys:/sys:ro
- /proc:/proc:ro
ports:
- "9100:9100"
networks:
- monitoring
restart: unless-stopped
networks:
monitoring:
driver: bridge
volumes:
prometheus_data:
alertmanager_data:
grafana_data:
secrets:
grafana_admin_password:
file: ./secrets/grafana_admin_password.txt
Notes opérationnelles clés :
- Épinglez les tags d'image à des versions spécifiques (pas
latest) pour éviter les mises à niveau surprises. - Stockez les secrets (mot de passe admin Grafana, URLs webhook Alertmanager) dans les secrets Docker ou un fichier
.envexclu du contrôle de version. - Montez la configuration en lecture seule (
:ro) quand possible pour prévenir les modifications accidentelles. - Utilisez des volumes nommés pour les données persistantes (TSDB Prometheus, état Alertmanager, tableaux de bord Grafana) afin que la recréation des conteneurs préserve l'historique.
Configuration Prometheus et Découverte de Services
Prometheus découvre les cibles de scraping via la configuration statique ou la découverte de services Docker. Pour Docker Compose, le mécanisme dockersd détecte automatiquement les conteneurs avec des étiquettes spécifiques, éliminant la gestion manuelle des cibles.
Configuration Prometheus (prometheus/prometheus.yml)
global:
scrape_interval: 15s
evaluation_interval: 15s
external_labels:
environment: "production"
compose_project: "myapp"
alerting:
alertmanagers:
- static_configs:
- targets: ["alertmanager:9093"]
rule_files:
- "rules/*.yml"
scrape_configs:
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"]
- job_name: "cadvisor"
static_configs:
- targets: ["cadvisor:8080"]
- job_name: "node-exporter"
static_configs:
- targets: ["node-exporter:9100"]
- job_name: "docker-compose-services"
dockerswarm_sd_configs:
- host: unix:///var/run/docker.sock
role: services
relabel_configs:
- source_labels: [__meta_docker_service_label_prometheus_job]
action: keep
regex: .+
- source_labels: [__meta_docker_service_label_prometheus_port]
action: replace
target_label: __address__
regex: (.+)
replacement: ${1}:${2}
- source_labels: [__meta_docker_service_label_prometheus_path]
action: replace
target_label: __metrics_path__
regex: (.+)
replacement: ${1}
Activation des Métriques d'Application via Étiquettes
Ajoutez les étiquettes de scraping Prometheus à vos services applicatifs dans le docker-compose.yml principal :
services:
api:
image: myorg/api:v1.12.0
ports:
- "8000:8000"
labels:
- "prometheus.job=api"
- "prometheus.port=8000"
- "prometheus.path=/metrics"
networks:
- app-network
- monitoring
deploy:
replicas: 3
Prometheus découvrira automatiquement le service api, scrapera /metrics sur le port 8000, et taguera les métriques avec job="api". Ce pattern s'étend à des dizaines de services sans toucher à prometheus.yml.
Règles d'Alerting Qui Réduisent le Bruit
Les alertes efficaces se déclenchent sur les symptômes (impact utilisateur) plutôt que sur les causes (état interne). Définissez les règles dans prometheus/rules/ regroupées par domaine.
Alertes Infrastructure (prometheus/rules/infrastructure.yml)
groups:
- name: infrastructure
interval: 30s
rules:
- alert: ContainerDown
expr: |
absent(container_last_seen{job="cadvisor"}) or
(time() - container_last_seen{job="cadvisor"}) > 60
for: 1m
labels:
severity: critical
annotations:
summary: "Conteneur {{ $labels.name }} hors ligne depuis > 1m"
description: "Le conteneur {{ $labels.name }} (image: {{ $labels.image }}) n'a pas rapporté de métriques depuis plus de 60 secondes."
runbook_url: "https://wiki.example.com/runbooks/container-down"
- alert: ContainerHighCPU
expr: |
(rate(container_cpu_usage_seconds_total{job="cadvisor",container!=""}[5m]) /
container_spec_cpu_quota{job="cadvisor",container!=""} / 100000) > 0.85
for: 5m
labels:
severity: warning
annotations:
summary: "Conteneur {{ $labels.name }} CPU > 85% depuis 5m"
description: "Le conteneur {{ $labels.name }} utilise plus de 85% de son quota CPU de façon soutenue. Vérifiez les processus incontrôlés ou les limites sous-dimensionnées."
- alert: ContainerHighMemory
expr: |
(container_memory_usage_bytes{job="cadvisor",container!=""} /
container_spec_memory_limit_bytes{job="cadvisor",container!=""}) > 0.85
for: 5m
labels:
severity: warning
annotations:
summary: "Conteneur {{ $labels.name }} mémoire > 85% depuis 5m"
description: "L'utilisation mémoire du conteneur {{ $labels.name }} dépasse 85% de sa limite. Risque de OOM kill."
- alert: HostDiskSpaceCritical
expr: |
(node_filesystem_avail_bytes{mountpoint="/",fstype!="tmpfs"} /
node_filesystem_size_bytes{mountpoint="/",fstype!="tmpfs"}) < 0.1
for: 5m
labels:
severity: critical
annotations:
summary: "Espace disque hôte < 10% sur {{ $labels.instance }}"
description: "Le système de fichiers racine sur {{ $labels.instance }} a moins de 10% d'espace libre. Nettoyez les journaux, images, ou agrandissez le volume."
Signaux Dorés Applicatifs (prometheus/rules/application.yml)
groups:
- name: application
interval: 30s
rules:
- alert: APIHighErrorRate
expr: |
sum(rate(http_requests_total{job="api",code=~"5.."}[2m])) by (job)
/
sum(rate(http_requests_total{job="api"}[2m])) by (job)
> 0.05
for: 2m
labels:
severity: critical
annotations:
summary: "Taux d'erreurs 5xx API > 5% depuis 2m"
description: "Le service {{ $labels.job }} retourne des erreurs 5xx sur plus de 5% des requêtes. Vérifiez les dépendances amont et les journaux."
- alert: APIHighLatency
expr: |
histogram_quantile(0.95,
sum(rate(http_request_duration_seconds_bucket{job="api"}[5m])) by (le, job)
) > 1.0
for: 5m
labels:
severity: warning
annotations:
summary: "Latence p95 API > 1s depuis 5m"
description: "La latence p95 des requêtes du service {{ $labels.job }} dépasse 1 seconde. Investiguez la base de données, le cache, ou les appels externes."
- alert: APITrafficDrop
expr: |
sum(rate(http_requests_total{job="api"}[5m])) by (job) < 0.1
for: 10m
labels:
severity: warning
annotations:
summary: "Trafic API proche de zéro depuis 10m"
description: "Le service {{ $labels.job }} reçoit < 0.1 req/s. Problème de routage, échec de déploiement, ou panne amont possible."
Routage Alertmanager (alertmanager/alertmanager.yml)
global:
resolve_timeout: 5m
slack_api_url: "https://hooks.slack.com/services/XXX/YYY/ZZZ"
route:
group_by: ["alertname", "job", "severity"]
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: "slack-critical"
routes:
- match:
severity: "critical"
receiver: "slack-critical"
continue: true
- match:
severity: "warning"
receiver: "slack-warning"
group_interval: 15m
repeat_interval: 12h
receivers:
- name: "slack-critical"
slack_configs:
- channel: "#alertes-critiques"
title: "[{{ .Status }}] {{ .GroupLabels.alertname }}"
text: "{{ range .Alerts }}{{ .Annotations.description }}\n{{ end }}"
send_resolved: true
icon_emoji: ":fire:"
- name: "slack-warning"
slack_configs:
- channel: "#alertes-avertissements"
title: "[{{ .Status }}] {{ .GroupLabels.alertname }}"
text: "{{ range .Alerts }}{{ .Annotations.description }}\n{{ end }}"
send_resolved: true
icon_emoji: ":warning:"
inhibit_rules:
- source_match:
severity: "critical"
target_match:
severity: "warning"
equal: ["job", "instance"]
Cette configuration route les alertes critiques vers un canal à haute visibilité avec des intervalles de répétition courts, tandis que les avertissements vont vers un canal à moindre bruit avec un regroupement plus long. L'inhibition prévient les tempêtes d'avertissements quand une alerte critique couvre déjà le même service.
Tableaux de Bord Grafana et Provisioning
Provisionnez les tableaux de bord comme du code pour qu'ils soient versionnés aux côtés de l'infrastructure. Grafana lit le JSON des tableaux de bord depuis un répertoire monté au démarrage.
Configuration de Provisioning (grafana/provisioning/dashboards/dashboard-provider.yml)
apiVersion: 1
providers:
- name: "Docker Compose Monitoring"
orgId: 1
folder: "Infrastructure"
type: file
disableDeletion: false
updateIntervalSeconds: 30
allowUiUpdates: false
options:
path: /var/lib/grafana/dashboards
Panneaux Clés des Tableaux de Bord
Créez ou importez des tableaux de bord couvrant :
- Vue d'ensemble des conteneurs : Tableau de tous les conteneurs avec statut, CPU %, mémoire %, nombre de redémarrages et temps de fonctionnement. Utilisez
container_last_seen,container_cpu_usage_seconds_total,container_memory_usage_bytes, etcontainer_start_time_secondsdepuis cAdvisor. - Saturation des ressources : Carte de chaleur de l'utilisation CPU et mémoire à travers les services dans le temps. Repérez les tendances avant d'atteindre les limites.
- Taux de requêtes, Erreurs, Durée (RED) : Pour chaque service instrumenté, affichez requêtes/seconde, taux d'erreur (5xx / total), et latence p50/p95/p99 depuis les points de terminaison
/metricsd'application. - Ressources hôte : Panneaux Node Exporter pour E/S disque, débit réseau, charge moyenne, et utilisation des systèmes de fichiers.
- Statut des alertes : Tableau des alertes en cours de déclenchement depuis l'API Alertmanager (
/api/v2/alertes) avec boutons de silence.
Stockez les fichiers JSON des tableaux de bord dans grafana/dashboards/ et commitez-les. Au redémarrage de Grafana, les tableaux de bord apparaissent automatiquement sans import manuel.
Procédures Opérationnelles
Déploiement de la Stack
# Créer le répertoire secrets et générer le mot de passe Grafana
mkdir -p secrets
openssl rand -base64 32 > secrets/grafana_admin_password.txt
chmod 600 secrets/grafana_admin_password.txt
# Déployer la stack de monitoring
docker compose -f docker-compose.monitoring.yml up -d
# Vérifier que tous les services sont sains
docker compose -f docker-compose.monitoring.yml ps
Vérification de la Collecte de Métriques
# Vérifier les cibles Prometheus
curl -s http://localhost:9090/api/v1/targets | jq '.data.activeTargets[] | {job: .labels.job, instance: .labels.instance, health: .health}'
# Requêter une métrique d'exemple
curl -s "http://localhost:9090/api/v1/query?query=container_cpu_usage_seconds_total" | jq '.data.result[0]'
# Vérifier le statut Alertmanager
curl -s http://localhost:9093/api/v2/status | jq '.'
Ajout d'un Nouveau Service au Monitoring
- Ajoutez les étiquettes Prometheus au service dans votre
docker-compose.ymlapplicatif. - Assurez-vous que le service rejoint le réseau
monitoring. - Redéployez la stack applicative :
docker compose up -d. - Vérifiez que la cible apparaît dans l'UI Prometheus (Status → Targets) dans les 30 secondes.
- Créez ou mettez à jour les règles d'alerting si le service expose de nouveaux SLI.
- Ajoutez des panneaux au tableau de bord Grafana pertinent.
Rotation des Secrets
# Générer un nouveau mot de passe Grafana
openssl rand -base64 32 > secrets/grafana_admin_password.txt.new
# Mettre à jour le secret (nécessite un redémarrage de la stack pour que Grafana le prenne en compte)
mv secrets/grafana_admin_password.txt.new secrets/grafana_admin_password.txt
docker compose -f docker-compose.monitoring.yml up -d --force-recreate grafana
Sauvegarde et Reprise Après Sinistre
- Données Prometheus : Instantané via API (
POST /api/v1/admin/tsdb/snapshot) ou arrêt du conteneur et archivage du volumeprometheus_data. - Tableaux de bord Grafana : Déjà dans Git via le provisioning. Exportez le JSON des tableaux de bord depuis l'UI comme sauvegarde.
- Configuration Alertmanager : Dans Git. L'état des silences stocké dans le volume
alertmanager_data; recréation depuis la config à la restauration.
Testez la restauration trimestriellement : lancez un hôte frais, montez les sauvegardes de volumes, démarrez la stack, vérifiez que les tableaux de bord affichent l'historique et que les alertes s'évaluent correctement.
Modes de Défaillance et Atténuations
| Mode de défaillance | Détection | Atténuation |
|---|---|---|
| Prometheus OOM | container_memory_usage_bytes près de la limite, échecs de scraping | Augmenter --storage.tsdb.retention.time, ajouter memory_limit au Compose, activer la compression WAL |
| Alertmanager hors ligne | Aucune alerte livrée, cible Prometheus alertmanager non saine | Exécuter 2+ répliques Alertmanager en mode HA avec mesh gossip partagé |
| cAdvisor conteneurs manquants | Gaps container_last_seen, alertes "ContainerDown" | S'assurer que cAdvisor a --docker_only=true et accès au socket Docker |
| Dérive tableaux de bord Grafana | Modifications UI non reflétées dans Git | Définir allowUiUpdates: false dans le provisioning ; imposer workflow PR pour changements tableaux de bord |
| Spam de journaux erreurs scrape | Journaux Prometheus, scrape_duration_seconds élevé | Corriger le point de terminaison /metrics cible, ajuster scrape_timeout, vérifier politiques réseau |
Conclusion
Le monitoring des charges de travail Docker Compose exige plus que docker stats et la consultation de journaux. Une stack construite sur Prometheus, Alertmanager, Grafana et cAdvisor fournit une visibilité au niveau service, des alertes actionnables et une analyse historique sans installation d'agent ni modification d'hôte. Le déploiement basé sur Compose garde les opérations simples : configuration versionnée, gestion des secrets via secrets Docker, et mise à l'échelle indépendante du plan d'observabilité. Commencez par les alertes infrastructure (santé des conteneurs, saturation des ressources), ajoutez les signaux dorés applicatifs au fur et à mesure que les services exposent des points de terminaison /metrics, et itérez les tableaux de bord basés sur les rétrospectives d'incidents. Traitez le code de monitoring comme du code applicatif — révisez, testez, versionnez, et déployez à travers le même pipeline.