Jenkins + Minio + Prometheus + Grafana v1
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
# Backup de dashboards de Grafana
|
||||
|
||||
Este servidor corre Grafana en `http://localhost:3000` (puerto expuesto: 3000).
|
||||
El backup se hace vía la API HTTP de Grafana (no toca los volúmenes/DB de Docker
|
||||
directamente), exportando cada dashboard como JSON.
|
||||
|
||||
## Archivos involucrados
|
||||
|
||||
| Ruta | Qué es |
|
||||
|----------------------------------------------------------------|-------------------------------------------|
|
||||
| `/opt/server/scripts/backup-grafana-dashboards.sh` | Script de backup (root:root, permisos 700 porque contiene la contraseña de Grafana) |
|
||||
| `/opt/server/backups/grafana_dashboards/` | Carpeta con los `.tar.gz` generados |
|
||||
|
||||
**No está agregado a crontab** (a diferencia de `backup-jenkins-home.sh`). Se
|
||||
ejecuta manualmente con `sudo` cuando se necesite.
|
||||
|
||||
## Cómo correr el backup manualmente
|
||||
|
||||
```bash
|
||||
sudo /opt/server/scripts/backup-grafana-dashboards.sh
|
||||
```
|
||||
|
||||
Esto genera `/opt/server/backups/grafana_dashboards/grafana_dashboards_YYYYMMDD.tar.gz`
|
||||
y conserva solo los últimos 4 backups (los más viejos se borran automáticamente,
|
||||
`KEEP=4` dentro del script).
|
||||
|
||||
### Convención de nombres dentro del tar.gz
|
||||
|
||||
Cada dashboard se guarda como:
|
||||
|
||||
```
|
||||
<título_sanitizado>__<uid>.json
|
||||
```
|
||||
|
||||
Ejemplo:
|
||||
|
||||
```
|
||||
Monitoreo__adpjcx6.json
|
||||
Node_Exporter_Full__rYdddlPWk.json
|
||||
Node_Exporter_Full_completo__rYdddlPWk3.json
|
||||
MySQL_Overview__MQWgroiiz.json
|
||||
```
|
||||
|
||||
El título se sanitiza (solo `A-Za-z0-9`, resto reemplazado por `_`), y el `uid`
|
||||
real de Grafana queda al final por si dos títulos sanitizados coinciden.
|
||||
|
||||
### Ver contenido de un backup sin extraerlo
|
||||
|
||||
```bash
|
||||
sudo tar tzf /opt/server/backups/grafana_dashboards/grafana_dashboards_<fecha>.tar.gz
|
||||
```
|
||||
|
||||
## Cómo restaurar un dashboard
|
||||
|
||||
Cada archivo `.json` dentro del tar tiene esta forma (respuesta cruda de la API
|
||||
`GET /api/dashboards/uid/{uid}`):
|
||||
|
||||
```json
|
||||
{
|
||||
"meta": { ... },
|
||||
"dashboard": { ... } <- esto es lo que Grafana necesita para importar
|
||||
}
|
||||
```
|
||||
|
||||
**IMPORTANTE:** para importar, Grafana necesita únicamente el contenido del
|
||||
campo `dashboard`, sin el wrapper `meta`. Si se sube/pega el JSON completo
|
||||
(`meta` + `dashboard`) da el error:
|
||||
|
||||
```
|
||||
Invalid or unknown dashboard schema
|
||||
```
|
||||
|
||||
### Opción A — Restaurar vía API (rápido, scripteable)
|
||||
|
||||
```bash
|
||||
sudo bash -c '
|
||||
LATEST=$(ls -1t /opt/server/backups/grafana_dashboards/grafana_dashboards_*.tar.gz | head -1)
|
||||
mkdir -p /tmp/restore
|
||||
tar xzf "$LATEST" -C /tmp/restore ./<archivo>.json
|
||||
|
||||
jq "{dashboard: (.dashboard + {id: null}), overwrite: true}" \
|
||||
/tmp/restore/<archivo>.json > /tmp/restore/payload.json
|
||||
|
||||
curl -sf -X POST -H "Content-Type: application/json" \
|
||||
-u admin:<password_de_grafana> \
|
||||
http://localhost:3000/api/dashboards/db \
|
||||
-d @/tmp/restore/payload.json
|
||||
'
|
||||
```
|
||||
|
||||
Notas:
|
||||
- `id: null` — el `id` interno viejo puede no existir más (ej. si se borró el
|
||||
dashboard); ponerlo en `null` hace que Grafana cree uno nuevo.
|
||||
- El `uid` se mantiene igual, así el dashboard vuelve con la misma URL que tenía.
|
||||
- `overwrite: true` evita el error 412 si el uid ya existiera.
|
||||
- Respuesta esperada: `{"status":"success", "uid": "...", "url": "...", ...}`.
|
||||
- Limpiar `/tmp/restore` después (`sudo rm -rf /tmp/restore`).
|
||||
|
||||
### Opción B — Restaurar a mano desde la UI
|
||||
|
||||
1. Extraer solo el campo `dashboard` (sin el wrapper `meta`):
|
||||
|
||||
```bash
|
||||
sudo bash -c '
|
||||
LATEST=$(ls -1t /opt/server/backups/grafana_dashboards/grafana_dashboards_*.tar.gz | head -1)
|
||||
mkdir -p /tmp/restore
|
||||
tar xzf "$LATEST" -C /tmp/restore ./<archivo>.json
|
||||
jq ".dashboard" /tmp/restore/<archivo>.json > /tmp/restore/import.json
|
||||
'
|
||||
```
|
||||
|
||||
2. Bajar `/tmp/restore/import.json` a tu equipo si vas a subirlo como archivo
|
||||
(`scp jenkins-srv:/tmp/restore/import.json .`), o simplemente abrirlo con
|
||||
`cat`/editor para copiar el contenido.
|
||||
|
||||
3. En la UI de Grafana (`http://172.19.13.204:3000`):
|
||||
**Dashboards → New → Import → Upload JSON file** (o pegar el contenido en
|
||||
"Import via panel json").
|
||||
|
||||
4. Confirmar el nombre/folder propuesto y click **Import**.
|
||||
|
||||
5. Si Grafana avisa que el `uid` ya existe, ofrece la opción de sobrescribir
|
||||
en el mismo diálogo.
|
||||
|
||||
6. Limpiar `/tmp/restore` cuando termines.
|
||||
|
||||
## Encontrar rápido el uid/título de un dashboard sin extraer todo el tar
|
||||
|
||||
```bash
|
||||
for f in $(tar tzf <backup>.tar.gz | grep '\.json$'); do
|
||||
echo -n "$f -> "
|
||||
tar xzOf <backup>.tar.gz "$f" | jq -r '.dashboard.title'
|
||||
done
|
||||
```
|
||||
|
||||
(Con la convención de nombres actual esto ya no es necesario para uso normal,
|
||||
pero sirve como referencia si en algún momento se cambia el formato del script.)
|
||||
|
||||
## Credenciales
|
||||
|
||||
El script usa el usuario admin de Grafana (`admin`) y su contraseña, embebidas
|
||||
en `/opt/server/scripts/backup-grafana-dashboards.sh`. Por eso el script tiene
|
||||
permisos `700` (solo root puede leerlo/ejecutarlo), a diferencia de otros
|
||||
scripts en `/opt/server/scripts/` que son `755`.
|
||||
|
||||
## Probado el (2026-08-05)
|
||||
|
||||
Ciclo completo validado: crear dashboard de prueba → backup → borrar dashboard
|
||||
→ restaurar (API y manual) → verificar que el contenido vuelve idéntico. Ambos
|
||||
métodos de restauración funcionan.
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
GRAFANA_URL=http://localhost:3000
|
||||
GRAFANA_USER=admin
|
||||
GRAFANA_PASS=holamundo
|
||||
BACKUP_DIR=/opt/server/backups/grafana_dashboards
|
||||
KEEP=4
|
||||
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
STAMP=$(date +%Y%m%d)
|
||||
TMP_DIR=$(mktemp -d)
|
||||
trap 'rm -rf "$TMP_DIR"' EXIT
|
||||
|
||||
curl -sf -u "$GRAFANA_USER:$GRAFANA_PASS" "$GRAFANA_URL/api/search?type=dash-db" \
|
||||
| jq -r '.[].uid' \
|
||||
| while read -r uid; do
|
||||
dashboard_json=$(curl -sf -u "$GRAFANA_USER:$GRAFANA_PASS" "$GRAFANA_URL/api/dashboards/uid/$uid")
|
||||
title=$(jq -r '.dashboard.title' <<< "$dashboard_json")
|
||||
safe_title=$(echo "$title" | tr -c 'A-Za-z0-9' '_' | sed 's/_\+/_/g; s/^_//; s/_$//')
|
||||
echo "$dashboard_json" > "$TMP_DIR/${safe_title}__${uid}.json"
|
||||
done
|
||||
|
||||
tar czf "$BACKUP_DIR/grafana_dashboards_$STAMP.tar.gz" -C "$TMP_DIR" .
|
||||
|
||||
ls -1t "$BACKUP_DIR"/grafana_dashboards_*.tar.gz | tail -n +$((KEEP + 1)) | xargs -r rm --
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
SRC_DIR=/opt/server/data
|
||||
BACKUP_DIR=/opt/server/backups/jenkins_home
|
||||
KEEP=4
|
||||
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
STAMP=$(date +%Y%m%d)
|
||||
tar czf "$BACKUP_DIR/jenkins_home_$STAMP.tar.gz" -C "$SRC_DIR" jenkins_home
|
||||
|
||||
ls -1t "$BACKUP_DIR"/jenkins_home_*.tar.gz | tail -n +$((KEEP + 1)) | xargs -r rm --
|
||||
Reference in New Issue
Block a user