Aller au contenu
medium

Dashboards utiles : concevoir des tableaux de bord qui servent au diagnostic

26 min de lecture

Un dashboard utile répond à une question en moins de 5 secondes. Pourtant, la plupart des dashboards qu’on rencontre dans les organisations sont des murs de graphes : 40 panneaux, pas de hiérarchie, pas de contexte, ouverts une fois puis oubliés. Le problème n’est pas l’outil — c’est l’absence de méthode. Ce guide vous apprend à construire des dashboards structurés autour de deux frameworks éprouvés (RED pour les services, USE pour l’infrastructure) et à éviter les erreurs qui transforment un outil de diagnostic en source de bruit.

  • La philosophie : pourquoi la plupart des dashboards échouent et ce qui fait la différence
  • Le dashboard service (RED) : les panneaux essentiels pour une API ou un microservice, avec les requêtes PromQL prod-safe
  • Le dashboard infrastructure (USE) : CPU, mémoire, disque, réseau — organisés pour le diagnostic, avec des filtres adaptés à Kubernetes
  • Le dashboard overview : la vue d’ensemble qui relie services et infra
  • Le dashboard SLO : les 3 panneaux pour suivre vos objectifs métier
  • Les recording rules : pré-calculer les requêtes pour accélérer vos dashboards et réduire la charge
  • Les annotations : comment superposer déploiements et incidents sur vos graphes pour corréler cause et effet
  • Les variables et la navigation : templates Grafana pour un dashboard réutilisable
  • Les conventions : nommage, unités, seuils — la charte qui évite l’effet “un dashboard différent par équipe”
  • Les anti-patterns : les erreurs classiques qui rendent un dashboard inutile — et comment les corriger

Un dashboard mal conçu a trois symptômes caractéristiques :

  1. Personne ne l’ouvre — il a été créé “au cas où”, sans audience définie
  2. Tout le monde le regarde mais personne ne comprend — trop de panneaux, pas de hiérarchie, pas de contexte
  3. Il ralentit le diagnostic — au lieu de guider l’investigation, il noie l’opérateur sous les données

La cause est toujours la même : le dashboard a été construit par addition (on ajoute des panneaux quand on y pense) au lieu d’être construit par soustraction (on ne garde que ce qui répond à une question précise).

Avant de créer ou refondre un dashboard, répondez à ces trois questions :

  1. Qui va le consulter ? Un développeur, un SRE, un manager ?
  2. Quelle question essaie-t-il de résoudre ? “Mon service est-il dégradé ?” ou “Ai-je assez de CPU pour absorber le trafic de demain ?”
  3. Quelle action peut-il déclencher ? Si la réponse est “aucune”, le dashboard ne sert à rien

Un dashboard doit mener à une décision : scaler, rollback, investiguer les logs, créer un ticket, ou constater que tout va bien.

La méthode RED (Rate, Errors, Duration) a été formalisée par Tom Wilkie (Grafana) pour les services orientés requêtes : APIs, microservices, workers. Elle se concentre sur l’expérience vue par l’appelant — pas sur la santé interne du serveur.

PanneauQuestionCe qu’il montre
Rate”Combien de requêtes mon service traite-t-il ?”Débit (req/s), ventilé par endpoint si utile
Errors”Quelle proportion de requêtes échoue ?”Taux d’erreur (%), codes 5xx, exceptions
Duration”Combien de temps prend une requête ?”Latence p50, p90, p99

Le point de départ est la métrique http_requests_total (ou équivalent dans votre instrumentation). Voici les requêtes pour un service nommé payment-api. Toutes utilisent $__rate_interval au lieu d’un intervalle fixe — Grafana ajuste automatiquement cet intervalle au pas de temps du dashboard.

Rate — requêtes par seconde :

sum(rate(http_requests_total{service="$service"}[$__rate_interval]))

Cette requête calcule le nombre moyen de requêtes par seconde. Utilisez sum by (method) pour ventiler par méthode HTTP (GET, POST, etc.).

