← Retour aux tutoriels

Monitoring et alerting pour workloads Docker : détecter les pannes avant les utilisateurs

devopsdockermonitoringalertingobservabiliteprometheusgrafanalogstracingsre

Monitoring et alerting pour workloads Docker : détecter les pannes avant les utilisateurs

Le monitoring et l’alerting d’applications conteneurisées ne se résument pas à « vérifier que le conteneur tourne ». Un conteneur peut être up tout en étant inutile (deadlock, saturation CPU, fuite mémoire, pool de connexions épuisé, latence énorme, erreurs 5xx, disque plein, etc.). L’objectif de ce tutoriel est de construire une chaîne complète et pragmatique pour détecter les pannes avant les utilisateurs, avec des commandes réelles, des métriques actionnables, des alertes pertinentes et des tests de panne.

Ce guide se concentre sur Docker (standalone), mais les principes sont identiques en Swarm/Kubernetes.


1) Principes : ce qu’il faut vraiment monitorer

1.1 Les 4 couches indispensables

  1. Hôte (node)
    CPU, RAM, swap, disque, I/O, réseau, saturation, erreurs kernel, pression mémoire.
  2. Runtime conteneur (Docker)
    Nombre de conteneurs, restarts, OOMKills, limites cgroups, usage CPU/mémoire par conteneur.
  3. Application
    Latence, taux d’erreur, throughput, queues, connexions DB, temps de réponse, exceptions.
  4. Expérience utilisateur / SLO
    Disponibilité, p95/p99, taux d’erreur, apdex, objectifs (SLO) et budget d’erreur.

1.2 Golden Signals (recommandé)

Pour chaque service, essayez d’avoir au minimum :


2) Outils : une stack simple et efficace

Une combinaison classique et robuste :

Ce tutoriel installe Prometheus/Grafana/Alertmanager + exporters, puis configure des alertes utiles.


3) Pré-requis et vérifications Docker

Sur votre serveur (Linux recommandé), vérifiez Docker :

docker version
docker info

Vérifiez l’usage actuel :

docker ps
docker stats --no-stream
docker events --since 10m

Inspectez un conteneur pour voir les limites :

docker inspect --format '{{json .HostConfig}}' <container_name_or_id> | jq

Si jq n’est pas installé :

sudo apt-get update && sudo apt-get install -y jq

4) Déploiement de la stack monitoring (Prometheus + Grafana + Alertmanager)

Vous pouvez tout lancer avec docker compose. Comme on vous demande « Markdown only » et des commandes réelles, voici une approche reproductible : vous créez les fichiers, puis vous lancez.

4.1 Arborescence

mkdir -p monitoring/{prometheus,alertmanager,grafana,blackbox}
cd monitoring

4.2 Réseau Docker dédié

docker network create monitoring

4.3 Prometheus : configuration

Créez prometheus/prometheus.yml :

cat > prometheus/prometheus.yml <<'EOF'
global:
  scrape_interval: 15s
  evaluation_interval: 15s

