Grafana mit dem Grafana Operator verwalten
Deklariere Instanzen, Ordner, Dashboards, Datenquellen und Alert-Regeln als Kubernetes Custom Resources.
Der Grafana Operator verwandelt jede Grafana-Ressource in ein Kubernetes-Objekt. Ein GrafanaDashboard ist ein Manifest, eine GrafanaDatasource ist ein Manifest, und der Operator gleicht sie über die API mit einer Grafana-Instanz ab. Das passt natürlich zu GitOps-Werkzeugen wie Flux und Argo CD, und es funktioniert für Grafana-Instanzen innerhalb oder außerhalb des Clusters, einschließlich Grafana Cloud. Alle Ressourcen verwenden apiVersion: grafana.integreatly.org/v1beta1.
Den Operator installieren
Installiere ihn mit Helm aus seinem OCI-Chart (prüfe die Installationsdokumentation des Operators auf den aktuellen Chart-Ort und die Version und pinne sie):
helm upgrade -i grafana-operator \
oci://ghcr.io/grafana/helm-charts/grafana-operator \
--namespace grafana --create-namespace \
--version <operator-version>
Die Dokumentation des Operators beschreibt auch eine Kustomize-Installation. Mit Flux packst du dasselbe Chart in ein HelmRelease.
Die Instanz beschreiben
Eine Instanz kann verwaltet sein (der Operator deployt Grafana) oder extern (er verbindet sich mit einer bereits existierenden). Eine verwaltete Instanz:
apiVersion: grafana.integreatly.org/v1beta1
kind: Grafana
metadata:
name: grafana
namespace: grafana
labels:
dashboards: "grafana"
spec:
config:
log:
mode: console
security:
admin_user: root
admin_password: secret # nur ein Beispiel; siehe unten
Eine externe Instanz, etwa ein Grafana-Cloud-Stack, zeigt auf eine URL und nimmt ein Token aus einem Secret:
apiVersion: grafana.integreatly.org/v1beta1
kind: Grafana
metadata:
name: my-stack
namespace: grafana
labels:
dashboards: my-stack
spec:
external:
url: https://my-stack.grafana.net/
apiKey:
name: grafana-cloud-credentials
key: GRAFANA_CLOUD_INSTANCE_TOKEN
Der Block spec.config nimmt dieselben Sections und Schlüssel wie grafana.ini. Schreibe kein echtes Passwort in ein Manifest. Die Dokumentation des Operators zeigt, wie du Admin-Zugangsdaten aus einem Secret liest.
Die Labels der Instanz sind wichtig: Jede andere Ressource wählt ihre Ziel-Instanz mit instanceSelector.matchLabels über diese Labels aus.
Ordner
apiVersion: grafana.integreatly.org/v1beta1
kind: GrafanaFolder
metadata:
name: applications
spec:
instanceSelector:
matchLabels:
dashboards: "grafana"
title: Applications
uid: applications # setze eine stabile UID, damit andere Ressourcen darauf verweisen können
Wird title weggelassen, ist der Standard metadata.name. Setze spec.uid, wann immer andere Ressourcen mit folderRef auf den Ordner verweisen, denn ohne sie kann der Reconciler einen bestehenden Ordner mit demselben Namen übernehmen.
Datenquellen
apiVersion: grafana.integreatly.org/v1beta1
kind: GrafanaDatasource
metadata:
name: prometheus
spec:
instanceSelector:
matchLabels:
dashboards: "grafana"
datasource:
name: prometheus
type: prometheus
access: proxy
url: http://prometheus-service:9090
isDefault: true
jsonData:
timeInterval: 5s
Zugangsdaten kommen aus einem Secret im selben Namespace über valuesFrom, sodass sie nie im Manifest erscheinen:
apiVersion: v1
kind: Secret
metadata:
name: credentials
type: Opaque
stringData:
PROMETHEUS_USERNAME: grafana
PROMETHEUS_PASSWORD: change-me
---
apiVersion: grafana.integreatly.org/v1beta1
kind: GrafanaDatasource
metadata:
name: prometheus-secured
spec:
instanceSelector:
matchLabels:
dashboards: "grafana"
valuesFrom:
- targetPath: basicAuthUser
valueFrom:
secretKeyRef:
name: credentials
key: PROMETHEUS_USERNAME
- targetPath: secureJsonData.basicAuthPassword
valueFrom:
secretKeyRef:
name: credentials
key: PROMETHEUS_PASSWORD
datasource:
name: prometheus-secured
type: prometheus
access: proxy
basicAuth: true
url: http://prometheus-service:9090
secureJsonData:
basicAuthPassword: ${PROMETHEUS_PASSWORD}
Schreibe keine Zugangsdaten in die url. Verschlüssele das Secret oder synchronisiere es mit SOPS oder External Secrets, wie bei jedem Kubernetes-Secret.
Dashboards
Ein GrafanaDashboard kann sein JSON aus mehreren Quellen beziehen, was die größte Stärke des Operators ist:
# Inline-JSON
apiVersion: grafana.integreatly.org/v1beta1
kind: GrafanaDashboard
metadata:
name: simple
spec:
resyncPeriod: 30s
instanceSelector:
matchLabels:
dashboards: "grafana"
folderRef: applications
json: >
{ "uid": "simple", "title": "Simple Dashboard", "panels": [] }
# aus einer ConfigMap
spec:
instanceSelector:
matchLabels:
dashboards: "grafana"
configMapRef:
name: dashboard-definition
key: json
# aus einer URL, etwa grafana.com oder eine rohe Git-Datei
spec:
instanceSelector:
matchLabels:
dashboards: "grafana"
url: "https://grafana.com/api/dashboards/1860/revisions/30/download"
# aus einem OCI-Artefakt
spec:
instanceSelector:
matchLabels:
dashboards: "grafana"
oci:
reference: ghcr.io/team-a/dashboards:v1.4.7
path: board.json
pullSecretRef:
name: ghcr-pull
Weitere Felder, die du nutzen wirst:
folderRefverweist per Namen auf einGrafanaFolder, undfolderUIDauf die UID eines bestehenden Ordners.gzipJsonhält das Dashboard als Base64-kodiertes Gzip (cat dashboard.json | gzip | base64 -w0), für Dashboards, die für ein Manifest zu groß sind.variablesüberschreibt Template-Variablen, zum Beispiel um pro Umgebung einennamespaceoder eine Datenquelle zu setzen.resyncPeriodundcontentCacheDurationsteuern, wie oft Inhalte erneut angewendet werden und wie lange abgerufene URLs im Cache bleiben.
Alert-Regeln
apiVersion: grafana.integreatly.org/v1beta1
kind: GrafanaAlertRuleGroup
metadata:
name: webapp-alerts
spec:
folderRef: applications
instanceSelector:
matchLabels:
dashboards: "grafana"
interval: 5m
rules:
- uid: webapp-down
title: Webapp targets down
condition: C
for: 5m
noDataState: NoData
execErrState: Error
data:
- refId: A
# der Prometheus-Query-Schritt, wie in der Alerting-Anleitung
- refId: C
# der Threshold-Ausdrucksschritt
Jede Regelgruppe braucht einen Ordner und mindestens eine Regel. Die Daten-Schritte nutzen dieselbe Struktur wie Provisioning-Dateien, du kannst also das YAML aus der Alerting-Anleitung wiederverwenden. Der Operator hat auch Ressourcen für Contact Points; die aktuelle Liste findest du in seinen Beispielen.
Betrieb
kubectl get grafanas,grafanafolders,grafanadatasources,grafanadashboards -A
kubectl describe grafanadashboard simple -n grafana
describe zeigt die Status-Bedingungen der Ressource, die sagen, ob der letzte Sync nach Grafana erfolgreich war und warum nicht, falls er fehlschlug. Häufige Ursachen: ein instanceSelector, der keine Instanz trifft, ein falsches Token oder ein Secret im falschen Namespace.
Operator oder Datei-Provisioning?
Nutze den Operator, wenn du bereits GitOps auf Kubernetes betreibst, jedes Team seine Dashboards und Alerts als eigene Objekte besitzen soll oder du Grafana Cloud oder mehrere Instanzen verwaltest. Nutze die Provisioning-Values des Helm-Charts, wenn du ein Grafana und eine Handvoll Ressourcen hast, da das keinen zusätzlichen Controller hinzufügt. Beide können nebeneinander existieren, aber lass ein Werkzeug jede Ressource besitzen.
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.