Error rate — pourcentage d’erreurs :

sum(rate(http_requests_total{service="$service", status=~"5.."}[$__rate_interval]))
/
sum(rate(http_requests_total{service="$service"}[$__rate_interval]))
* 100

Le status=~"5.." est une expression régulière qui capture tous les codes HTTP 5xx. Le résultat est un pourcentage : 0.5 = 0.5 % d’erreurs.

Duration — latence par percentile (global) :

histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket{service="$service"}[$__rate_interval]))
by (le)
)

Cette requête exploite un histogram pour calculer le 99e percentile (p99) de la latence. Le le (less than or equal) est le label interne des buckets d’histogram dans Prometheus. Pour afficher p50 et p90 sur le même graphe, ajoutez des requêtes identiques avec 0.50 et 0.90.

Un dashboard RED complet pour un service contient 5 à 8 panneaux, pas plus :

PositionPanneauType de visualisation
Ligne 1 (statuts)Taux de requêtes (req/s)Stat (grand chiffre)
Ligne 1Taux d’erreur (%)Stat (grand chiffre, rouge si > seuil)
Ligne 1Latence p99Stat (grand chiffre)
Ligne 2 (tendances)Rate dans le tempsTime series (graphe)
Ligne 2Error rate dans le tempsTime series (graphe)
Ligne 3 (détails)Latence p50 / p90 / p99Time series (3 courbes)
Ligne 3Top 5 endpoints les plus lentsTable
Ligne 4 (contexte)Logs récents (erreurs)Logs panel (Loki)

La première ligne donne la réponse immédiate : vert = tout va bien, rouge = quelque chose ne va pas. Les lignes suivantes permettent d’investiguer.

La méthode USE (Utilization, Saturation, Errors) a été créée par Brendan Gregg pour diagnostiquer les problèmes de performance des ressources matérielles : CPU, mémoire, disque, réseau.

RessourceUtilizationSaturationErrors
CPU% de temps CPU occupéLoad average / run queue
Mémoire% de RAM utiliséePages swappées / OOM killsECC errors (rare)
Disque% d’espace utilisé, IOPSI/O queue depth, latence I/OErreurs disque (SMART)
RéseauBande passante utilisée (%)Paquets droppés, retransmissions TCPErreurs d’interface

Ces requêtes utilisent les métriques exportées par node_exporter (Prometheus). Toutes les requêtes retournent un ratio entre 0 et 1 — dans Grafana, configurez l’unité du panneau en “Percent (0.0-1.0)” pour afficher le résultat en pourcentage lisible.

CPU — utilisation (ratio 0..1) :

1 - avg by (instance) (
rate(node_cpu_seconds_total{mode="idle", instance=~"$instance"}[$__rate_interval])
)

node_cpu_seconds_total est un counter qui cumule les secondes CPU par mode (idle, user, system, etc.). rate() le transforme en ratio par seconde. On soustrait le mode idle de 1 pour obtenir l’utilisation.

Mémoire — utilisation (ratio 0..1) :

1 - (
node_memory_MemAvailable_bytes{instance=~"$instance"}
/ node_memory_MemTotal_bytes{instance=~"$instance"}
)

MemAvailable (et non MemFree) est la bonne métrique car elle inclut les buffers et le cache récupérables par le système.

Disque — espace utilisé (ratio 0..1, filtré pour Kubernetes) :

1 - (
node_filesystem_avail_bytes{mountpoint="/", fstype!~"tmpfs|overlay|squashfs"}
/
node_filesystem_size_bytes{mountpoint="/", fstype!~"tmpfs|overlay|squashfs"}
)

Le filtre fstype!~"tmpfs|overlay|squashfs" exclut les systèmes de fichiers virtuels — indispensable sur Kubernetes où overlay (layers de conteneurs), tmpfs (emptyDir) et squashfs (snaps) polluent les graphes. Un seuil d’alerte classique est 85 % d’utilisation.

Réseau — trafic entrant (bits/s, interfaces réelles) :