rule_files:
  - /etc/prometheus/rules/*.rules.yml

alerting:
  alertmanagers:
    - static_configs:
        - targets: ["alertmanager:9093"]

scrape_configs:
  - job_name: "prometheus"
    static_configs:
      - targets: ["prometheus:9090"]

  - job_name: "node_exporter"
    static_configs:
      - targets: ["node_exporter:9100"]

  - job_name: "cadvisor"
    static_configs:
      - targets: ["cadvisor:8080"]

  - job_name: "blackbox"
    metrics_path: /probe
    params:
      module: [http_2xx]
    static_configs:
      - targets:
          - https://example.com/
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: blackbox:9115
EOF

Créez un dossier de règles :

mkdir -p prometheus/rules

4.4 Alertmanager : configuration

Créez alertmanager/alertmanager.yml (exemple webhook ; adaptez à Slack/Email) :

cat > alertmanager/alertmanager.yml <<'EOF'
global:
  resolve_timeout: 5m

route:
  receiver: "webhook-default"
  group_by: ["alertname", "job", "instance"]
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 2h

receivers:
  - name: "webhook-default"
    webhook_configs:
      - url: "http://your-webhook-endpoint.local/alert"
        send_resolved: true
EOF

Pour tester rapidement sans webhook réel, vous pouvez utiliser un conteneur qui logge les requêtes HTTP (voir section tests).

4.5 Blackbox exporter : configuration

Créez blackbox/blackbox.yml :

cat > blackbox/blackbox.yml <<'EOF'
modules:
  http_2xx:
    prober: http
    timeout: 5s
    http:
      valid_http_versions: ["HTTP/1.1", "HTTP/2.0"]
      valid_status_codes: []
      method: GET
      preferred_ip_protocol: "ip4"
EOF

4.6 Lancement via Docker Compose

Créez compose.monitoring.yml :

cat > compose.monitoring.yml <<'EOF'
services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"
      - "--storage.tsdb.path=/prometheus"
    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:latest
    container_name: alertmanager
    command:
      - "--config.file=/etc/alertmanager/alertmanager.yml"
    volumes:
      - ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
    ports:
      - "9093:9093"
    networks: ["monitoring"]
    restart: unless-stopped

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana_data:/var/lib/grafana
    ports:
      - "3000:3000"
    networks: ["monitoring"]
    restart: unless-stopped

  node_exporter:
    image: prom/node-exporter:latest
    container_name: node_exporter
    pid: host
    command:
      - "--path.rootfs=/host"
    volumes:
      - "/:/host:ro,rslave"
    ports:
      - "9100:9100"
    networks: ["monitoring"]
    restart: unless-stopped

  cadvisor:
    image: gcr.io/cadvisor/cadvisor:latest
    container_name: cadvisor
    privileged: true
    volumes:
      - "/:/rootfs:ro"
      - "/var/run:/var/run:rw"
      - "/sys:/sys:ro"
      - "/var/lib/docker/:/var/lib/docker:ro"
      - "/dev/disk/:/dev/disk:ro"
    ports:
      - "8080:8080"
    networks: ["monitoring"]
    restart: unless-stopped

  blackbox:
    image: prom/blackbox-exporter:latest
    container_name: blackbox
    volumes:
      - ./blackbox/blackbox.yml:/etc/blackbox_exporter/config.yml:ro
    command:
      - "--config.file=/etc/blackbox_exporter/config.yml"
    ports:
      - "9115:9115"
    networks: ["monitoring"]
    restart: unless-stopped

networks:
  monitoring:
    external: true

volumes:
  prometheus_data:
  grafana_data:
EOF

Lancez :

docker compose -f compose.monitoring.yml up -d
docker ps

Accès :


5) Ajouter des alertes utiles (pas du bruit)

Créer des alertes « bêtes » du type CPU > 80% est souvent une source de fatigue (alert fatigue). Préférez des alertes orientées impact (erreurs, latence, indisponibilité) et risque (disque presque plein, OOM, restarts en boucle).

5.1 Règles Prometheus (fichier)

Créez prometheus/rules/docker-workloads.rules.yml :

cat > prometheus/rules/docker-workloads.rules.yml <<'EOF'
groups:
- name: docker-workloads
  rules:

  - alert: InstanceDown
    expr: up == 0
    for: 2m
    labels:
      severity: critical
    annotations:
      summary: "Cible Prometheus down ({{ $labels.job }} / {{ $labels.instance }})"
      description: "Prometheus n'arrive plus à scrapper la cible depuis 2 minutes."

  - alert: HostDiskAlmostFull
    expr: (node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"}) < 0.10
    for: 10m
    labels:
      severity: warning
    annotations:
      summary: "Disque presque plein sur {{ $labels.instance }} ({{ $labels.mountpoint }})"
      description: "Moins de 10% d'espace libre depuis 10 minutes."

  - alert: HostDiskWillFillSoon
    expr: predict_linear(node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"}[6h], 24*3600) < 0
    for: 30m
    labels:
      severity: critical
    annotations:
      summary: "Disque va se remplir dans < 24h sur {{ $labels.instance }} ({{ $labels.mountpoint }})"
      description: "Projection sur 24h basée sur les 6 dernières heures."

  - alert: ContainerRestartsHigh
    expr: increase(container_start_time_seconds[15m]) > 3
    for: 0m
    labels:
      severity: warning
    annotations:
      summary: "Redémarrages fréquents détectés (cadvisor)"
      description: "Un ou plusieurs conteneurs semblent redémarrer souvent (augmentation de start_time_seconds). À investiguer via docker ps / logs."

  - alert: ContainerCPUThrottlingHigh
    expr: rate(container_cpu_cfs_throttled_seconds_total[5m]) > 0.5
    for: 10m
    labels:
      severity: warning
    annotations:
      summary: "CPU throttling élevé ({{ $labels.container_label_com_docker_compose_service }})"
      description: "Le conteneur est fortement bridé par CFS. Vérifiez limites CPU et charge."

  - alert: HostMemoryPressure
    expr: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) > 0.90
    for: 10m
    labels:
      severity: warning
    annotations:
      summary: "Pression mémoire élevée sur {{ $labels.instance }}"
      description: "Plus de 90% de la mémoire est consommée (MemAvailable faible). Risque d'OOM."

  - alert: EndpointDownBlackbox
    expr: probe_success == 0
    for: 2m
    labels:
      severity: critical
    annotations:
      summary: "Endpoint indisponible ({{ $labels.instance }})"
      description: "Le check blackbox échoue depuis 2 minutes."
EOF

Rechargez Prometheus (redémarrage simple) :

docker restart prometheus

Vérifiez dans Prometheus > Status > Rules.

Remarque importante : container_start_time_seconds n’est pas un compteur, donc increase() est une approximation pour détecter des changements. Selon versions cAdvisor, vous pouvez préférer des métriques de restart si disponibles dans votre environnement, ou instrumenter via Docker events (voir section 9).


6) Dashboards Grafana : ce qu’il faut afficher

6.1 Ajouter Prometheus comme datasource

Dans Grafana :

6.2 Dashboards recommandés

Vous pouvez importer des dashboards communautaires (ID Grafana). Exemples souvent utilisés :

Import manuel :

6.3 Les panneaux qui aident vraiment en incident

Pour chaque service applicatif, essayez d’avoir :


7) Instrumenter l’application : métriques et healthchecks

Le monitoring infra est nécessaire mais insuffisant. Pour détecter « avant les utilisateurs », il faut des métriques applicatives et des checks.

7.1 Healthcheck Docker

Ajoutez un HEALTHCHECK dans l’image ou via compose (si vous gérez vos Dockerfiles). Exemple Dockerfile :

HEALTHCHECK --interval=30s --timeout=3s --retries=3 CMD wget -qO- http://localhost:8080/health || exit 1

Vérification :

docker inspect --format '{{.State.Health.Status}}' <container>
docker ps --format 'table {{.Names}}\t{{.Status}}'

Un healthcheck doit tester une dépendance minimale (ex: DB) si votre service ne peut pas fonctionner sans. Sinon vous aurez des conteneurs « healthy » mais un service inutilisable.

7.2 Exposer des métriques Prometheus

Exemple conceptuel (sans code complet) : exposez /metrics et /health. Ensuite ajoutez un scrape_config dans Prometheus pour votre service :

# Exemple: votre service écoute sur 8080 et expose /metrics
# Si le service est dans Docker et sur le réseau monitoring, vous pouvez le cibler par nom de conteneur.

Ajoutez dans prometheus/prometheus.yml :

grep -n "scrape_configs" -n prometheus/prometheus.yml

Éditez (avec nano/vim) et ajoutez :

  - job_name: "app"
    static_configs:
      - targets: ["mon_app:8080"]

Puis :

docker restart prometheus

8) Alerting orienté SLO : erreurs et latence

Les alertes les plus utiles sont celles qui indiquent un impact utilisateur imminent. Si votre application expose des métriques HTTP (ex: http_requests_total, http_request_duration_seconds_bucket), vous pouvez alerter sur :

8.1 Exemples de requêtes PromQL (à adapter)

Taux d’erreur (5xx)

sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))

Latence p95 (histogramme)

histogram_quantile(
  0.95,
  sum by (le) (rate(http_request_duration_seconds_bucket[5m]))
)

Si vous n’avez pas d’histogrammes, commencez par en ajouter. Les moyennes masquent les queues de distribution (p95/p99).


9) Détecter les redémarrages, crashloops et OOM de façon fiable

9.1 Observer les événements Docker

Docker émet des événements utiles :

docker events --since 1h --filter 'type=container' --filter 'event=die'
docker events --since 1h --filter 'event=oom'

Pour investiguer un conteneur qui redémarre :

docker ps -a --filter "name=mon_app" --format "table {{.Names}}\t{{.Status}}\t{{.Image}}"
docker logs --since 30m mon_app
docker inspect mon_app --format '{{json .State}}' | jq

9.2 Exporter des événements Docker vers Prometheus (approche simple)

Il existe des exporters dédiés (ex: docker daemon metrics, ou des sidecars). Une solution pragmatique : un petit agent qui convertit les événements en métriques. Si vous ne voulez pas développer, vous pouvez au minimum :

Même sans exporter, gardez des runbooks : « si alerte X, exécuter commandes Y ».


10) Checks externes : Blackbox exporter (HTTP/TCP)

Le blackbox exporter simule un utilisateur externe (ou un point de contrôle) : DNS, TLS, latence, code HTTP.

10.1 Tester manuellement une probe

Depuis Prometheus, vous pouvez requêter :

Exemple : vérifier l’expiration TLS :

(probe_ssl_earliest_cert_expiry - time()) / 86400

Alerte typique : certificat expire dans < 14 jours.


11) Sécurité et robustesse : éviter que le monitoring soit le maillon faible

11.1 Persistance

Vous avez déjà des volumes prometheus_data et grafana_data. Assurez-vous que le disque n’est pas éphémère et qu’il y a de la place.

11.2 Rétention Prometheus

Par défaut, Prometheus garde un certain historique. Vous pouvez contrôler la rétention :

Dans le service Prometheus, ajoutez par exemple :

# Exemple (à mettre dans command):
# --storage.tsdb.retention.time=15d

11.3 Authentification


12) Exercices de chaos (tests) : valider que vos alertes marchent

Un système d’alerting non testé est un système qui échoue en prod. Faites des tests contrôlés.

12.1 Simuler une panne applicative

Stoppez un service :

docker stop mon_app

Attendez 2–3 minutes :

Relancez :

docker start mon_app

12.2 Simuler une saturation CPU

Dans un conteneur (ou sur l’hôte), vous pouvez générer de la charge. Exemple sur l’hôte :

sudo apt-get install -y stress-ng
stress-ng --cpu 2 --timeout 120s

Surveillez :

12.3 Simuler une pression disque

Créez un gros fichier (attention à ne pas casser votre machine) :

df -h
fallocate -l 2G /tmp/bigfile.test
df -h
rm -f /tmp/bigfile.test

Validez l’alerte « disque presque plein » si vous ajustez le seuil.


13) Runbooks : que faire quand une alerte tombe

Une alerte sans procédure = temps perdu. Ajoutez dans vos annotations (ou documentation) des étapes.

13.1 Exemple de runbook pour « EndpointDownBlackbox »

  1. Vérifier si l’endpoint répond depuis le serveur :
    curl -vk https://example.com/ -m 5
  2. Vérifier DNS :
    dig +short example.com
  3. Vérifier reverse proxy / conteneur :
    docker ps
    docker logs --since 10m reverse-proxy
  4. Vérifier certificats :
    echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -noout -dates

13.2 Exemple de runbook pour « HostMemoryPressure »

  1. Voir mémoire :
    free -h
    vmstat 1 5
  2. Top processus :
    ps aux --sort=-%mem | head -n 15
  3. Conteneurs gourmands :
    docker stats --no-stream
  4. Vérifier OOM dans kernel :
    dmesg -T | egrep -i 'oom|killed process' | tail -n 50

14) Bonnes pratiques d’alerting (pour éviter le bruit)

  1. Alertez sur l’impact, pas sur des symptômes isolés.
    Exemple : « taux d’erreur > 2% » est souvent mieux que « CPU > 80% ».
  2. Utilisez for: pour filtrer les spikes.
    Un pic de 10 secondes ne mérite pas toujours un réveil.
  3. Définissez des niveaux (warning/critical) et des canaux.
    Warning → canal équipe, Critical → astreinte.
  4. Dédupliquez (grouping Alertmanager) et mettez un repeat_interval raisonnable.
  5. Ajoutez du contexte : lien Grafana, commande de diagnostic, owner du service.
  6. Révisez les alertes après chaque incident : lesquelles ont aidé, lesquelles ont fait du bruit.

15) Dépannage fréquent

15.1 Prometheus ne scrape pas une cible Docker

15.2 cAdvisor ne montre pas certains conteneurs

15.3 Alertmanager ne reçoit rien


16) Aller plus loin (recommandations réalistes)


Conclusion

Mettre en place un monitoring Docker efficace consiste à :

  1. Collecter métriques hôte + conteneurs + endpoints externes.
  2. Instrumenter l’application (métriques + healthchecks).
  3. Alerter intelligemment (impact/SLO, pas de bruit).
  4. Tester régulièrement les alertes par des pannes contrôlées.
  5. Documenter via runbooks pour réduire le MTTR.

Avec Prometheus + Alertmanager + Grafana + node_exporter + cAdvisor + blackbox exporter, vous avez une base solide pour détecter les pannes avant vos utilisateurs—à condition de choisir des signaux pertinents et de valider votre chaîne d’alerte en conditions réelles.