Grafana Grafana

Provisiona dashboards desde archivos JSON

Carga dashboards desde disco, asigna carpetas a partir de directorios y crea dashboards sin perder cambios.

12 min Intermedio

Los dashboards son documentos JSON, lo que los hace fáciles de guardar en Git. Un proveedor de dashboards le dice a Grafana una carpeta que vigilar, y Grafana carga cada archivo JSON que encuentra y luego sigue comprobando si hay cambios. Esta guía cubre el archivo del proveedor, la asignación de carpetas, el propio JSON del dashboard y un flujo de trabajo para crear dashboards sin acabar con ediciones que solo existen en la interfaz.

El archivo del proveedor

provisioning/dashboards/providers.yaml:

apiVersion: 1

providers:
  - name: default
    orgId: 1
    type: file
    disableDeletion: false
    updateIntervalSeconds: 30
    allowUiUpdates: false
    options:
      path: /var/lib/grafana/dashboards
      foldersFromFilesStructure: true

Qué hace cada campo:

  • name es obligatorio y debe ser único entre los proveedores.
  • options.path es el directorio que Grafana escanea en busca de archivos JSON. Debe existir dentro del contenedor.
  • updateIntervalSeconds es con qué frecuencia Grafana vuelve a escanear la ruta. Todos los dashboards se cargan al arrancar, y los cambios se recogen después sin reiniciar.
  • allowUiUpdates: cuando es false, un dashboard provisionado no puede guardarse desde la interfaz, lo que mantiene a Git como autoridad. Cuando es true, los guardados de la interfaz se conservan en la base de datos hasta que cambia el archivo de origen, momento en que el archivo los sobrescribe.
  • disableDeletion: cuando es true, eliminar un archivo no elimina su dashboard de Grafana. Déjalo en false si Git debe ser la verdad.
  • folder o folderUid colocan todos los dashboards en una carpeta con nombre. Sin ellos, los dashboards van a la raíz.
  • foldersFromFilesStructure: true asigna los subdirectorios de path a carpetas de Grafana. Deja folder y folderUid vacíos cuando lo uses. Las carpetas anidadas no están soportadas, así que un nivel de subdirectorio es el límite.

Organiza el repositorio por carpeta

Con foldersFromFilesStructure: true, esta estructura:

dashboards/
├── infrastructure/
│   ├── node-exporter.json
│   └── kubernetes.json
└── applications/
    └── webapp.json

crea dos carpetas de Grafana, infrastructure y applications, con los dashboards dentro. Usa proveedores separados en su lugar si necesitas ajustes distintos por grupo, como un proveedor con allowUiUpdates: true para un área “scratch”.

Lo esencial del JSON del dashboard

Un archivo provisionado debe contener el propio modelo del dashboard, con uid y title en el nivel superior. No lo envuelvas en el sobre {"dashboard": {...}, "overwrite": true} que usa la API HTTP, que es una causa común del error “Dashboard title cannot be empty”.

{
  "uid": "webapp-overview",
  "title": "Webapp Overview",
  "tags": ["webapp", "provisioned"],
  "schemaVersion": 39,
  "version": 1,
  "refresh": "30s",
  "time": { "from": "now-6h", "to": "now" },
  "templating": {
    "list": [
      {
        "name": "namespace",
        "type": "query",
        "datasource": { "type": "prometheus", "uid": "prometheus" },
        "query": "label_values(kube_pod_info, namespace)"
      }
    ]
  },
  "panels": [
    {
      "id": 1,
      "type": "timeseries",
      "title": "Request rate",
      "gridPos": { "h": 8, "w": 12, "x": 0, "y": 0 },
      "datasource": { "type": "prometheus", "uid": "prometheus" },
      "targets": [
        {
          "refId": "A",
          "expr": "sum(rate(http_requests_total{namespace=\"$namespace\"}[5m]))",
          "datasource": { "type": "prometheus", "uid": "prometheus" }
        }
      ]
    }
  ]
}

Pautas para dashboards que se comportan bien como código:

  • Define un uid estable. Grafana actualiza el dashboard con ese UID en cada carga. Evita reutilizar un UID entre archivos, o el mismo título dos veces en una carpeta.
  • Omite el id numérico. Lo asigna la base de datos y difiere entre instancias.
  • Referencia los data sources por UID, que coincida con el uid que provisionaste ({"type": "prometheus", "uid": "prometheus"}). Los dashboards exportados para compartir pueden contener marcadores como ${DS_PROMETHEUS}, que debes reemplazar con el UID real o con una variable de plantilla de data source.
  • La interpolación de variables de entorno no funciona dentro del JSON del dashboard. Usa variables de plantilla del dashboard para las diferencias por entorno.
  • Grafana 13 almacena los dashboards internamente en un esquema más nuevo y migra el JSON antiguo al cargarlo, así que los archivos existentes siguen funcionando.

Crea en la interfaz y devuelve el resultado a Git

Escribir a mano el JSON de los paneles es lento, así que la mayoría de los equipos esbozan en la interfaz y exportan. Un flujo de trabajo que mantiene los archivos como la verdad:

  1. Ejecuta una instancia scratch (la configuración compose de la guía anterior) donde un proveedor tenga allowUiUpdates: true.
  2. Construye o ajusta el dashboard en la interfaz.
  3. Expórtalo como JSON desde el menú de compartir o exportar del dashboard. Elige la opción de exportar para compartir externamente si quieres que los data sources se reemplacen por entradas, y luego define los UID reales.
  4. Elimina el id numérico, define un uid estable y haz commit del archivo en la carpeta del repositorio.
  5. Abre un pull request. El Grafana de producción lo recoge tras el merge, y allowUiUpdates: false allí impide que nadie se desvíe.

También puedes obtener un dashboard existente a través de la API:

curl -s -u admin:$GRAFANA_ADMIN_PASSWORD \
  http://localhost:3000/api/dashboards/uid/webapp-overview \
  | jq '.dashboard | del(.id)' > dashboards/applications/webapp.json

Formatea el JSON de forma coherente (por ejemplo jq -S .) para que los diffs muestren cambios reales.

Genera dashboards desde código

Si muchos dashboards comparten una forma, genera el JSON en lugar de copiarlo. El Grafana Foundation SDK (Go, TypeScript, Python, PHP, Java) construye dashboards a partir de código tipado, y su salida es el mismo JSON que dejas en la carpeta del proveedor. La guía del Foundation SDK de esta serie lo cubre.

Valida en CI

Detecta errores antes de que lleguen a Grafana:

# ¿JSON válido?
jq empty dashboards/**/*.json
# ¿cada archivo tiene uid y title?
for f in dashboards/*/*.json; do
  jq -e '.uid and .title' "$f" >/dev/null || echo "missing uid/title: $f"
done
# ¿uid duplicados?
jq -r '.uid' dashboards/*/*.json | sort | uniq -d

Aplica y verifica

Los cambios se recogen dentro de updateIntervalSeconds. Para forzar un reescaneo:

curl -X POST -u admin:$GRAFANA_ADMIN_PASSWORD \
  http://localhost:3000/api/admin/provisioning/dashboards/reload

curl -s -u admin:$GRAFANA_ADMIN_PASSWORD \
  "http://localhost:3000/api/search?type=dash-db" | jq '.[] | {title, uid, folderTitle}'

Si un dashboard no aparece, revisa las líneas de log de arranque y de reescaneo del logger de provisioning. Las causas habituales son una ruta que no existe en el contenedor, JSON envuelto en el sobre de la API o dos archivos que comparten un uid.

Guías populares