sum by (instance) (
rate(node_network_receive_bytes_total{device!~"lo|veth.*|cni.*|docker.*|br-.*", instance=~"$instance"}[$__rate_interval])
) * 8

Le * 8 convertit les octets en bits (pour afficher en Mbps). Le filtre device!~"lo|veth.*|cni.*|docker.*|br-.*" exclut le loopback et les interfaces virtuelles (veth de conteneurs, bridges Docker, interfaces CNI). Le nom de l’interface physique varie (eth0, ens3, enp0s3…) — un filtre d’exclusion est plus robuste qu’un filtre d’inclusion.

PositionPanneauType
Ligne 1 (vue d’ensemble)CPU utilisation par nœudTime series
Ligne 1Mémoire disponible par nœudTime series
Ligne 2 (stockage)Espace disque (%) par mountGauge ou Bar gauge
Ligne 2IOPS lecture/écritureTime series
Ligne 3 (réseau)Trafic réseau in/outTime series
Ligne 3Erreurs réseau / dropsTime series
Ligne 4 (saturation)Load average (1m, 5m, 15m)Time series
Ligne 4Swap utiliséStat

Au-dessus des dashboards service et infra, créez un dashboard overview — la page d’accueil que le SRE ouvre en premier quand une alerte se déclenche.

PanneauSourceObjectif
Statut des services (vert/rouge)Taux d’erreur par serviceIdentifier quel service est impacté
Error rate globalSomme des erreurs tous servicesVoir la tendance générale
Latence p99 par serviceHistograms agrégésComparer les services entre eux
Alertes activesAlertmanager APIVoir les alertes en cours sans quitter le dashboard
Annotations : derniers déploiementsCI/CD → Grafana APICorréler un déploiement récent avec une dégradation

Ce dashboard ne doit jamais dépasser 10 panneaux. Son rôle est de diriger vers le bon dashboard service ou infra, pas de tout montrer.

Le workflow de diagnostic suit une logique descendante :

Overview (quel service ?)
→ Dashboard service RED (quel symptôme ?)
→ Dashboard infra USE (quelle ressource ?)
→ Logs / Traces (quelle requête, quel span ?)

Dans Grafana, utilisez les data links pour connecter les panneaux entre eux : un clic sur un service dans l’overview ouvre son dashboard RED. Un clic sur un nœud dans le dashboard RED ouvre le dashboard infra USE filtré sur ce nœud.

Si vous avez défini des SLO (Service Level Objectives), un dashboard dédié donne la vision métier de votre fiabilité. Ce n’est pas un remplacement du dashboard RED — c’est la vue que le product owner et le management consultent pour savoir si le service tient ses promesses.

PanneauRequête PromQL (exemple)Ce qu’il montre
Disponibilité (% succès sur 30 j)sum(rate(http_requests_total{service="$service", status!~"5.."}[$__rate_interval])) / sum(rate(http_requests_total{service="$service"}[$__rate_interval]))Ratio de requêtes réussies — comparer au SLO (ex: 99.9 %)
Latence SLO (% < seuil)sum(rate(http_request_duration_seconds_bucket{service="$service", le="0.3"}[$__rate_interval])) / sum(rate(http_request_duration_seconds_count{service="$service"}[$__rate_interval]))% de requêtes sous 300 ms — comparer au SLO (ex: 95 %)
Budget d’erreur restantCalcul basé sur le burn rate (voir guide Alerting)Budget consommé depuis le début de la fenêtre SLO

Le panneau de budget d’erreur est le plus puissant : il répond à la question “peut-on déployer une fonctionnalité risquée, ou sommes-nous déjà en zone rouge?”. Les détails sur le burn rate et le multi-window alerting sont couverts dans le guide dédié à l’alerting.

Quand un dashboard contient des panneaux avec des requêtes PromQL complexes (agrégations multi-dimensions, histogram_quantile, rate sur des millions de séries), chaque ouverture du dashboard exécute ces requêtes en temps réel sur Prometheus. Résultat : dashboards lents, charge élevée sur la datasource, et timeout quand la fenêtre de temps est longue.

