Commands & Recipes
Installation
Docker (Quick Start)
# Latest OSS version
docker run -d --name grafana \
-p 3000:3000 \
-v grafana-data:/var/lib/grafana \
grafana/grafana-oss:latest
# With environment variable overrides
docker run -d --name grafana \
-p 3000:3000 \
-e GF_SECURITY_ADMIN_PASSWORD=mysecretpassword \
-e GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-piechart-panel \
-e GF_DATABASE_TYPE=postgres \
-e GF_DATABASE_HOST=postgres:5432 \
-e GF_DATABASE_NAME=grafana \
-e GF_DATABASE_USER=grafana \
-e GF_DATABASE_PASSWORD=dbpassword \
grafana/grafana-oss:latest
Docker Compose (LGTM Stack)
# docker-compose.yml — Minimal LGTM stack for development
version: '3.8'
services:
grafana:
image: grafana/grafana-oss:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana-data:/var/lib/grafana
- ./provisioning:/etc/grafana/provisioning
mimir:
image: grafana/mimir:latest
command: ["-config.file=/etc/mimir/config.yaml", "-target=all"]
ports:
- "9009:9009"
volumes:
- ./mimir-config.yaml:/etc/mimir/config.yaml
loki:
image: grafana/loki:latest
ports:
- "3100:3100"
command: ["-config.file=/etc/loki/local-config.yaml"]
tempo:
image: grafana/tempo:latest
ports:
- "3200:3200" # Tempo API
- "4317:4317" # OTLP gRPC
- "4318:4318" # OTLP HTTP
command: ["-config.file=/etc/tempo/config.yaml"]
volumes:
- ./tempo-config.yaml:/etc/tempo/config.yaml
alloy:
image: grafana/alloy:latest
ports:
- "12345:12345" # Debug UI
volumes:
- ./alloy-config.alloy:/etc/alloy/config.alloy
command: ["run", "/etc/alloy/config.alloy"]
volumes:
grafana-data:
Helm (Kubernetes Production)
# Add Grafana Helm repo
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
# Install Grafana
helm install grafana grafana/grafana \
--namespace monitoring \
--create-namespace \
--set replicas=3 \
--set persistence.enabled=false \
--set database.type=postgres \
--set "grafana.ini.database.host=postgres.internal:5432" \
--set "grafana.ini.database.name=grafana" \
--set "grafana.ini.database.user=grafana" \
--set "grafana.ini.database.password=${DB_PASSWORD}" \
--set "grafana.ini.server.root_url=https://grafana.example.com"
# Install Mimir (distributed mode)
helm install mimir grafana/mimir-distributed \
--namespace monitoring \
-f mimir-values.yaml
# Install Loki
helm install loki grafana/loki \
--namespace monitoring \
-f loki-values.yaml
# Install Tempo
helm install tempo grafana/tempo-distributed \
--namespace monitoring \
-f tempo-values.yaml
# Install Alloy (DaemonSet)
helm install alloy grafana/alloy \
--namespace monitoring \
-f alloy-values.yaml
Homebrew (macOS)
brew install grafana
brew services start grafana
# Access at http://localhost:3000 (admin/admin)
grafana-cli Commands
Plugin Management
# Install a plugin
grafana-cli plugins install grafana-piechart-panel
# Install specific version
grafana-cli plugins install grafana-piechart-panel 1.6.4
# List installed plugins
grafana-cli plugins ls
# List all available plugins
grafana-cli plugins list-remote
# Update all plugins
grafana-cli plugins update-all
# Remove a plugin
grafana-cli plugins remove grafana-piechart-panel
# Install from a custom URL (private/unsigned)
grafana-cli --pluginUrl https://example.com/plugin.zip plugins install custom-plugin
Admin Commands
# Reset admin password
grafana-cli admin reset-admin-password MyNewPassword
# Reset admin password (custom install path)
grafana-cli --homepath /usr/share/grafana \
--config /etc/grafana/grafana.ini \
admin reset-admin-password MyNewPassword
# Encrypt data source passwords (migrate to secure_json_data)
grafana-cli admin data-migration encrypt-datasource-passwords
# Show Grafana version
grafana-cli --version
# Generate secret key
grafana-cli admin secret-scan
API Recipes
Authentication
# API key auth
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://grafana.example.com/api/dashboards/home
# Basic auth
curl -u admin:password \
https://grafana.example.com/api/org
# Service account token (recommended for automation)
curl -H "Authorization: Bearer sa-token-xxx" \
https://grafana.example.com/api/dashboards/home
Dashboard Operations
# List all dashboards
curl -s -H "Authorization: Bearer $TOKEN" \
"$GRAFANA_URL/api/search?type=dash-db" | jq '.[] | {title, uid, url}'
# Get dashboard by UID
curl -s -H "Authorization: Bearer $TOKEN" \
"$GRAFANA_URL/api/dashboards/uid/YOUR_DASHBOARD_UID" | jq .
# Export dashboard JSON (for backup/provisioning)
curl -s -H "Authorization: Bearer $TOKEN" \
"$GRAFANA_URL/api/dashboards/uid/YOUR_DASHBOARD_UID" \
| jq '.dashboard' > dashboard-export.json
# Import/create dashboard
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"dashboard": '"$(cat dashboard-export.json)"',
"overwrite": true,
"folderId": 0
}' "$GRAFANA_URL/api/dashboards/db"
# Delete dashboard
curl -X DELETE -H "Authorization: Bearer $TOKEN" \
"$GRAFANA_URL/api/dashboards/uid/YOUR_DASHBOARD_UID"
Data Source Operations
# List all data sources
curl -s -H "Authorization: Bearer $TOKEN" \
"$GRAFANA_URL/api/datasources" | jq '.[] | {name, type, url}'
# Create a Prometheus data source
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Prometheus",
"type": "prometheus",
"url": "http://prometheus:9090",
"access": "proxy",
"isDefault": true
}' "$GRAFANA_URL/api/datasources"
# Test data source connectivity
curl -s -H "Authorization: Bearer $TOKEN" \
"$GRAFANA_URL/api/datasources/proxy/1/api/v1/query?query=up"
Alert Operations
# List all alert rules
curl -s -H "Authorization: Bearer $TOKEN" \
"$GRAFANA_URL/api/v1/provisioning/alert-rules" | jq .
# Get alert rule by UID
curl -s -H "Authorization: Bearer $TOKEN" \
"$GRAFANA_URL/api/v1/provisioning/alert-rules/RULE_UID"
# List contact points
curl -s -H "Authorization: Bearer $TOKEN" \
"$GRAFANA_URL/api/v1/provisioning/contact-points" | jq .
# List notification policies
curl -s -H "Authorization: Bearer $TOKEN" \
"$GRAFANA_URL/api/v1/provisioning/policies" | jq .
User & Org Management
# List all users
curl -s -H "Authorization: Bearer $TOKEN" \
"$GRAFANA_URL/api/org/users" | jq '.[] | {login, role}'
# Create a service account
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "automation-sa", "role": "Editor"}' \
"$GRAFANA_URL/api/serviceaccounts"
# Create service account token
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "ci-token"}' \
"$GRAFANA_URL/api/serviceaccounts/1/tokens"
Provisioning Recipes
Data Source Provisioning (YAML)
# /etc/grafana/provisioning/datasources/datasources.yaml
apiVersion: 1
datasources:
- name: Mimir
type: prometheus
access: proxy
url: http://mimir-query-frontend:8080/prometheus
isDefault: true
jsonData:
httpMethod: POST
exemplarTraceIdDestinations:
- name: traceID
datasourceUid: tempo
- name: Loki
type: loki
access: proxy
url: http://loki-gateway:3100
jsonData:
derivedFields:
- datasourceUid: tempo
matcherRegex: '"traceID":"(\w+)"'
name: TraceID
url: '$${__value.raw}'
- name: Tempo
type: tempo
access: proxy
url: http://tempo-query-frontend:3200
jsonData:
tracesToMetrics:
datasourceUid: mimir
tracesToLogs:
datasourceUid: loki
tags: ['job', 'namespace', 'pod']
Dashboard Provider (YAML)
# /etc/grafana/provisioning/dashboards/provider.yaml
apiVersion: 1
providers:
- name: 'Infrastructure'
orgId: 1
folder: 'Infrastructure'
type: file
editable: false
options:
path: /etc/grafana/provisioning/dashboards/infra
foldersFromFilesStructure: true
Alert Rule Provisioning (YAML)
# /etc/grafana/provisioning/alerting/rules.yaml
apiVersion: 1
groups:
- orgId: 1
name: infrastructure-alerts
folder: Infrastructure Alerts
interval: 1m
rules:
- uid: high-cpu-alert
title: High CPU Usage
condition: A
data:
- refId: A
relativeTimeRange:
from: 600
to: 0
datasourceUid: mimir
model:
expr: '100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80'
refId: A
for: 5m
labels:
severity: warning
team: infra
annotations:
summary: "CPU usage above 80% on {{ $labels.instance }}"
# /etc/grafana/provisioning/alerting/contactpoints.yaml
apiVersion: 1
contactPoints:
- orgId: 1
name: slack-oncall
receivers:
- uid: slack-receiver
type: slack
settings:
recipient: '#alerts-oncall'
token: '${SLACK_BOT_TOKEN}'
title: '{{ template "slack.default.title" . }}'
text: '{{ template "slack.default.text" . }}'
Grafana Alloy Configuration
Basic OTel Pipeline (Alloy Syntax)
// config.alloy — Basic OTLP receiver → Grafana Cloud
// OTLP Receiver (gRPC + HTTP)
otelcol.receiver.otlp "default" {
grpc { endpoint = "0.0.0.0:4317" }
http { endpoint = "0.0.0.0:4318" }
output {
metrics = [otelcol.processor.batch.default.input]
logs = [otelcol.processor.batch.default.input]
traces = [otelcol.processor.batch.default.input]
}
}
// Batch Processor
otelcol.processor.batch "default" {
output {
metrics = [otelcol.exporter.otlphttp.grafana_cloud.input]
logs = [otelcol.exporter.otlphttp.grafana_cloud.input]
traces = [otelcol.exporter.otlphttp.grafana_cloud.input]
}
}
// Export to Grafana Cloud
otelcol.exporter.otlphttp "grafana_cloud" {
client {
endpoint = env("GRAFANA_CLOUD_OTLP_ENDPOINT")
auth = otelcol.auth.basic.grafana_cloud.handler
}
}
otelcol.auth.basic "grafana_cloud" {
username = env("GRAFANA_CLOUD_INSTANCE_ID")
password = env("GRAFANA_CLOUD_API_KEY")
}
Prometheus Scraping (Alloy Syntax)
// Scrape Prometheus endpoints
prometheus.scrape "kubernetes_pods" {
targets = discovery.kubernetes.pods.targets
forward_to = [prometheus.remote_write.mimir.receiver]
}
// Kubernetes pod discovery
discovery.kubernetes "pods" {
role = "pod"
}
// Remote write to Mimir
prometheus.remote_write "mimir" {
endpoint {
url = "http://mimir-distributor:8080/api/v1/push"
}
}
Grafana Provider Setup
terraform {
required_providers {
grafana = {
source = "grafana/grafana"
version = ">= 3.0.0"
}
}
}
provider "grafana" {
url = "https://grafana.example.com"
auth = var.grafana_api_key
}
resource "grafana_dashboard" "node_overview" {
config_json = file("${path.module}/dashboards/node-overview.json")
folder = grafana_folder.infrastructure.id
overwrite = true
}
resource "grafana_folder" "infrastructure" {
title = "Infrastructure"
}
resource "grafana_data_source" "prometheus" {
type = "prometheus"
name = "Mimir"
url = "http://mimir-query-frontend:8080/prometheus"
is_default = true
json_data_encoded = jsonencode({
httpMethod = "POST"
})
}
Useful One-Liners
# Backup all dashboards via API
for uid in $(curl -s -H "Authorization: Bearer $TOKEN" "$GRAFANA_URL/api/search?type=dash-db" | jq -r '.[].uid'); do
curl -s -H "Authorization: Bearer $TOKEN" "$GRAFANA_URL/api/dashboards/uid/$uid" \
| jq '.dashboard' > "backup-$uid.json"
done
# Check Grafana health
curl -s "$GRAFANA_URL/api/health" | jq .
# Get Grafana build info
curl -s "$GRAFANA_URL/api/frontend/settings" | jq '.buildInfo'
# Count dashboards per folder
curl -s -H "Authorization: Bearer $TOKEN" "$GRAFANA_URL/api/search?type=dash-db" \
| jq 'group_by(.folderTitle) | map({folder: .[0].folderTitle, count: length})'
# Find dashboards not viewed in 90 days (requires admin)
curl -s -H "Authorization: Bearer $TOKEN" "$GRAFANA_URL/api/search?type=dash-db" \
| jq '[.[] | select(.sortMeta < (now - 7776000))] | length'