infra / monitoring-observabilite
Grafana : construire des dashboards
Explication
Ce que vous allez apprendre
- Installer Grafana et le connecter à Prometheus comme source de données
- Provisionner les datasources et les dashboards en fichiers de code plutôt qu'à la main
- Construire un dashboard avec les panels essentiels : débit, latence, taux d'erreur
- Rendre un dashboard réutilisable entre plusieurs services grâce aux variables
- Exporter un dashboard existant en JSON pour le versionner en Git
Dans quel contexte ?
L'équipe backend maîtrise maintenant PromQL, mais chaque investigation d'incident demande de retaper les mêmes requêtes à la main dans l'interface brute de Prometheus. Il faut un endroit permanent, visuel et partagé où toute l'équipe peut voir en un coup d'oeil l'état de mon-api — c'est exactement le rôle de Grafana, créé en 2014 par Torkel Ödegaard et devenu depuis le standard de facto pour la visualisation de métriques.
D'abord, Grafana a besoin d'une source de données
Grafana lui-même ne stocke aucune métrique : il ne fait que se connecter à des sources externes (Prometheus, Loki, MySQL, et bien d'autres) et afficher leurs résultats. La toute première étape consiste donc à déclarer Prometheus comme "datasource".
Deux façons d'y arriver : cliquer dans l'interface web, ou déclarer cette connexion dans un fichier YAML de provisioning. La seconde méthode est systématiquement préférée en production.
Une fois la datasource connectée, pourquoi éviter absolument le clic dans l'interface ?
Configurer Grafana uniquement à la souris ("clickops") fonctionne très bien... jusqu'au jour où le conteneur Grafana redémarre et perd tout, ou jusqu'à ce qu'il faille reproduire exactement la même configuration sur un second environnement. Le provisioning en fichiers résout ce problème une fois pour toutes.
| Approche | Survit à un redéploiement ? | Versionnable en Git ? | Reproductible sur un 2e environnement |
|---|---|---|---|
| Configuration via l'UI ("clickops") | Non (sauf volume persistant) | Non | Manuel, source d'erreurs |
| Provisioning YAML/JSON | Oui | Oui | Automatique |
Prérequis
Avoir Prometheus déjà installé et en train de scraper au moins une cible (voir les leçons précédentes) est indispensable : sans données à afficher, un dashboard reste une coquille vide.
Maintenant, la question centrale : quels panels mettre sur un premier dashboard ?
Il est tentant de vouloir tout afficher d'un coup. En réalité, un dashboard efficace commence toujours par les mêmes trois informations : le débit de requêtes, la latence en percentiles (P50/P95/P99), et le taux d'erreur — une préfiguration directe des "golden signals" que tu approfondiras en toute fin de cours.
Bonne pratique
Configure des seuils de couleur (vert/orange/rouge) sur tes panels de taux d'erreur, comme dans l'exemple JSON de cette leçon. Un chiffre nu de "2.3%" ne dit rien d'alarmant à l'oeil ; le même chiffre affiché en orange attire immédiatement l'attention lors d'une astreinte.
Il reste un problème une fois le premier dashboard construit : et s'il y a dix services à surveiller ?
Dupliquer le même dashboard dix fois, un par service, devient vite ingérable à maintenir : la moindre modification doit être répétée dix fois. Les variables de dashboard ($service, $env) résolvent ce problème en transformant les valeurs de labels en menus déroulants dynamiques en haut du dashboard.
Piège fréquent
Une variable de dashboard mal alimentée (par exemple label_values(métrique_inexistante, service)) affiche un menu déroulant vide, sans message d'erreur explicite. Vérifie toujours qu'au moins une série correspond réellement à la métrique utilisée dans la requête de la variable.
Le lien avec la suite
Un dashboard, aussi bien conçu soit-il, ne réveille personne à 3h du matin : il faut le regarder activement pour qu'il serve à quelque chose. La prochaine leçon aborde justement l'automatisation de cette surveillance, avec l'alerting Prometheus et Alertmanager.
Commandes & code
Grafana : construire des dashboards
# docker-compose.yml
services:
grafana:
image: grafana/grafana:11.1.0
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=changeme
volumes:
- grafana_data:/var/lib/grafana
- ./provisioning:/etc/grafana/provisioning:ro # provisioning as code, voir plus bas
volumes:
grafana_data:# provisioning/datasources/prometheus.yml — déclarer la source de données SANS clic dans l'UI
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
jsonData:
timeInterval: "15s"{
"title": "API — Vue d'ensemble",
"panels": [
{
"title": "Débit de requêtes",
"type": "timeseries",
"targets": [
{ "expr": "sum(rate(http_requests_total[5m])) by (status)", "legendFormat": "{{status}}" }
]
},
{
"title": "Latence P50 / P95 / P99",
"type": "timeseries",
"targets": [
{ "expr": "histogram_quantile(0.50, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))", "legendFormat": "P50" },
{ "expr": "histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))", "legendFormat": "P95" },
{ "expr": "histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))", "legendFormat": "P99" }
]
},
{
"title": "Taux d'erreur (%)",
"type": "stat",
"targets": [
{ "expr": "sum(rate(http_requests_total{status=~\"5..\"}[5m])) / sum(rate(http_requests_total[5m])) * 100" }
],
"fieldConfig": {
"defaults": { "thresholds": { "steps": [
{ "color": "green", "value": 0 },
{ "color": "orange", "value": 1 },
{ "color": "red", "value": 5 }
]}}
}
}
]
}# provisioning/dashboards/dashboards.yml — auto-charger les dashboards JSON au démarrage de Grafana
apiVersion: 1
providers:
- name: "default"
folder: "API"
type: file
options:
path: /etc/grafana/provisioning/dashboards/json# Variable de dashboard : rendre un dashboard réutilisable pour PLUSIEURS services/environnements
# Settings > Variables > name=service, query=label_values(http_requests_total, service)
sum(rate(http_requests_total{service="$service", env="$env"}[5m])) by (status)
# -> $service et $env deviennent des menus déroulants en haut du dashboard# Export/import d'un dashboard existant en JSON, pour le versionner en Git
curl -s -H "Authorization: Bearer $GRAFANA_TOKEN" \
http://localhost:3000/api/dashboards/uid/abc123 | jq '.dashboard' > dashboards/api-overview.jsonRésumé
- Provisionner les datasources ET les dashboards via des fichiers YAML/JSON versionnés en Git : jamais de configuration manuelle en prod (le "clickops" ne survit pas à un redéploiement).
- Un dashboard efficace commence toujours par : débit, latence (P50/P95/P99), taux d'erreur — les "golden signals" appliqués concrètement.
- Les variables de dashboard (
$service,$env) rendent un même dashboard réutilisable sur plusieurs services sans dupliquer les panels.
Exercices pratiques
Mission : dix services, un seul dashboard
Objectif : Provisionner Grafana en fichiers versionnés plutôt qu'à la main, et rendre un dashboard réutilisable entre plusieurs services grâce aux variables.
Contexte
L'équipe vient de dupliquer manuellement le même dashboard 10 fois, un par service, en cliquant dans l'UI Grafana. Le conteneur Grafana redémarre après une mise à jour et TOUT disparaît. Ta mission : reconstruire ça correctement, en provisioning, avec un seul dashboard variabilisé.