Les recording rules pré-calculent le résultat d’une requête à intervalle régulier et stockent le résultat comme une nouvelle métrique. Le dashboard interroge cette métrique pré-calculée au lieu de recalculer à chaque affichage.

Au lieu que chaque ouverture du dashboard RED recalcule le taux d’erreur :

prometheus/rules/recording-rules.yaml
groups:
- name: red_dashboard_rules
interval: 30s
rules:
- record: service:http_requests:rate5m
expr: sum by (service) (rate(http_requests_total[5m]))
- record: service:http_errors:ratio_rate5m
expr: |
sum by (service) (rate(http_requests_total{status=~"5.."}[5m]))
/
sum by (service) (rate(http_requests_total[5m]))
- record: service:http_request_duration_seconds:p99
expr: |
histogram_quantile(0.99,
sum by (service, le) (rate(http_request_duration_seconds_bucket[5m]))
)

Dans le dashboard, remplacez la requête PromQL complexe par le nom de la recording rule :

service:http_errors:ratio_rate5m{service="$service"}
SituationRecording rule utile ?
Dashboard consulté par 1-2 personnes, fenêtre courteNon — overhead inutile
Dashboard consulté par 10+ personnes en parallèleOui — réduit la charge
Requête avec histogram_quantile sur 30+ servicesOui — le calcul est coûteux
Alerting basé sur la même requête qu’un dashboardOui — cohérence et performance
Requête simple (rate sur 1 série)Non — pas de gain

Un graphe de latence qui monte ne dit rien de la cause. Une annotation qui montre qu’un déploiement a eu lieu 2 minutes avant donne immédiatement le suspect n°1.

AnnotationSourceValeur
DéploiementCI/CD (GitLab, ArgoCD, Flux)“Est-ce que le déploiement de 14h32 a causé la régression ?”
IncidentPagerDuty, Opsgenie, Grafana OnCall”Cet incident est-il corrélé au pic de latence ?”
ScalingHPA Kubernetes, Auto Scaling Group”Le scaling a-t-il résolu le problème ou l’a-t-il causé ?”
Changement de configGit webhook, ConfigMap update”Qui a modifié la config à 16h05 ?”

Grafana expose une API HTTP pour créer des annotations. Pour créer une annotation globale (visible sur tous les dashboards), omettez le champ dashboardUID et utilisez des tags pour le filtrage :

# .gitlab-ci.yml — stage deploy
deploy:
stage: deploy
script:
- ./deploy.sh
- |
curl -s -X POST "${GRAFANA_URL}/api/annotations" \
-H "Authorization: Bearer ${GRAFANA_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"text": "Deploy '"${CI_PROJECT_NAME}"' v'"${CI_COMMIT_TAG}"'",
"tags": ["deploy", "'"${CI_ENVIRONMENT_NAME}"'", "'"${CI_PROJECT_NAME}"'"]
}'

En omettant dashboardUID, l’annotation est globale — elle apparaît dans tous les dashboards qui ont activé le filtre par tags correspondant. Pour cibler un dashboard spécifique, ajoutez "dashboardUID": "abc123".

Dans Grafana, activez l’affichage des annotations : Dashboard Settings → Annotations → Add → Grafana → Filter by Tags → deploy. Chaque dashboard peut choisir quels tags il affiche.

Les variables Grafana rendent un dashboard réutilisable sans duplication. Au lieu de créer un dashboard par service ou par nœud, vous créez un seul dashboard avec des sélecteurs.

