Grafana
1 - Présentation
Grafana est la plateforme de visualisation et d'observabilité la plus populaire.
2 - Installation
2.1 Docker
# docker-compose.yml
version: '3.8'
services:
grafana:
image: grafana/grafana:10.2.0
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
- GF_USERS_ALLOW_SIGN_UP=false
volumes:
- grafana_data:/var/lib/grafana
- ./provisioning:/etc/grafana/provisioning
volumes:
grafana_data:
2.2 Kubernetes
helm repo add grafana https://grafana.github.io/helm-charts
helm install grafana grafana/grafana \
--namespace monitoring \
--set adminPassword=admin \
--set persistence.enabled=true
3 - Data Sources
3.1 Provisioning
# provisioning/datasources/datasources.yml
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
editable: false
- name: Loki
type: loki
access: proxy
url: http://loki:3100
- name: Tempo
type: tempo
access: proxy
url: http://tempo:3200
jsonData:
tracesToLogs:
datasourceUid: loki
tags: ['service.name']
3.2 Configuration par API
# Créer une data source via API
curl -X POST http://admin:admin@localhost:3000/api/datasources \
-H "Content-Type: application/json" \
-d '{
"name": "Prometheus",
"type": "prometheus",
"url": "http://prometheus:9090",
"access": "proxy",
"isDefault": true
}'
4 - Dashboards
4.1 Structure JSON
{
"dashboard": {
"title": "My Dashboard",
"tags": ["monitoring", "production"],
"timezone": "browser",
"panels": [
{
"id": 1,
"title": "Request Rate",
"type": "timeseries",
"gridPos": { "x": 0, "y": 0, "w": 12, "h": 8 },
"targets": [
{
"expr": "rate(http_requests_total[5m])",
"legendFormat": "{{method}} {{status}}"
}
]
}
],
"templating": {
"list": []
},
"time": {
"from": "now-1h",
"to": "now"
}
}
}
4.2 Provisioning Dashboards
# provisioning/dashboards/default.yml
apiVersion: 1
providers:
- name: 'default'
folder: 'Provisioned'
type: file
disableDeletion: true
updateIntervalSeconds: 30
options:
path: /etc/grafana/provisioning/dashboards
5 - Panels
5.1 Types de panels
| Panel | Usage |
|---|---|
| Time series | Graphiques temporels |
| Stat | Valeur unique |
| Gauge | Jauge visuelle |
| Bar gauge | Barres |
| Table | Données tabulaires |
| Heatmap | Distribution |
| Logs | Affichage des logs |
5.2 Time series
{
"type": "timeseries",
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"drawStyle": "line",
"lineInterpolation": "smooth",
"fillOpacity": 20
},
"unit": "reqps"
}
},
"options": {
"legend": {
"displayMode": "table",
"placement": "bottom",
"calcs": ["mean", "max", "last"]
}
}
}
5.3 Stat Panel
{
"type": "stat",
"fieldConfig": {
"defaults": {
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 50 },
{ "color": "red", "value": 80 }
]
},
"unit": "percent"
}
},
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "horizontal"
}
}
6 - Variables (Templates)
6.1 Types de variables
variables:
# Query variable
- name: namespace
type: query
datasource: Prometheus
query: label_values(kube_pod_info, namespace)
refresh: on_time_range_change
# Custom variable
- name: environment
type: custom
options:
- { text: "Production", value: "prod" }
- { text: "Staging", value: "staging" }
# Interval variable
- name: interval
type: interval
options: ["1m", "5m", "15m", "1h"]
auto: true
auto_count: 30
6.2 Utilisation dans les queries
# Utiliser les variables
rate(http_requests_total{namespace="$namespace"}[$__interval])
# Multi-value
rate(http_requests_total{namespace=~"$namespace"}[5m])
6.3 Chained Variables
variables:
- name: cluster
query: label_values(kube_pod_info, cluster)
- name: namespace
query: label_values(kube_pod_info{cluster="$cluster"}, namespace)
- name: pod
query: label_values(kube_pod_info{cluster="$cluster", namespace="$namespace"}, pod)
7 - Alerting
7.1 Alert Rules
# Alert rule via provisioning
apiVersion: 1
groups:
- name: http-alerts
folder: HTTP
interval: 1m
rules:
- uid: high-error-rate
title: High Error Rate
condition: B
data:
- refId: A
relativeTimeRange:
from: 300
to: 0
datasourceUid: prometheus
model:
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m]))
/ sum(rate(http_requests_total[5m])) * 100
- refId: B
relativeTimeRange:
from: 0
to: 0
datasourceUid: '-100'
model:
conditions:
- evaluator:
params: [5]
type: gt
operator:
type: and
query:
params: [A]
reducer:
type: avg
for: 5m
labels:
severity: critical
annotations:
summary: "Error rate above 5%"
7.2 Contact Points
# Contact point configuration
contactPoints:
- name: slack-notifications
receivers:
- uid: slack
type: slack
settings:
url: https://hooks.slack.com/services/xxx
recipient: "#alerts"
- name: pagerduty-critical
receivers:
- uid: pagerduty
type: pagerduty
settings:
integrationKey: xxx
severity: critical
7.3 Notification Policies
policies:
- receiver: slack-notifications
group_by: ['alertname', 'severity']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- receiver: pagerduty-critical
matchers:
- severity = critical
continue: true
8 - Dashboard Best Practices
8.1 Layout recommandé
┌─────────────────────────────────────────────────┐
│ Variables │
├─────────────────────────────────────────────────┤
│ Request Rate │ Error Rate │ Latency P99 │ Uptime│ <- Stat panels
├────── ───────────────────────────────────────────┤
│ │
│ Request Rate Graph │ <- Time series
│ │
├─────────────────────────────────────────────────┤
│ │
│ Latency Distribution │ <- Heatmap
│ │
├─────────────────────────────────────────────────┤
│ Top Endpoints Table │ <- Table
└─────────────────────────────────────────────────┘
8.2 Conventions
| Aspect | Recommandation |
|---|---|
| Couleurs | Vert=OK, Jaune=Warning, Rouge=Critical |
| Noms | Descriptifs, incluant l'unité |
| Requêtes | Utiliser des Recording Rules |
| Variables | Namespace, Environment, Service |
Résumé
Dans ce chapitre, nous avons appris :
- L'installation de Grafana
- La configuration des Data Sources
- La création de Dashboards
- Les différents types de Panels
- Les Variables et templates
- L'Alerting intégré
- Les bonnes pratiques
Prochaine étape
Dans le prochain chapitre, nous verrons ELK Stack.
→ Chapitre suivant : ELK Stack