Aller au contenu
  1. Blog/

Monitoring avec Prometheus et Grafana : guide pratique de A à Z

Votre infrastructure tourne, vos services répondent… mais savez-vous vraiment ce qui se passe sous le capot ? Sans monitoring, vous pilotez à l’aveugle. Une latence qui grimpe, un disque qui se remplit, une mémoire qui fuit — autant de bombes à retardement invisibles sans les bons outils.

Prometheus et Grafana forment le duo de référence en monitoring open source. Prometheus collecte et stocke les métriques, Grafana les visualise. Ensemble, ils offrent une observabilité complète de votre infrastructure, du serveur bare-metal au cluster Kubernetes.

Dans ce guide, on part de zéro : installation avec Docker Compose, configuration, premières métriques, requêtes PromQL, création de dashboards Grafana et mise en place de l’alerting. Un guide pratique, concret, applicable immédiatement.

Pourquoi Prometheus et Grafana ?
#

Avant de plonger dans la technique, posons le contexte. Il existe des dizaines de solutions de monitoring (Zabbix, Datadog, New Relic…). Pourquoi ce stack s’est-il imposé dans l’écosystème DevOps ?

Les forces de Prometheus
#

  • Modèle pull : Prometheus va chercher les métriques sur vos cibles (scraping), ce qui simplifie la configuration réseau
  • Stockage time-series natif : base de données optimisée pour les métriques temporelles, avec compression efficace
  • PromQL : un langage de requêtes puissant, pensé pour l’analyse de métriques
  • Service discovery : découverte automatique des cibles via Consul, Kubernetes, DNS, fichiers…
  • Écosystème d’exporters : des centaines d’exporters disponibles (Node Exporter, MySQL, PostgreSQL, Redis, Nginx…)
  • Standard de facto : adopté par la CNCF, compatible avec la quasi-totalité des outils cloud-native

Les forces de Grafana
#

  • Visualisation de haut niveau : graphiques, jauges, heatmaps, tables — tout est personnalisable
  • Multi-datasources : Prometheus, Loki, InfluxDB, Elasticsearch, PostgreSQL…
  • Dashboards communautaires : des milliers de dashboards prêts à l’emploi sur grafana.com/grafana/dashboards
  • Alerting intégré : depuis Grafana 9+, un système d’alerting unifié directement dans l’interface
  • Annotations et corrélations : croisez métriques, logs et traces dans une seule interface

Architecture du stack
#

Avant d’installer quoi que ce soit, comprenons l’architecture :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
┌─────────────┐     scrape      ┌──────────────┐
│ Node Exporter├───────────────►│              │
└─────────────┘                 │              │     query     ┌─────────┐
                                │  Prometheus  ├──────────────►│ Grafana │
┌─────────────┐     scrape      │              │               └─────────┘
│ cAdvisor    ├───────────────►│              │
└─────────────┘                 │              │     alert      ┌──────────────┐
                                │              ├───────────────►│ Alertmanager │
┌─────────────┐     scrape      └──────────────┘               └──────────────┘
│ Votre app   ├───────────────►
└─────────────┘

Prometheus scrape (interroge) les cibles à intervalles réguliers, stocke les métriques, évalue les règles d’alerte et expose une API de requêtes. Grafana interroge Prometheus pour afficher les dashboards. Alertmanager gère le routage et la déduplication des alertes (email, Slack, PagerDuty…).

Installation avec Docker Compose
#

On va déployer le stack complet en une seule commande. Créez un répertoire de travail :

1
mkdir -p monitoring-stack && cd monitoring-stack

Le fichier docker-compose.yml
#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
version: "3.8"

networks:
  monitoring:
    driver: bridge

volumes:
  prometheus_data: {}
  grafana_data: {}

