Grafana Grafana

Gestiona Grafana con el Grafana Operator

Declara instancias, carpetas, dashboards, data sources y reglas de alertas como recursos personalizados de Kubernetes.

15 min Avanzado

El Grafana Operator convierte cada recurso de Grafana en un objeto de Kubernetes. Un GrafanaDashboard es un manifiesto, un GrafanaDatasource es un manifiesto, y el operator los reconcilia contra una instancia de Grafana a través de su API. Eso encaja de forma natural con herramientas GitOps como Flux y Argo CD, y funciona para instancias de Grafana dentro o fuera del clúster, incluido Grafana Cloud. Todos los recursos usan apiVersion: grafana.integreatly.org/v1beta1.

Instala el operator

Instálalo con Helm desde su chart OCI (consulta la documentación de instalación del operator para la ubicación y versión actuales del chart, y fíjala):

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

La documentación del operator también describe una instalación con Kustomize. Con Flux, pon el mismo chart en un HelmRelease.

Describe la instancia

Una instancia puede ser administrada (el operator despliega Grafana) o externa (se conecta a una que ya existe). Una instancia administrada:

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     # solo como ejemplo; ver más abajo

Una instancia externa, como un stack de Grafana Cloud, apunta a una URL y toma un token de 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

El bloque spec.config acepta las mismas secciones y claves que grafana.ini. No pongas una contraseña real en un manifiesto. La documentación del operator muestra cómo leer las credenciales de admin de un Secret.

Las etiquetas de la instancia importan: cada otro recurso selecciona su instancia de destino con instanceSelector.matchLabels, usando esas etiquetas.

Carpetas

apiVersion: grafana.integreatly.org/v1beta1
kind: GrafanaFolder
metadata:
  name: applications
spec:
  instanceSelector:
    matchLabels:
      dashboards: "grafana"
  title: Applications
  uid: applications     # define un UID estable para que otros recursos puedan referenciarlo

Si se omite title, toma por defecto metadata.name. Define spec.uid siempre que otros recursos apunten a la carpeta con folderRef, porque sin él el reconciliador puede adoptar una carpeta existente con el mismo nombre.

Data sources

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

Las credenciales vienen de un Secret en el mismo namespace mediante valuesFrom, así que nunca aparecen en el manifiesto:

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}

No pongas credenciales en la url. Cifra o sincroniza el Secret con SOPS o External Secrets, como con cualquier Secret de Kubernetes.

Dashboards

Un GrafanaDashboard puede tomar su JSON de varias fuentes, que es la mayor fortaleza del operator:

# JSON en línea
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": [] }
# desde un ConfigMap
spec:
  instanceSelector:
    matchLabels:
      dashboards: "grafana"
  configMapRef:
    name: dashboard-definition
    key: json
# desde una URL, como grafana.com o un archivo raw de Git
spec:
  instanceSelector:
    matchLabels:
      dashboards: "grafana"
  url: "https://grafana.com/api/dashboards/1860/revisions/30/download"
# desde un artefacto OCI
spec:
  instanceSelector:
    matchLabels:
      dashboards: "grafana"
  oci:
    reference: ghcr.io/team-a/dashboards:v1.4.7
    path: board.json
    pullSecretRef:
      name: ghcr-pull

Otros campos que usarás:

  • folderRef apunta a un GrafanaFolder por nombre, y folderUID al UID de una carpeta existente.
  • gzipJson contiene el dashboard como gzip codificado en base64 (cat dashboard.json | gzip | base64 -w0), para dashboards demasiado grandes para un manifiesto.
  • variables sobrescribe variables de plantilla, por ejemplo para definir un namespace o un data source por entorno.
  • resyncPeriod y contentCacheDuration controlan con qué frecuencia se vuelve a aplicar el contenido y durante cuánto tiempo se almacenan en caché las URL obtenidas.

Reglas de alertas

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
          # el paso de consulta a Prometheus, como en la guía de alertas
        - refId: C
          # el paso de expresión de umbral

Cada grupo de reglas necesita una carpeta y al menos una regla. Los pasos de datos usan la misma estructura que los archivos de provisioning, así que puedes reutilizar el YAML de la guía de alertas. El operator también tiene recursos para contact points; consulta sus ejemplos para la lista actual.

Opéralo

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

describe muestra las condiciones de estado del recurso, que indican si la última sincronización con Grafana tuvo éxito y por qué no, si falló. Causas comunes: un instanceSelector que no coincide con ninguna instancia, un token incorrecto o un Secret en el namespace equivocado.

¿Operator o provisioning por archivos?

Usa el Operator cuando ya ejecutes GitOps en Kubernetes, quieras que cada equipo sea dueño de sus dashboards y alertas como objetos separados, o gestiones Grafana Cloud o varias instancias. Usa los valores de provisioning del chart de Helm cuando tengas un solo Grafana y un puñado de recursos, ya que eso no añade ningún controlador adicional. Ambos pueden coexistir, pero deja que una sola herramienta sea dueña de cada recurso.

Guías populares