VariableTypeRequêteUsage
$datasourceData sourcePermet de basculer entre clusters/environnements
$serviceQuerylabel_values(http_requests_total, service)Filtre par service
$namespaceQuerylabel_values(kube_pod_info, namespace)Filtre par namespace Kubernetes
$instanceQuerylabel_values(node_cpu_seconds_total{namespace="$namespace"}, instance)Filtre par nœud, scopé au namespace
  • Ajoutez un filtre All : cochez “Include All option” pour voir tous les services d’un coup — mais par défaut, sélectionnez un seul service pour éviter de surcharger le dashboard
  • Limitez la portée : une variable $instance sans filtre charge toutes les instances du cluster — ajoutez un filtre namespace en amont pour limiter
  • Limitez le nombre de valeurs : si une variable retourne 5 000 services, le dropdown devient inutilisable et le dashboard se bloque. Ajoutez un filtre regex dans la définition de la variable ou un limit dans la requête pour cap à 100-200 valeurs max
  • Utilisez $__rate_interval : dans toutes vos rate(), préférez [$__rate_interval] à un intervalle fixe comme [5m]. Cette variable s’ajuste automatiquement au pas de temps du dashboard
  • Ordonnez les variables : datasource → namespace → service → instance, du plus large au plus spécifique

Quand plusieurs équipes créent des dashboards, l’absence de convention produit un résultat chaotique : chaque dashboard a un style différent, des unités différentes, des seuils différents. Définir une charte de dashboards résout le problème.

ConventionRègleExemple
Nommage[Équipe] Service - TypePayments payment-api - RED
Titres de panneauxFormulés comme une question”Error rate — payment-api (%)“
Unitésreq/s, ms, %, bytes, bits/s — jamais d’unité ambiguëRatio 0..1 → format Grafana “Percent (0.0-1.0)“
Seuils visuelsVert < warning, orange < critical, rouge ≥ criticalError rate : vert < 0.1 %, orange < 1 %, rouge ≥ 1 %
CouleursRouge = mauvais, vert = bon — partout, sans exceptionPas de rouge pour “normal”
Time range par défaut6 h pour diagnostic, 24 h pour vue quotidienne, 7 j pour tendanceConfigurer par dashboard dans Settings → Time Range
DescriptionChaque dashboard a une description (Settings → General)“Dashboard RED du service payment-api — latence, erreurs, débit”

Deux options qui fonctionnent :

  1. Un dashboard “Template” : un dashboard vide avec les bonnes variables, les bons seuils, les bons dossiers — que les équipes dupliquent pour démarrer
  2. Une page dans votre wiki/documentation interne : les règles de nommage, unités et seuils, avec des exemples
Anti-patternPourquoi c’est un problèmeSolution
Dashboard de 40+ panneauxImpossible à lire, charge lente, aucune hiérarchie5-10 panneaux max par dashboard, organisés par question
Graphes sans titre explicite”Panel 1”, “Untitled” — impossible de comprendre sans lire la requêteTitre = la question que le panneau résout (“Error rate — payment-api”)
Moyenne seule (sans percentiles)Masque les outliers, donne une fausse impression de normalitéAfficher p50 + p99 minimum
Fenêtre de temps trop large par défaut30 jours de données = lent et illisible6 h ou 24 h par défaut, le SRE ajuste si besoin
Pas d’annotationsImpossible de corréler un changement avec un symptômeAnnotations de déploiement au minimum
Dashboard sans variableUn dashboard par service = duplication, maintenance impossibleVariables $service, $namespace au minimum
Panels qui query ”*“Charge toutes les séries du cluster = lent et coûteuxFiltres explicites (service, namespace) dans chaque requête
Refresh trop fréquentAuto-refresh à 5 s sur un dashboard avec 30 panneaux = DDoS sur la datasource30 s ou 1 min pour les dashboards opérationnels, 5 min pour les dashboards de tendance
Couleurs arbitrairesRouge pour “normal”, vert pour les erreurs — confusRouge = mauvais, vert = bon, partout, sans exception
Variables sans limiteUn dropdown qui retourne 5 000 services bloque le dashboard et surcharge PrometheusRegex ou limite dans la requête de variable (100-200 valeurs max)

Workflow : construire vos dashboards étape par étape