services:
  prometheus:
    image: prom/prometheus:v2.53.0
    container_name: prometheus
    restart: unless-stopped
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
      - ./prometheus/alerts.yml:/etc/prometheus/alerts.yml
      - prometheus_data:/prometheus
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"
      - "--storage.tsdb.path=/prometheus"
      - "--storage.tsdb.retention.time=30d"
      - "--web.enable-lifecycle"
    ports:
      - "9090:9090"
    networks:
      - monitoring

  grafana:
    image: grafana/grafana:11.1.0
    container_name: grafana
    restart: unless-stopped
    volumes:
      - grafana_data:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=changeme-please
      - GF_USERS_ALLOW_SIGN_UP=false
    ports:
      - "3000:3000"
    networks:
      - monitoring
    depends_on:
      - prometheus

  node-exporter:
    image: prom/node-exporter:v1.8.1
    container_name: node-exporter
    restart: unless-stopped
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - "--path.procfs=/host/proc"
      - "--path.rootfs=/rootfs"
      - "--path.sysfs=/host/sys"
      - "--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)"
    ports:
      - "9100:9100"
    networks:
      - monitoring

  alertmanager:
    image: prom/alertmanager:v0.27.0
    container_name: alertmanager
    restart: unless-stopped
    volumes:
      - ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml
    ports:
      - "9093:9093"
    networks:
      - monitoring

  cadvisor:
    image: gcr.io/cadvisor/cadvisor:v0.49.1
    container_name: cadvisor
    restart: unless-stopped
    privileged: true
    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

Note : Changez impérativement le mot de passe Grafana (GF_SECURITY_ADMIN_PASSWORD) avant tout déploiement en production.

Configuration de Prometheus
#

Créez le fichier prometheus/prometheus.yml :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
global:
  scrape_interval: 15s
  evaluation_interval: 15s
  scrape_timeout: 10s

alerting:
  alertmanagers:
    - static_configs:
        - targets:
            - alertmanager:9093

rule_files:
  - "alerts.yml"

scrape_configs:
  # Prometheus se monitore lui-même
  - job_name: "prometheus"
    static_configs:
      - targets: ["localhost:9090"]

  # Métriques système via Node Exporter
  - job_name: "node-exporter"
    static_configs:
      - targets: ["node-exporter:9100"]

  # Métriques containers via cAdvisor
  - job_name: "cadvisor"
    static_configs:
      - targets: ["cadvisor:8080"]

Configuration d’Alertmanager
#

Créez le fichier alertmanager/alertmanager.yml :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
global:
  resolve_timeout: 5m

route:
  group_by: ["alertname", "severity"]
  group_wait: 10s
  group_interval: 10s
  repeat_interval: 1h
  receiver: "default"

receivers:
  - name: "default"
    webhook_configs:
      - url: "http://localhost:5001/"
        send_resolved: true

Provisioning automatique de Grafana
#

Pour que Grafana se connecte automatiquement à Prometheus au démarrage, créez grafana/provisioning/datasources/prometheus.yml :

1
2
3
4
5
6
7
8
9
apiVersion: 1

datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://prometheus:9090
    isDefault: true
    editable: true

Lancement du stack
#

1
2
3
4
5
# Créer l'arborescence
mkdir -p prometheus alertmanager grafana/provisioning/datasources

# (après avoir créé les fichiers de config ci-dessus)
docker compose up -d

Vérifiez que tout tourne :

1
docker compose ps

Vous devriez voir 5 containers en état running. Accédez aux interfaces :

  • Prometheus : http://localhost:9090
  • Grafana : http://localhost:3000 (admin / changeme-please)
  • Node Exporter : http://localhost:9100/metrics
  • Alertmanager : http://localhost:9093
  • cAdvisor : http://localhost:8080

Vérifier les premières métriques
#

Une fois le stack démarré, rendez-vous sur Prometheus (port 9090) et naviguez vers Status > Targets. Vous devriez voir trois targets avec l’état UP :

  • prometheus (auto-monitoring)
  • node-exporter (métriques système)
  • cadvisor (métriques containers)

Dans l’onglet Graph, tapez une première requête :

1
up

Cette métrique retourne 1 pour chaque cible active et 0 pour les cibles injoignables. C’est le health check le plus basique de Prometheus.

