Grafana
Overviewπ
Grafana is an open-source observability platform for visualizing metrics, logs, and traces from multiple data sources.
Key Features:
- Multi-source data visualization
- Interactive dashboards
- Alerting and notifications
- Support for 150+ data sources
- Template variables for dynamic dashboards
- Panel library and sharing
Installationπ
Dockerπ
docker run -d -p 3000:3000 --name=grafana grafana/grafanaDocker with persistent storageπ
docker run -d -p 3000:3000 \
--name=grafana \
-v grafana-storage:/var/lib/grafana \
grafana/grafanaDocker Composeπ
version: '3'
services:
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
volumes:
- grafana-data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
- GF_USERS_ALLOW_SIGN_UP=false
volumes:
grafana-data:Kubernetes (with Helm)π
helm repo add grafana https://grafana.github.io/helm-charts
helm install grafana grafana/grafanaLinux (Debian/Ubuntu)π
sudo apt-get install -y software-properties-common
sudo add-apt-repository "deb https://packages.grafana.com/oss/deb stable main"
wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
sudo apt-get update
sudo apt-get install grafana
sudo systemctl start grafana-server
sudo systemctl enable grafana-serverDefault Credentialsπ
- URL: http://localhost:3000
- Username:
admin - Password:
admin(change on first login)
Configurationπ
Main Configuration Fileπ
Location: /etc/grafana/grafana.ini (Linux) or conf/defaults.ini
[server]
http_port = 3000
domain = localhost
root_url = %(protocol)s://%(domain)s:%(http_port)s/
[database]
type = sqlite3
path = grafana.db
[security]
admin_user = admin
admin_password = admin
[users]
allow_sign_up = false
allow_org_create = false
[auth.anonymous]
enabled = false
[smtp]
enabled = true
host = smtp.gmail.com:587
user = your-email@gmail.com
password = your-password
from_address = grafana@yourdomain.comEnvironment Variablesπ
# Set admin password
GF_SECURITY_ADMIN_PASSWORD=mypassword
# Disable anonymous access
GF_AUTH_ANONYMOUS_ENABLED=false
# Set SMTP
GF_SMTP_ENABLED=true
GF_SMTP_HOST=smtp.gmail.com:587
GF_SMTP_USER=email@example.com
GF_SMTP_PASSWORD=passwordData Sourcesπ
Add Prometheus Data Sourceπ
Via UI:
- Configuration β Data Sources β Add data source
- Select Prometheus
- URL:
http://prometheus:9090 - Click βSave & Testβ
Via provisioning (/etc/grafana/provisioning/datasources/prometheus.yml):
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
editable: trueAdd MySQL Data Sourceπ
apiVersion: 1
datasources:
- name: MySQL
type: mysql
url: mysql-host:3306
database: mydb
user: grafana
secureJsonData:
password: 'password'Add PostgreSQL Data Sourceπ
apiVersion: 1
datasources:
- name: PostgreSQL
type: postgres
url: postgres-host:5432
database: mydb
user: grafana
secureJsonData:
password: 'password'
jsonData:
sslmode: disableAdd Loki Data Sourceπ
apiVersion: 1
datasources:
- name: Loki
type: loki
access: proxy
url: http://loki:3100
jsonData:
maxLines: 1000Add Elasticsearch Data Sourceπ
apiVersion: 1
datasources:
- name: Elasticsearch
type: elasticsearch
access: proxy
url: http://elasticsearch:9200
database: "[logs-]YYYY.MM.DD"
jsonData:
esVersion: "7.10.0"
timeField: "@timestamp"Dashboardsπ
Create Dashboard via UIπ
- Click β+β β Dashboard
- Click βAdd new panelβ
- Configure query and visualization
- Click βApplyβ
- Click βSave dashboardβ
Import Dashboardπ
- Click β+β β Import
- Enter dashboard ID or JSON
- Select data source
- Click βImportβ
Popular Dashboard IDs:
- Node Exporter Full:
1860 - Kubernetes Cluster Monitoring:
7249 - Docker Dashboard:
893 - MySQL Overview:
7362 - NGINX:
12708
Export Dashboardπ
- Dashboard Settings (gear icon) β JSON Model
- Copy JSON or click βSave to fileβ
Dashboard Provisioningπ
Create /etc/grafana/provisioning/dashboards/dashboard.yml:
apiVersion: 1
providers:
- name: 'Default'
orgId: 1
folder: ''
type: file
disableDeletion: false
updateIntervalSeconds: 10
options:
path: /var/lib/grafana/dashboards
Place dashboard JSON files in /var/lib/grafana/dashboards/
Dashboard JSON Exampleπ
{
"dashboard": {
"title": "My Dashboard",
"panels": [
{
"id": 1,
"type": "graph",
"title": "CPU Usage",
"targets": [
{
"expr": "100 - (avg(rate(node_cpu_seconds_total{mode=\"idle\"}[5m])) * 100)",
"refId": "A"
}
]
}
],
"time": {
"from": "now-6h",
"to": "now"
},
"refresh": "5s"
}
}Panels & Visualizationsπ
Panel Typesπ
Time Series (Graph)π
Best for: Metrics over time
{
"type": "timeseries",
"targets": [
{
"expr": "rate(http_requests_total[5m])"
}
]
}Statπ
Best for: Single numeric value
{
"type": "stat",
"targets": [
{
"expr": "sum(up)"
}
],
"options": {
"graphMode": "area",
"colorMode": "value"
}
}Gaugeπ
Best for: Percentage or threshold visualization
{
"type": "gauge",
"targets": [
{
"expr": "(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100"
}
],
"fieldConfig": {
"defaults": {
"max": 100,
"min": 0,
"thresholds": {
"steps": [
{"color": "green", "value": 0},
{"color": "yellow", "value": 70},
{"color": "red", "value": 90}
]
}
}
}
}Bar Chartπ
Best for: Comparing values across categories
{
"type": "barchart",
"targets": [
{
"expr": "sum(http_requests_total) by (method)"
}
]
}Tableπ
Best for: Tabular data display
{
"type": "table",
"targets": [
{
"expr": "up",
"format": "table"
}
]
}Heatmapπ
Best for: Distribution over time
{
"type": "heatmap",
"targets": [
{
"expr": "rate(http_request_duration_seconds_bucket[5m])"
}
]
}Pie Chartπ
Best for: Part-to-whole relationships
{
"type": "piechart",
"targets": [
{
"expr": "sum(http_requests_total) by (status_code)"
}
]
}Logs Panelπ
Best for: Log entries from Loki
{
"type": "logs",
"datasource": "Loki",
"targets": [
{
"expr": "{job=\"varlogs\"}"
}
]
}Panel Optionsπ
Thresholdsπ
{
"thresholds": {
"mode": "absolute",
"steps": [
{"value": 0, "color": "green"},
{"value": 80, "color": "yellow"},
{"value": 100, "color": "red"}
]
}
}Value Mappingsπ
{
"mappings": [
{
"type": "value",
"options": {
"0": {"text": "Down", "color": "red"},
"1": {"text": "Up", "color": "green"}
}
}
]
}Overridesπ
{
"overrides": [
{
"matcher": {"id": "byName", "options": "Series 1"},
"properties": [
{"id": "color", "value": {"mode": "fixed", "fixedColor": "blue"}}
]
}
]
}Variablesπ
Query Variableπ
Name: instance
Type: Query
Data source: Prometheus
Query: label_values(up, instance)
Refresh: On Dashboard Load
Usage in query:
up{instance="$instance"}Custom Variableπ
Name: environment
Type: Custom
Values: production,staging,developmentInterval Variableπ
Name: interval
Type: Interval
Values: 1m,5m,10m,30m,1h
Auto: enabled
Usage in query:
rate(http_requests_total[$interval])Constant Variableπ
Name: threshold
Type: Constant
Value: 80Data Source Variableπ
Name: datasource
Type: Data source
Type: Prometheus
Usage:
Select data source: ${datasource}
Chained Variablesπ
Variable 1:
Name: region
Query: label_values(up, region)
Variable 2:
Name: instance
Query: label_values(up{region="$region"}, instance)Multi-value Variablesπ
Enable βMulti-valueβ option to select multiple values.
Usage in query:
up{instance=~"$instance"}Transformationsπ
Common Transformationsπ
Filter by nameπ
Filter series by name pattern.
Rename by regexπ
Regex: (.*)_total
Replace: $1Organize fieldsπ
Reorder, hide, or rename fields.
Join by fieldπ
Combine data from multiple queries.
Add field from calculationπ
Mode: Reduce row
Calculation: Mean
Alias: averageFilter data by valueπ
Match: All conditions
Condition: temperature > 30Group byπ
Group by: hostname
Aggregation: MeanTransformation Exampleπ
{
"transformations": [
{
"id": "filterByName",
"options": {
"include": {
"pattern": "^temp.*"
}
}
},
{
"id": "organize",
"options": {
"excludeByName": {},
"indexByName": {},
"renameByName": {
"temp_celsius": "Temperature (Β°C)"
}
}
}
]
}Alertingπ
Create Alert Ruleπ
Via UI:
- Panel β Alert tab
- Create alert rule
- Define query and conditions
- Set evaluation interval
- Configure notifications
Alert Rule Example:
apiVersion: 1
groups:
- orgId: 1
name: my-alerts
folder: alerts
interval: 1m
rules:
- uid: alert1
title: High CPU Usage
condition: A
data:
- refId: A
datasourceUid: prometheus-uid
model:
expr: 100 - (avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
refId: A
noDataState: NoData
execErrState: Alerting
for: 5m
annotations:
description: CPU usage is above 80%
labels:
severity: warningNotification Channelsπ
Emailπ
apiVersion: 1
notifiers:
- name: Email
type: email
uid: email1
settings:
addresses: admin@example.com;ops@example.comSlackπ
apiVersion: 1
contactPoints:
- orgId: 1
name: Slack
receivers:
- uid: slack1
type: slack
settings:
url: https://hooks.slack.com/services/YOUR/WEBHOOK/URL
text: |
{{ range .Alerts }}
Alert: {{ .Labels.alertname }}
Status: {{ .Status }}
{{ end }}PagerDutyπ
apiVersion: 1
contactPoints:
- orgId: 1
name: PagerDuty
receivers:
- uid: pd1
type: pagerduty
settings:
integrationKey: YOUR_INTEGRATION_KEYWebhookπ
apiVersion: 1
contactPoints:
- orgId: 1
name: Webhook
receivers:
- uid: webhook1
type: webhook
settings:
url: https://api.example.com/alerts
httpMethod: POSTNotification Policyπ
apiVersion: 1
policies:
- orgId: 1
receiver: default-email
group_by: ['alertname', 'cluster']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- receiver: slack
matchers:
- severity = critical
- receiver: pagerduty
matchers:
- severity = critical
- team = opsAnnotationsπ
Create Annotationπ
{
"dashboardId": 1,
"panelId": 1,
"time": 1609459200000,
"text": "Deployment v2.0",
"tags": ["deployment", "release"]
}Query Annotations from Prometheusπ
Data source: Prometheus
Query: ALERTS{alertname="InstanceDown"}
Title field: alertname
Text field: summary
Tags field: severityAPI Examplesπ
Authenticationπ
# API key (recommended)
curl -H "Authorization: Bearer YOUR_API_KEY" http://localhost:3000/api/...
# Basic auth
curl -u admin:password http://localhost:3000/api/...Create API Keyπ
curl -X POST http://admin:admin@localhost:3000/api/auth/keys \
-H "Content-Type: application/json" \
-d '{
"name": "mykey",
"role": "Admin"
}'Get All Dashboardsπ
curl -H "Authorization: Bearer YOUR_API_KEY" \
http://localhost:3000/api/search?type=dash-dbGet Dashboard by UIDπ
curl -H "Authorization: Bearer YOUR_API_KEY" \
http://localhost:3000/api/dashboards/uid/DASHBOARD_UIDCreate/Update Dashboardπ
curl -X POST http://localhost:3000/api/dashboards/db \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"dashboard": {
"title": "My Dashboard",
"panels": []
},
"overwrite": true
}'Delete Dashboardπ
curl -X DELETE http://localhost:3000/api/dashboards/uid/DASHBOARD_UID \
-H "Authorization: Bearer YOUR_API_KEY"Get Data Sourcesπ
curl -H "Authorization: Bearer YOUR_API_KEY" \
http://localhost:3000/api/datasourcesCreate Data Sourceπ
curl -X POST http://localhost:3000/api/datasources \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Prometheus",
"type": "prometheus",
"url": "http://prometheus:9090",
"access": "proxy",
"isDefault": true
}'Query Data Sourceπ
curl -X POST http://localhost:3000/api/ds/query \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"queries": [
{
"datasource": {"type": "prometheus"},
"expr": "up",
"refId": "A"
}
],
"from": "now-1h",
"to": "now"
}'Create Organizationπ
curl -X POST http://localhost:3000/api/orgs \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "New Org"}'Create Userπ
curl -X POST http://localhost:3000/api/admin/users \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe",
"email": "john@example.com",
"login": "john",
"password": "password"
}'Get Current Userπ
curl -H "Authorization: Bearer YOUR_API_KEY" \
http://localhost:3000/api/userCreate Snapshotπ
curl -X POST http://localhost:3000/api/snapshots \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"dashboard": ,
"name": "My Snapshot",
"expires": 3600
}'Provisioningπ
Directory Structureπ
/etc/grafana/provisioning/
βββ dashboards/
β βββ dashboard.yml
β βββ my-dashboard.json
βββ datasources/
β βββ datasource.yml
βββ notifiers/
β βββ notifier.yml
βββ alerting/
βββ alert-rules.yml
βββ notification-policies.ymlComplete Exampleπ
datasources/prometheus.yml:
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
dashboards/default.yml:
apiVersion: 1
providers:
- name: 'Default'
orgId: 1
folder: ''
type: file
options:
path: /var/lib/grafana/dashboardsBest Practicesπ
Dashboard Designπ
- Use consistent time ranges
- Group related panels
- Use appropriate visualizations
- Add descriptions to panels
- Use template variables for flexibility
- Keep dashboards focused (single purpose)
Performanceπ
- Limit time ranges for heavy queries
- Use recording rules in Prometheus
- Avoid too many panels per dashboard (< 20)
- Use appropriate refresh intervals
- Cache query results when possible
Organizationπ
- Use folders to organize dashboards
- Tag dashboards appropriately
- Use naming conventions
- Document complex queries
- Version control dashboard JSON
Securityπ
- Use API keys instead of passwords
- Implement role-based access control
- Enable HTTPS
- Regular backups
- Update Grafana regularly
Alertingπ
- Set appropriate thresholds
- Avoid alert fatigue (donβt over-alert)
- Group related alerts
- Use meaningful alert names
- Include context in notifications
- Test alerts before production
Keyboard Shortcutsπ
| Shortcut | Action |
|---|---|
g + h | Go to home dashboard |
g + p | Go to profile |
g + e | Open explore |
s | Open search |
f | Open dashboard finder |
d + k | Toggle kiosk mode |
d + e | Expand all rows |
d + s | Dashboard settings |
d + v | Toggle in-active/active panel |
Ctrl + S | Save dashboard |
Esc | Exit panel edit/settings |
? | Show keyboard shortcuts |
Resourcesπ
- Official documentation: https://grafana.com/docs/
- Community dashboards: https://grafana.com/grafana/dashboards/
- Plugins: https://grafana.com/grafana/plugins/
- Tutorials: https://grafana.com/tutorials/
- Community forum: https://community.grafana.com/
- GitHub: https://github.com/grafana/grafana