Section intitulée « Workflow : construire vos dashboards étape par étape »
  1. Identifiez vos services critiques

    Listez les 3-5 services dont la dégradation a le plus d’impact sur vos utilisateurs. Ce sont vos candidats prioritaires pour un dashboard RED.

  2. Créez le dashboard overview

    Un seul dashboard avec le statut (vert/rouge) de chaque service critique, les alertes actives et les derniers déploiements. C’est la porte d’entrée de votre observabilité.

  3. Créez un dashboard RED par service

    Pour chaque service : rate, error rate, latence (p50, p90, p99). Ajoutez les variables $service et $namespace. Ajoutez un panneau “derniers logs ERROR” si vous avez Loki. Ajoutez le panneau “Top 5 routes” pour le diagnostic fin.

  4. Créez un dashboard USE pour l’infrastructure

    CPU, mémoire, disque, réseau — organisé par nœud avec une variable $instance. Ajoutez le load average pour la saturation. Utilisez les filtres fstype et device adaptés à votre environnement.

  5. Ajoutez les recording rules

    Pour les requêtes les plus coûteuses (histograms, agrégations multi- services), créez des recording rules. Le dashboard référence la métrique pré-calculée au lieu de recalculer à chaque ouverture.

  6. Connectez les dashboards entre eux

    Ajoutez des data links : overview → service RED → infra USE. Le SRE doit pouvoir naviguer de “quel service est impacté ?” à “quel nœud est saturé ?” en 3 clics.

  7. Ajoutez les annotations

    Configurez l’envoi d’annotations depuis votre CI/CD. Au minimum : les déploiements. Si vous avez un outil d’incident management, ajoutez les incidents.

  8. Revoyez et élaguez

    Après 2 semaines d’utilisation, demandez aux utilisateurs : “Quels panneaux avez-vous réellement consultés ?” Supprimez le reste. Un bon dashboard est un dashboard qui a été élagué.

PiègeConséquenceSolution
Construire le dashboard avant de savoir quoi mesurerDashboard sans direction, panneaux inutilesChoisir le framework (RED/USE) d’abord, puis les panneaux
Copier un dashboard communautaire sans l’adapter50 panneaux dont 45 inutiles pour votre contextePartir d’un dashboard vide, ajouter panneau par panneau
Mélanger RED et USE dans le même dashboardConfusion entre symptôme service et cause infra1 dashboard RED (service) + 1 dashboard USE (infra), reliés par data links
Pas de convention de nommage”Dashboard API”, “Mon dashboard”, “test-2” — introuvableConvention : [Équipe] Service - Type (ex: “Payments payment-api - RED”)
Alerter depuis le dashboardLes alertes dépendent du dashboard, pas de règles centraliséesSéparer alerting (recording rules + Alertmanager) et dashboards (visualisation)
  1. Un dashboard utile répond à une question précise en moins de 5 secondes — s’il faut chercher, c’est raté

  2. Utilisez la méthode RED (Rate, Errors, Duration) pour les services orientés requêtes et la méthode USE (Utilization, Saturation, Errors) pour l’infrastructure

  3. Organisez vos dashboards en trois niveaux : overview → service RED → infra USE, connectés par des data links

  4. Les annotations de déploiement sont le moyen le plus simple de corréler un changement avec un incident — envoyez-les comme annotations globales (sans dashboardUID) avec des tags pour le filtrage

  5. Les recording rules pré-calculent les requêtes coûteuses et accélèrent vos dashboards — indispensable dès que plusieurs personnes consultent les mêmes panneaux

  6. Les variables Grafana ($service, $namespace, $instance) rendent un dashboard réutilisable — mais limitez le nombre de valeurs retournées pour éviter les dropdown de 5 000 entrées

  7. Affichez toujours les percentiles (p50, p99), jamais la moyenne seule — et affichez le p99 par route en complément du p99 global

  8. Définissez une charte de dashboards (nommage, unités, seuils, couleurs) pour que les dashboards de toutes les équipes restent cohérents

  9. Un dashboard non consulté depuis 90 jours doit être archivé ou supprimé — la maintenance invisible a un coût

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.