Essayez ensuite :

1
node_cpu_seconds_total

Vous obtiendrez les secondes CPU accumulées par mode (user, system, idle, iowait…). Pas très lisible en l’état — c’est là que PromQL entre en jeu.

PromQL : le langage de requêtes de Prometheus
#

PromQL (Prometheus Query Language) est ce qui rend Prometheus véritablement puissant. Voici les concepts essentiels et des exemples concrets.

Types de métriques
#

TypeDescriptionExemple
CounterValeur qui ne fait qu’augmenterhttp_requests_total
GaugeValeur qui monte et descendnode_memory_MemAvailable_bytes
HistogramDistribution de valeurs dans des bucketshttp_request_duration_seconds_bucket
SummarySimilaire à histogram, avec quantiles pré-calculésgo_gc_duration_seconds

Requêtes essentielles
#

Utilisation CPU en pourcentage (par cœur) :

1
100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

Cette requête calcule le pourcentage de temps CPU non-idle sur les 5 dernières minutes. irate donne le taux instantané, plus réactif que rate pour les dashboards.

Mémoire utilisée en pourcentage :

1
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100

Espace disque disponible en pourcentage :

1
(node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100

Trafic réseau entrant (Mo/s) :

1
rate(node_network_receive_bytes_total{device!="lo"}[5m]) / 1024 / 1024

Nombre de containers en cours d’exécution :

1
count(container_last_seen{name!=""})

Utilisation mémoire par container (top 10) :

1
topk(10, container_memory_usage_bytes{name!=""}) / 1024 / 1024

Fonctions PromQL les plus utiles
#

  • rate(v[t]) : taux moyen par seconde d’un counter sur la fenêtre t
  • irate(v[t]) : taux instantané (entre les 2 derniers points)
  • increase(v[t]) : augmentation totale sur la fenêtre t
  • avg_over_time(v[t]) : moyenne d’un gauge sur la fenêtre
  • histogram_quantile(q, v) : calcul de percentile depuis un histogram
  • topk(n, v) : les n séries avec les plus hautes valeurs
  • predict_linear(v[t], s) : prédiction linéaire à s secondes

Exemple avancé — prédiction de remplissage disque :

1
predict_linear(node_filesystem_avail_bytes{mountpoint="/"}[6h], 24*3600) < 0

Cette requête prédit si le disque sera plein dans les 24 prochaines heures en se basant sur la tendance des 6 dernières heures. Extrêmement utile pour l’alerting proactif.

Créer des dashboards Grafana
#

Connectez-vous à Grafana (http://localhost:3000). La datasource Prometheus est déjà configurée grâce au provisioning.

Importer un dashboard communautaire
#

Le moyen le plus rapide de démarrer : importer un dashboard existant.

  1. Allez dans Dashboards > New > Import
  2. Entrez l’ID 1860 (Node Exporter Full)
  3. Sélectionnez la datasource Prometheus
  4. Cliquez sur Import

Ce dashboard offre une vue complète de vos métriques système : CPU, mémoire, disque, réseau, load average, et bien plus.

Autres dashboards recommandés :

IDNomUsage
1860Node Exporter FullMétriques système détaillées
14282cAdvisor ExporterMétriques containers Docker
3662Prometheus 2.0 OverviewSanté de Prometheus lui-même
13946Docker Container & Host MetricsVue combinée host + containers

Créer un dashboard personnalisé
#

Pour un dashboard sur mesure :

  1. Dashboards > New > New Dashboard
  2. Add visualization
  3. Sélectionnez la datasource Prometheus

Panel 1 — CPU Usage :

  • Requête : 100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
  • Type : Time series
  • Unité : Percent (0-100)
  • Titre : “CPU Usage (%)”

Panel 2 — Memory Usage :

  • Requête : (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100
  • Type : Gauge
  • Unité : Percent (0-100)
  • Seuils : 0-60 vert, 60-80 orange, 80-100 rouge
  • Titre : “Memory Usage (%)”

Panel 3 — Disk Space :

  • Requête : (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100
  • Type : Gauge
  • Unité : Percent (0-100)
  • Seuils inversés : 100-30 vert, 30-15 orange, 15-0 rouge
  • Titre : “Disk Available (%)”

Panel 4 — Network I/O :

  • Requête A : rate(node_network_receive_bytes_total{device!="lo"}[5m])
  • Requête B : rate(node_network_transmit_bytes_total{device!="lo"}[5m])
  • Type : Time series
  • Unité : bytes/sec (SI)
  • Titre : “Network Traffic”

Astuce : Utilisez les variables de template Grafana pour rendre vos dashboards dynamiques. Ajoutez une variable instance de type Query avec label_values(up, instance) pour filtrer par serveur.

Configurer l’alerting
#

Le monitoring sans alerting, c’est comme une alarme incendie sans sirène. Configurons des alertes utiles.

Règles d’alerte Prometheus
#

Créez le fichier prometheus/alerts.yml :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
groups:
  - name: infrastructure
    rules:
      # Alerte si une cible est down depuis 2 minutes
      - alert: TargetDown
        expr: up == 0
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Cible {{ $labels.instance }} injoignable"
          description: "La cible {{ $labels.job }}/{{ $labels.instance }} est down depuis plus de 2 minutes."

      # Alerte si le CPU dépasse 85% pendant 5 minutes
      - alert: HighCpuUsage
        expr: 100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "CPU élevé sur {{ $labels.instance }}"
          description: "L'utilisation CPU est à {{ $value | printf \"%.1f\" }}% depuis 5 minutes."

      # Alerte si la mémoire dépasse 90%
      - alert: HighMemoryUsage
        expr: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 90
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Mémoire élevée sur {{ $labels.instance }}"
          description: "L'utilisation mémoire est à {{ $value | printf \"%.1f\" }}%."

      # Alerte si le disque est rempli à plus de 85%
      - alert: DiskSpaceLow
        expr: (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100 < 15
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "Espace disque faible sur {{ $labels.instance }}"
          description: "Il reste {{ $value | printf \"%.1f\" }}% d'espace disponible sur /."

      # Alerte prédictive : disque plein dans 24h
      - alert: DiskWillFillIn24h
        expr: predict_linear(node_filesystem_avail_bytes{mountpoint="/"}[6h], 24*3600) < 0
        for: 30m
        labels:
          severity: warning
        annotations:
          summary: "Disque bientôt plein sur {{ $labels.instance }}"
          description: "Au rythme actuel, le disque sera plein dans moins de 24 heures."

Après modification, rechargez la config Prometheus :

1
curl -X POST http://localhost:9090/-/reload

Vérifiez dans Prometheus sous Status > Rules que vos règles sont bien chargées.

Alertmanager : routage des notifications
#

Pour envoyer les alertes par email, modifiez alertmanager/alertmanager.yml :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
global:
  resolve_timeout: 5m
  smtp_from: "alertmanager@devopslab.ch"
  smtp_smarthost: "smtp.example.com:587"
  smtp_auth_username: "alertmanager@devopslab.ch"
  smtp_auth_password: "votre-mot-de-passe"
  smtp_require_tls: true

route:
  group_by: ["alertname", "severity"]
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  receiver: "email-team"
  routes:
    - match:
        severity: critical
      receiver: "email-team"
      repeat_interval: 1h

receivers:
  - name: "email-team"
    email_configs:
      - to: "team@devopslab.ch"
        send_resolved: true

inhibit_rules:
  - source_match:
      severity: "critical"
    target_match:
      severity: "warning"
    equal: ["alertname", "instance"]

Points clés de cette configuration :

  • group_by : regroupe les alertes similaires pour éviter le spam
  • group_wait : attend 30s avant d’envoyer, pour regrouper les alertes simultanées
  • repeat_interval : renvoie l’alerte toutes les 4h si non résolue (1h pour les critiques)
  • inhibit_rules : si une alerte critique est active, supprime l’alerte warning correspondante
  • send_resolved: true : notifie aussi quand l’alerte est résolue

Pour Slack, ajoutez un receiver :

1
2
3
4
5
6
7
8
receivers:
  - name: "slack-alerts"
    slack_configs:
      - api_url: "https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
        channel: "#monitoring"
        title: '{{ .GroupLabels.alertname }}'
        text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
        send_resolved: true

Bonnes pratiques de production
#

Un stack de monitoring en lab, c’est facile. En production, il faut penser à la durabilité.

Rétention et stockage
#

Par défaut, notre configuration conserve 30 jours de données (--storage.tsdb.retention.time=30d). Adaptez selon vos besoins :

1
2
3
command:
  - "--storage.tsdb.retention.time=90d"
  - "--storage.tsdb.retention.size=10GB"  # Limite par taille

Pour du stockage long terme, envisagez Thanos ou VictoriaMetrics comme backend remote-write.

Sécurité
#

  • Changez les mots de passe par défaut (Grafana surtout)
  • Ne pas exposer les ports 9090 et 9093 sur Internet sans authentification
  • Utilisez un reverse proxy (Nginx, Traefik) avec TLS et authentification
  • Activez le RBAC Grafana pour gérer les permissions par équipe

Labels et naming conventions
#

Adoptez une convention de labels cohérente dès le départ :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Bon
- targets: ["web-01:9100"]
  labels:
    env: production
    team: platform
    service: api-gateway

# Mauvais — labels incohérents
- targets: ["web-01:9100"]
  labels:
    environment: prod  # env vs environment ?
    TEAM: Platform     # casse incohérente

Performance
#

  • scrape_interval : 15s est un bon défaut. Descendez à 5s uniquement si nécessaire — chaque point de données coûte du stockage
  • Recording rules : pré-calculez les requêtes lourdes utilisées dans les dashboards
  • Limitez la cardinalité : évitez les labels à haute cardinalité (user_id, request_id…) — c’est le piège n°1 en production

Exemple de recording rule pour pré-calculer l’utilisation CPU :

1
2
3
4
5
groups:
  - name: recording_rules
    rules:
      - record: instance:node_cpu_utilisation:rate5m
        expr: 100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

Aller plus loin
#

Ce guide couvre les fondamentaux, mais l’écosystème Prometheus/Grafana est vaste. Voici les prochaines étapes :

  • Loki : agrégation de logs, requêtable depuis Grafana avec LogQL — le complément naturel de Prometheus
  • Tempo : tracing distribué, pour corréler métriques et traces
  • Mimir : stockage Prometheus long terme et multi-tenant, par Grafana Labs
  • Exporters spécialisés : blackbox-exporter (probes HTTP/TCP/ICMP), mysqld-exporter, postgres-exporter…
  • Service discovery : remplacez les static_configs par de la découverte automatique (Consul, Kubernetes, EC2…)
  • Grafana OnCall : gestion des astreintes et escalation, intégré à l’écosystème

Conclusion
#

Vous disposez maintenant d’un stack de monitoring fonctionnel avec Prometheus, Grafana, Node Exporter, cAdvisor et Alertmanager. En quelques commandes Docker Compose, vous avez :

  • ✅ Une collecte de métriques système et containers
  • ✅ Un stockage time-series avec 30 jours de rétention
  • ✅ Des dashboards de visualisation professionnels
  • ✅ Un système d’alerting avec notifications email/Slack
  • ✅ Des requêtes PromQL réutilisables pour vos cas d’usage

Le monitoring n’est pas un projet one-shot — c’est un processus continu. Commencez avec ce stack, ajoutez des exporters au fil de vos besoins, affinez vos alertes pour réduire le bruit, et faites évoluer vos dashboards avec votre infrastructure.

La règle d’or : si ce n’est pas monitoré, ça n’existe pas. Maintenant, vous avez les outils pour que tout existe.


Cet article fait partie de notre série sur l’observabilité. Retrouvez nos autres guides sur devopslab.ch.

Articles connexes