
Credit : Logo officiel
Creer un dashboard de monitoring avec Grafana
Pourquoi Grafana + Prometheus est devenu mon stack de monitoring par defaut
Lundi 8h45, alerte SMS : "web2.monsite.fr disk usage 92%". Le serveur d'un client tournait depuis 14 mois sans broncher, et logrotate avait silencieusement arrete de tourner sur un volume de logs Nginx en croissance constante. Sans Grafana et son alerte configuree 2 ans plus tot, je l'aurais decouvert quand le site serait tombe. La, 15 minutes pour purger, 5 pour relancer logrotate, 0 minute de downtime.
Grafana + Prometheus c'est la stack que j'utilise sur tous mes serveurs perso et chez plusieurs clients. La doc officielle est correcte mais suppose que vous savez deja ce que vous faites. Cet article est le guide que j'aurais aime trouver quand j'ai monte ma premiere stack en 2021 : installation, requetes PromQL utiles, dashboards a importer, alertes vraiment utiles, et les pieges qui font perdre 2 jours a chaque setup.
L'architecture en gros
[Serveurs cibles] [Serveur monitoring] [Vous]
node_exporter:9100 ----+
nginx_exporter:9113 ---+---> Prometheus:9090 ---> Grafana:3000 ---> Browser
mysql_exporter:9104 ---+ (scrape, store) (dashboards)
blackbox_exporter:9115 -+ (PromQL queries) (alertes)
Prometheus tire les metriques toutes les 15 secondes (modele pull). Grafana interroge Prometheus pour afficher des dashboards. Les exporters traduisent l'etat d'un systeme/service en metriques au format Prometheus.
Dimensionnement : un VPS 2 vCPU / 4 Go RAM tient 30 serveurs cibles avec 15 jours de retention. Au-dela, passer a 8 Go et SSD NVMe.
Installer node_exporter sur les serveurs a surveiller
node_exporter collecte CPU, RAM, disque, reseau, processus, etc. A installer sur CHAQUE machine a monitorer.
cd /tmp
VERSION=1.8.2
wget https://github.com/prometheus/node_exporter/releases/download/v${VERSION}/node_exporter-${VERSION}.linux-amd64.tar.gz
tar xzf node_exporter-${VERSION}.linux-amd64.tar.gz
sudo mv node_exporter-${VERSION}.linux-amd64/node_exporter /usr/local/bin/
sudo useradd -r -s /sbin/nologin node_exporter
Service systemd /etc/systemd/system/node_exporter.service :
[Unit]
Description=Prometheus Node Exporter
After=network.target
[Service]
User=node_exporter
Group=node_exporter
Type=simple
ExecStart=/usr/local/bin/node_exporter \
--web.listen-address=:9100 \
--collector.systemd \
--collector.processes
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now node_exporter
# Verifier
curl -s http://localhost:9100/metrics | head -20
sudo systemctl status node_exporter
Important : ne pas exposer le port 9100
Les exporters n'ont aucune authentification. Bloquer le port 9100 sur le pare-feu vis-a-vis d'Internet. Soit limiter via UFW :
sudo ufw allow from 10.0.0.5 to any port 9100 proto tcp
Soit utiliser un VPN entre Prometheus et les exporters (WireGuard est parfait pour ca). Cf hardening Linux.
Installer Prometheus sur le serveur de monitoring
VERSION=2.54.1
cd /tmp
wget https://github.com/prometheus/prometheus/releases/download/v${VERSION}/prometheus-${VERSION}.linux-amd64.tar.gz
tar xzf prometheus-${VERSION}.linux-amd64.tar.gz
sudo mv prometheus-${VERSION}.linux-amd64/{prometheus,promtool} /usr/local/bin/
sudo mkdir -p /etc/prometheus /var/lib/prometheus
sudo cp -r prometheus-${VERSION}.linux-amd64/{consoles,console_libraries} /etc/prometheus/
sudo useradd -r -s /sbin/nologin prometheus
sudo chown -R prometheus:prometheus /etc/prometheus /var/lib/prometheus
Config /etc/prometheus/prometheus.yml :
global:
scrape_interval: 15s
evaluation_interval: 15s
external_labels:
monitor: 'main'
rule_files:
- "alerts.yml"
alerting:
alertmanagers:
- static_configs:
- targets: ['localhost:9093']
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'nodes'
static_configs:
- targets:
- 'web1.monsite.fr:9100'
- 'web2.monsite.fr:9100'
- 'db1.monsite.fr:9100'
labels:
env: 'production'
- job_name: 'nginx'
static_configs:
- targets: ['web1.monsite.fr:9113', 'web2.monsite.fr:9113']
- job_name: 'mysql'
static_configs:
- targets: ['db1.monsite.fr:9104']
- job_name: 'blackbox'
metrics_path: /probe
params:
module: [http_2xx]
static_configs:
- targets:
- https://monsite.fr
- https://shop.monsite.fr
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: localhost:9115
Service systemd /etc/systemd/system/prometheus.service :
[Unit]
Description=Prometheus
After=network.target
[Service]
User=prometheus
Group=prometheus
Type=simple
ExecStart=/usr/local/bin/prometheus \
--config.file=/etc/prometheus/prometheus.yml \
--storage.tsdb.path=/var/lib/prometheus/ \
--storage.tsdb.retention.time=15d \
--web.console.templates=/etc/prometheus/consoles \
--web.console.libraries=/etc/prometheus/console_libraries \
--web.listen-address=127.0.0.1:9090
Restart=always
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now prometheus
# Verifier que les targets sont up
curl -s http://127.0.0.1:9090/api/v1/targets | jq '.data.activeTargets[] | {job:.labels.job,health}'
Installer Grafana
sudo apt install -y apt-transport-https software-properties-common gnupg
sudo mkdir -p /etc/apt/keyrings/
wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | sudo tee /etc/apt/keyrings/grafana.gpg > /dev/null
echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" \
| sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt update
sudo apt install grafana
sudo systemctl enable --now grafana-server
Acces sur http://serveur:3000 (admin/admin, changer immediatement).
Configurer la source de donnees Prometheus
Dans Grafana :
- Connections > Data sources > Add new data source
- Choisir Prometheus
- URL :
http://localhost:9090 - Save & Test
Vous devriez voir "Successfully queried the Prometheus API".
Importer des dashboards : ne reinventez pas la roue
Grafana a une bibliotheque enorme de dashboards prets a l'emploi. Mes incontournables :
| ID | Nom | Pour |
|---|---|---|
| 1860 | Node Exporter Full | Metriques systeme detaillees |
| 12708 | Node Exporter Quickstart | Vue d'ensemble simplifiee |
| 12559 | Linux Stats | Alternative legere |
| 12006 | NGINX | Stats Nginx |
| 7362 | MySQL Overview | MySQL/MariaDB |
| 13659 | Blackbox Exporter | Uptime checks |
Importer :
- Dashboards > New > Import
- Entrer l'ID (ex : 1860)
- Selectionner la source Prometheus
- Load
Le dashboard 1860 est massif : 200+ panels couvrant CPU, memoire, disque, reseau, IO, processus, conntrack. J'aurais mis 2 semaines a le refaire moi-meme.
Requetes PromQL essentielles
Pour creer vos propres panels ou comprendre les dashboards importes :
# CPU utilise en pourcentage
100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# Memoire utilisee en pourcentage
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100
# Espace disque utilise sur la partition root
(1 - node_filesystem_avail_bytes{mountpoint="/"}
/ node_filesystem_size_bytes{mountpoint="/"}) * 100
# Trafic reseau entrant en bytes par seconde
irate(node_network_receive_bytes_total{device="eth0"}[5m])
# Charge moyenne sur 1 minute
node_load1
# Uptime en jours
(time() - node_boot_time_seconds) / 86400
# Top 5 des processus consommant le plus de CPU
topk(5, rate(namedprocess_namegroup_cpu_seconds_total[5m]))
# Nombre de requetes Nginx par seconde
rate(nginx_http_requests_total[5m])
# Latence moyenne MySQL
avg(rate(mysql_global_status_questions[5m]))
# Disponibilite des sites (1 = up, 0 = down)
probe_success
# Certificat SSL expire dans X jours
(probe_ssl_earliest_cert_expiry - time()) / 86400
Alertes : la valeur reelle de la stack
Un dashboard sans alerte, c'est une jolie deco. Configurer les alertes dans /etc/prometheus/alerts.yml :
groups:
- name: serveurs
rules:
- 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 eleve sur {{ $labels.instance }}"
description: "CPU > 85% depuis 5 minutes (valeur actuelle: {{ $value | humanize }}%)"
- alert: DiskSpaceLow
expr: (1 - node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100 > 85
for: 10m
labels:
severity: critical
annotations:
summary: "Disque presque plein sur {{ $labels.instance }}"
- alert: InstanceDown
expr: up == 0
for: 2m
labels:
severity: critical
annotations:
summary: "{{ $labels.instance }} ne repond plus"
- alert: HighMemoryUsage
expr: (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 > 90
for: 5m
labels:
severity: warning
- alert: SslCertExpiringSoon
expr: (probe_ssl_earliest_cert_expiry - time()) / 86400 < 14
for: 1h
labels:
severity: warning
annotations:
summary: "Certificat SSL expire dans {{ $value | humanize }} jours"
- alert: NginxHighErrorRate
expr: rate(nginx_http_requests_total{status=~"5.."}[5m]) > 1
for: 5m
labels:
severity: warning
Verifier la syntaxe :
promtool check rules /etc/prometheus/alerts.yml
sudo systemctl reload prometheus
Notifications via Alertmanager ou Grafana
Deux options. Soit Alertmanager (more flexible), soit les contact points natifs de Grafana (plus simple).
Dans Grafana : Alerting > Contact points > New > selectionner Email/Slack/Discord/Telegram. Tester avec le bouton "Test".
Personnellement, j'utilise Alertmanager pour le routage avance (nuit = SMS uniquement critical, jour = mail + Slack).
Securiser Grafana en production
Ne JAMAIS exposer Grafana directement en HTTP sur Internet. Editer /etc/grafana/grafana.ini :
[server]
root_url = https://monitoring.monsite.fr/
serve_from_sub_path = false
http_addr = 127.0.0.1
http_port = 3000
[security]
admin_password = MotDePasseFort2026!
cookie_secure = true
strict_transport_security = true
strict_transport_security_max_age_seconds = 86400
content_security_policy = true
[users]
allow_sign_up = false
auto_assign_org_role = Viewer
[auth]
disable_login_form = false
oauth_auto_login = false
[smtp]
enabled = true
host = smtp.gmail.com:587
user = monitoring@monsite.fr
password = AppPassword
from_address = monitoring@monsite.fr
Reverse proxy Nginx avec SSL devant. Modele : reverse proxy Nginx avec SSL :
server {
listen 443 ssl http2;
server_name monitoring.monsite.fr;
ssl_certificate /etc/letsencrypt/live/monitoring.monsite.fr/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/monitoring.monsite.fr/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /api/live/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://127.0.0.1:3000;
}
}
Erreurs courantes et leur fix
1. Targets en "Down" dans Prometheus
90% du temps : pare-feu bloque le port 9100, ou node_exporter n'ecoute que sur 127.0.0.1. Verifier :
curl http://web1.monsite.fr:9100/metrics
sudo ss -tlnp | grep 9100
sudo ufw status
2. Disque /var/lib/prometheus se remplit vite
Retention par defaut 15 jours peut etre trop long. Reduire dans le service systemd : --storage.tsdb.retention.time=7d. Surveillance :
du -sh /var/lib/prometheus/
3. Dashboard 1860 affiche "No data"
Les labels ne matchent pas. Le dashboard utilise job="node" mais votre config utilise job="nodes". Soit renommer dans prometheus.yml, soit editer le dashboard pour ajuster les variables.
4. Alertes ne se declenchent pas
Verifier dans Prometheus UI > Alerts. Si "Pending" mais jamais "Firing", la duree for: est plus longue que l'incident. Reduire pour tester.
5. Grafana lent avec gros dashboards
Reduire le scrape_interval cause beaucoup de points. Soit downsampling avec recording rules :
groups:
- name: aggregations
interval: 1m
rules:
- record: instance:node_cpu:avg1m
expr: 100 - avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[1m])) * 100
Puis utiliser instance:node_cpu:avg1m dans les dashboards : 60x moins de points a charger.
Ajouter d'autres exporters utiles
L'ecosysteme Prometheus offre des exporters pour pratiquement tout. Ceux que j'ajoute systematiquement selon le contexte :
nginx_exporter
docker run -d --name nginx-exporter --restart unless-stopped \
-p 9113:9113 nginx/nginx-prometheus-exporter:latest \
-nginx.scrape-uri=http://nginx:8080/stub_status
Necessite d'activer le module stub_status dans Nginx :
location /stub_status {
stub_status;
access_log off;
allow 127.0.0.1;
deny all;
}
mysqld_exporter
VERSION=0.15.1
wget https://github.com/prometheus/mysqld_exporter/releases/download/v${VERSION}/mysqld_exporter-${VERSION}.linux-amd64.tar.gz
tar xzf mysqld_exporter-*.tar.gz
sudo mv mysqld_exporter-*/mysqld_exporter /usr/local/bin/
Fichier /etc/mysqld_exporter.cnf :
[client]
user=exporter
password=ExporterPassword!
User MySQL minimal :
CREATE USER 'exporter'@'localhost' IDENTIFIED BY 'ExporterPassword!';
GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'localhost';
blackbox_exporter
Indispensable pour surveiller la disponibilite externe de vos sites :
VERSION=0.25.0
wget https://github.com/prometheus/blackbox_exporter/releases/download/v${VERSION}/blackbox_exporter-${VERSION}.linux-amd64.tar.gz
tar xzf blackbox_exporter-*.tar.gz
sudo mv blackbox_exporter-*/blackbox_exporter /usr/local/bin/
Il mesure : disponibilite HTTP, code de retour, latence, validite du certificat SSL, expiration. Le dashboard 7587 affiche tout ca proprement.
Sauvegarder Grafana et Prometheus
Deux choses a sauvegarder :
- La base SQLite Grafana qui contient dashboards, users, datasources :
/var/lib/grafana/grafana.db - Les dashboards en JSON exportes (provisioning)
Script backup :
#!/bin/bash
DATE=$(date +%Y%m%d)
sudo systemctl stop grafana-server
cp /var/lib/grafana/grafana.db /backup/grafana_${DATE}.db
sudo systemctl start grafana-server
# Export des dashboards via API
for uid in $(curl -s -u admin:pwd http://localhost:3000/api/search | jq -r '.[].uid'); do
curl -s -u admin:pwd http://localhost:3000/api/dashboards/uid/${uid} \
> /backup/dashboards/${uid}.json
done
Les donnees temporelles Prometheus dans /var/lib/prometheus/ sont en general considerees comme jetables (15 jours de retention), mais si vous voulez les preserver, snapshot via API :
curl -XPOST http://127.0.0.1:9090/api/v1/admin/tsdb/snapshot
# Snapshot dans /var/lib/prometheus/snapshots/<timestamp>/
Pour aller plus loin
- Monitorer son serveur avec Netdata (alternative plus simple)
- Hardening Linux : securiser son serveur
- Bases de systemd et services Linux
- Reverse proxy Nginx avec SSL
- Les logs Linux : ou chercher et comment les lire
Du monitoring qui sert vraiment
Un bon dashboard Grafana, ce n'est pas celui qui a 80 panels colores. C'est celui qui repond en 5 secondes a la question "qu'est-ce qui cloche en ce moment ?". Mes regles : un dashboard "Overview" avec 6-8 panels max (CPU, RAM, disque, reseau, requetes/s, erreurs 5xx, latence, uptime), et des dashboards specialises (Nginx, MySQL, applicatifs) accessibles en un clic. Et surtout, des alertes calibrees : trop d'alertes tue les alertes. Mieux vaut 5 alertes par semaine pertinentes que 50 alertes "warning" qu'on apprend a ignorer. Le jour ou ca casse vraiment, vous voulez que le SMS reveille, pas qu'il soit le 30e de la nuit.