Grafana Grafana

Gérer Grafana avec le Grafana Operator

Déclarez instances, dossiers, tableaux de bord, sources de données et règles d'alerte comme ressources personnalisées Kubernetes.

15 min Avancé

Le Grafana Operator transforme chaque ressource Grafana en objet Kubernetes. Un GrafanaDashboard est un manifeste, un GrafanaDatasource est un manifeste, et l’operator les réconcilie avec une instance Grafana via son API. Cela s’accorde naturellement avec des outils GitOps comme Flux et Argo CD, et fonctionne pour des instances Grafana dans ou hors du cluster, y compris Grafana Cloud. Toutes les ressources utilisent apiVersion: grafana.integreatly.org/v1beta1.

Installer l’operator

Installez-le avec Helm depuis son chart OCI (consultez la documentation d’installation de l’operator pour l’emplacement et la version actuels du chart, et épinglez-la) :

helm upgrade -i grafana-operator \
  oci://ghcr.io/grafana/helm-charts/grafana-operator \
  --namespace grafana --create-namespace \
  --version <operator-version>

La documentation de l’operator décrit aussi une installation avec Kustomize. Avec Flux, placez le même chart dans une HelmRelease.

Décrire l’instance

Une instance peut être gérée (l’operator déploie Grafana) ou externe (il se connecte à une instance existante). Une instance gérée :

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     # exemple uniquement ; voir ci-dessous

Une instance externe, comme un stack Grafana Cloud, pointe vers une URL et prend un jeton depuis un 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

Le bloc spec.config accepte les mêmes sections et clés que grafana.ini. Ne mettez pas de vrai mot de passe dans un manifeste. La documentation de l’operator montre comment lire les identifiants admin depuis un Secret.

Les labels de l’instance comptent : toutes les autres ressources sélectionnent leur instance cible avec instanceSelector.matchLabels, en utilisant ces labels.

Dossiers

apiVersion: grafana.integreatly.org/v1beta1
kind: GrafanaFolder
metadata:
  name: applications
spec:
  instanceSelector:
    matchLabels:
      dashboards: "grafana"
  title: Applications
  uid: applications     # définissez un UID stable pour que d'autres ressources puissent le référencer

Si title est omis, il vaut par défaut metadata.name. Définissez spec.uid chaque fois que d’autres ressources pointeront vers le dossier avec folderRef, car sans lui le réconciliateur peut adopter un dossier existant portant le même nom.

Sources de données

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

Les identifiants proviennent d’un Secret du même namespace via valuesFrom, de sorte qu’ils n’apparaissent jamais dans le manifeste :

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}

Ne mettez pas d’identifiants dans l’url. Chiffrez ou synchronisez le Secret avec SOPS ou External Secrets, comme pour tout Secret Kubernetes.

Tableaux de bord

Un GrafanaDashboard peut tirer son JSON de plusieurs sources, ce qui est le plus grand atout de l’operator :

# JSON en ligne
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": [] }
# depuis une ConfigMap
spec:
  instanceSelector:
    matchLabels:
      dashboards: "grafana"
  configMapRef:
    name: dashboard-definition
    key: json
# depuis une URL, comme grafana.com ou un fichier brut Git
spec:
  instanceSelector:
    matchLabels:
      dashboards: "grafana"
  url: "https://grafana.com/api/dashboards/1860/revisions/30/download"
# depuis un artefact OCI
spec:
  instanceSelector:
    matchLabels:
      dashboards: "grafana"
  oci:
    reference: ghcr.io/team-a/dashboards:v1.4.7
    path: board.json
    pullSecretRef:
      name: ghcr-pull

Autres champs que vous utiliserez :

  • folderRef pointe vers un GrafanaFolder par nom, et folderUID vers l’UID d’un dossier existant.
  • gzipJson contient le tableau de bord sous forme de gzip encodé en base64 (cat dashboard.json | gzip | base64 -w0), pour les tableaux de bord trop volumineux pour un manifeste.
  • variables surcharge les variables de modèle, par exemple pour définir un namespace ou une source de données par environnement.
  • resyncPeriod et contentCacheDuration contrôlent la fréquence de réapplication du contenu et la durée de mise en cache des URL récupérées.

Règles d’alerte

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
          # l'étape de requête Prometheus, comme dans le guide sur l'alerting
        - refId: C
          # l'étape d'expression de seuil

Chaque groupe de règles a besoin d’un dossier et d’au moins une règle. Les étapes de données utilisent la même structure que les fichiers de provisionnement ; vous pouvez donc réutiliser le YAML du guide sur l’alerting. L’operator dispose aussi de ressources pour les points de contact ; consultez ses exemples pour la liste actuelle.

L’exploiter

kubectl get grafanas,grafanafolders,grafanadatasources,grafanadashboards -A
kubectl describe grafanadashboard simple -n grafana

describe affiche les conditions de statut de la ressource, qui indiquent si la dernière synchronisation vers Grafana a réussi et, sinon, pourquoi. Causes courantes : un instanceSelector qui ne correspond à aucune instance, un mauvais jeton, ou un Secret dans le mauvais namespace.

Operator ou provisionnement par fichiers ?

Utilisez l’Operator si vous faites déjà du GitOps sur Kubernetes, si vous voulez que chaque équipe possède ses tableaux de bord et ses alertes comme objets distincts, ou si vous gérez Grafana Cloud ou plusieurs instances. Utilisez les valeurs de provisionnement du chart Helm si vous avez un seul Grafana et une poignée de ressources, car cela n’ajoute aucun contrôleur supplémentaire. Les deux peuvent coexister, mais laissez un seul outil posséder chaque ressource.

Guides populaires