Grafana mit Terraform verwalten
Erstelle Ordner, Datenquellen, Dashboards, Alerts, Teams und Service Accounts aus HCL.
Datei-Provisioning deckt Datenquellen, Dashboards und Alerting ab, aber keine Benutzer, Teams, Service Accounts oder Berechtigungen. Terraform deckt all das ab, funktioniert über seine API gegen jedes laufende Grafana (selbst gehostet oder Grafana Cloud) und führt eine State-Datei, um Drift zu erkennen und zu korrigieren. Diese Anleitung richtet den Provider ein und verwaltet die gängigen Ressourcen.
Voraussetzungen und Provider
Du brauchst Terraform oder OpenTofu, ein erreichbares Grafana und ein Service-Account-Token mit einer Rolle, die verwalten darf, was du deklarierst (siehe die Authentifizierungsanleitung zum Erstellen). Halte das Token aus dem Code heraus:
terraform {
required_providers {
grafana = {
source = "grafana/grafana"
version = ">= 2.9.0" # pinne auf die Version, die du getestet hast
}
}
}
variable "grafana_url" {
type = string
default = "http://localhost:3000"
}
variable "grafana_token" {
type = string
sensitive = true
}
provider "grafana" {
url = var.grafana_url
auth = var.grafana_token
}
Reiche das Token über die Umgebung weiter, damit es nie in einer Datei landet:
export TF_VAR_grafana_token='glsa_...'
terraform init
Für Grafana Cloud kannst du den Stack und seinen Service Account in derselben Konfiguration erstellen. Die Grafana-Dokumentation zeigt ein Zwei-Provider-Muster: einen cloud-Provider, der sich mit einem Cloud-Access-Policy-Token authentifiziert, um den Stack (grafana_cloud_stack) und einen Service Account (grafana_cloud_stack_service_account mit seinem Token) zu erstellen, und einen zweiten Provider mit Alias für den Stack, der dieses Token nutzt.
Ordner und Datenquellen
resource "grafana_folder" "apps" {
title = "Applications"
}
resource "grafana_data_source" "prometheus" {
type = "prometheus"
name = "Prometheus"
uid = "prometheus"
url = "http://prometheus:9090"
is_default = true
json_data_encoded = jsonencode({
timeInterval = "15s"
})
}
resource "grafana_data_source" "postgres" {
type = "postgres"
name = "Postgres"
uid = "postgres-main"
url = "postgres.internal:5432"
username = "grafana"
json_data_encoded = jsonencode({
database = "app"
sslmode = "require"
})
secure_json_data_encoded = jsonencode({
password = var.postgres_password
})
}
Das explizite Setzen von uid hält Dashboards und Alert-Regeln über Umgebungen hinweg portabel. Über secure_json_data_encoded übergebene Secrets werden von Grafana verschlüsselt gespeichert, aber auch in den Terraform-State geschrieben, speichere den State also in einem verschlüsselten, zugriffsgeschützten Backend.
Dashboards
resource "grafana_dashboard" "webapp" {
folder = grafana_folder.apps.uid
config_json = file("${path.module}/dashboards/webapp.json")
overwrite = true
}
Nutze fileset, um ein ganzes Verzeichnis zu laden:
resource "grafana_dashboard" "all" {
for_each = fileset("${path.module}/dashboards", "*.json")
folder = grafana_folder.apps.uid
config_json = file("${path.module}/dashboards/${each.value}")
}
Das Dashboard-JSON ist dieselbe Datei, die du für Datei-Provisioning verwenden würdest, du kannst also zwischen beiden Ansätzen wechseln. Wenn du ein Dashboard an einen Ordner hängst, referenzierten ältere Provider-Versionen die id des Ordners, und neuere bevorzugen seine uid; prüfe die Provider-Dokumentation für die Version, die du pinnst.
Alerting
Terraform hat Ressourcen für jeden Teil des Alertings:
resource "grafana_contact_point" "slack" {
name = "team-slack"
slack {
url = var.slack_webhook_url
recipient = "#alerts"
}
}
resource "grafana_notification_policy" "default" {
group_by = ["alertname", "namespace"]
contact_point = grafana_contact_point.slack.name
group_wait = "30s"
group_interval = "5m"
repeat_interval = "4h"
}
Regelgruppen nutzen grafana_rule_group mit rule-Blöcken, deren data-Einträge die Provisioning-YAML spiegeln (Query, Reduce, Threshold). Mute Timings und Templates haben grafana_mute_timing und grafana_message_template. Schlage die exakten Attributnamen in der Provider-Dokumentation nach, da Alerting-Ressourcen über Provider-Versionen hinweg überarbeitet wurden.
grafana_notification_policy verwaltet wie beim Datei-Provisioning den gesamten Policy-Baum, stelle also sicher, dass nur ein Werkzeug ihn besitzt.
Teams, Service Accounts und Berechtigungen
Das sind die Ressourcen, die Dateien nicht ausdrücken können:
resource "grafana_team" "platform" {
name = "platform"
email = "platform@example.com"
}
resource "grafana_service_account" "ci" {
name = "ci-dashboards"
role = "Editor"
}
resource "grafana_service_account_token" "ci" {
name = "ci-token"
service_account_id = grafana_service_account.ci.id
}
resource "grafana_folder_permission" "apps" {
folder_uid = grafana_folder.apps.uid
permissions {
team_id = grafana_team.platform.id
permission = "Edit"
}
}
Behandle das erzeugte Token als geheime Ausgabe und schiebe es in deinen Secret Manager, statt es auszugeben.
Workflow
terraform fmt -check
terraform validate
terraform plan -out tfplan
terraform apply tfplan
Führe in CI plan bei Pull Requests und apply beim Merge aus. Der Plan zeigt genau, welche Dashboards, Datenquellen und Alerts sich ändern werden.
Bestehendes übernehmen
Wenn jemand Dinge in der UI gebaut hat, importiere sie in den State, statt sie neu zu erstellen:
terraform import grafana_folder.apps <folder-uid>
terraform import grafana_dashboard.webapp <dashboard-uid>
terraform import grafana_data_source.prometheus <data-source-uid>
Neuere Terraform-Versionen können auch import-Blöcke nutzen. Import-ID-Formate können sich zwischen Provider-Versionen unterscheiden, bestätige sie also in der Ressourcen-Dokumentation.
Terraform neben Datei-Provisioning
Verwalte dieselbe Ressource nicht mit beiden. Wähle eine Grenze und halte dich daran. Eine gängige Aufteilung ist Datei-Provisioning für Datenquellen und Dashboards (beim Start geladen, kein API-Token nötig) und Terraform für Teams, Service Accounts und Berechtigungen. Eine andere ist Terraform für alles, mit auf Servereinstellungen beschränkten Provisioning-Dateien.
Beliebte Anleitungen
-
Grafana als Code betreiben: Das große Ganze Was in Dateien leben kann, was eine API braucht und wie die Teile zusammenpassen. -
Den Grafana-Server mit grafana.ini und Umgebungsvariablen konfigurieren Wisse, wo Konfigurationsdateien liegen, wie Überschreibungen geordnet sind und wie du Einstellungen in Git hältst. -
Dashboards aus JSON-Dateien provisionieren Lade Dashboards von der Platte, bilde Ordner aus Verzeichnissen ab und erstelle sie, ohne Änderungen zu verlieren. -
Alert-Regeln, Contact Points und Notification Policies provisionieren Definiere die gesamte Alerting-Pipeline in YAML, damit sie wie Code geprüft und versioniert wird. -
Grafana auf Kubernetes mit Helm und Provisioning-Values deployen Betreibe Grafana aus einem Helm-Chart, bei dem Datenquellen, Dashboards und Einstellungen alle aus Values-Dateien stammen. -
Provisioning von der Kommandozeile neu laden, prüfen und Fehler beheben Finde heraus, was Grafana geladen hat, lade ohne Neustart neu und behebe die üblichen Provisioning-Fehler.