DevOps para Sysadmins: Configura Grafana y Prometheus en tu Homelab
TL;DR — Lo que vas a tener al final
- Tiempo de setup: 4-6 horas para setup completo.
- Requisitos: CPU con VT-x, 16+ GB RAM, 64+ GB SSD.
- Resultado: Homelab con VMs/LXC, backups PBS, monitoring integrado.
- Troubleshooting: Logs de Proxmox, snapshots, restore drills mensuales.
Por qué el homelab es donde un sysadmin se entera menos
En un data center productivo tienes Nagios, Zabbix, Datadog o un equipo de SRE que te avisa cuando algo cae. En tu homelab —ese mini rack con tres NUC, una Raspberry Pi, un NAS Synology y la VM vieja que reciclaste como servidor de Plex— lo único que sabe que algo se rompió eres tú, cuando intentas entrar al servicio y la página no carga. El homelab es exactamente el escenario donde el monitoreo paga más, porque nadie te va a despertar a las tres de la mañana para decirte que el contenedor de Nextcloud se quedó sin disco.
La excusa más común para no monitorear un homelab es “son pocos servidores, ya lo veo”. Pero ya lo viste dos veces: una cuando te quedaste sin espacio y no te diste cuenta hasta que Nextcloud empezó a tirar 500, y otra cuando un nodo de tu clúster Docker se cayó y nadie se lo dijo al load balancer, así que los usuarios vieron errores intermitentes durante horas. Un stack mínimo con Prometheus + Grafana + node_exporter corre en una VM con 1 vCPU y 1 GB de RAM, y te ahorra esos dos disgustos. Esta guía es el camino práctico para armarlo.
Qué monitorear primero: la lista corta
Antes de instalar nada, siéntate a decidir qué métricas importan. La tentación es scrapeaer todo lo que node_exporter expone —más de mil contadores por host— y después no mirar nunca el dashboard. La regla honesta: si una métrica no cambia una decisión (reiniciar, ampliar disco, escalar, alertar a alguien), no la grafiques. Para un homelab sysadmin, la lista corta es:
- CPU load average (no el porcentaje de uso): un load de 4 en una máquina de 4 cores significa que algo está saturando el scheduler. node_exporter lo expone en
node_load1,node_load5,node_load15. - Memoria disponible:
node_memory_MemAvailable_byteses la métrica correcta, no el porcentaje de uso. Linux usa memoria libre para caché de página, y eso no es presión. - Disco usado por volumen:
node_filesystem_avail_bytesconmountpointcomo label. Cuando un volumen llega al 80%, quieres un aviso con días de anticipación. - Red por interfaz:
node_network_receive_bytes_totalynode_network_transmit_bytes_total, agrupados pordevice. Sirve para detectar una interfaz caída y para entender qué saturación tienes. - Servicio systemd caído: la métrica
node_systemd_unit_statecon labelnamey valorfailedoinactive. Esta sola métrica te ahorra horas de “¿por qué este servicio no responde?”: es probable que ni siquiera esté corriendo.
Tres nodos monitoreados con esas cinco métricas cubren el 90% del debugging que harías a las apuradas. Todo lo demás se agrega después cuando aparece el caso real.
Arquitectura: una VM de monitoring separada
El error más común es instalar Prometheus y Grafana en el mismo servidor que ya está corriendo otros servicios. El problema no es de recursos —es de confianza: si el host se cae, te quedás sin métricas justo cuando más las necesitas. Una VM separada (o un contenedor en un host distinto) garantiza que el monitoring sobreviva a la caída del servidor que está monitoreando.
El tamaño mínimo en 2026 es sorprendentemente chico. Prometheus consume poca CPU; lo que come es disco por la base de datos TSDB local. Para 10 nodos scrapeados cada 15 segundos con retención de 30 días, necesitas unos 8 a 12 GB de disco y 2 GB de RAM. Caddy si lo quieres exponer remotamente, Node Exporter para la propia VM, y listo. La siguiente docker-compose levanta el stack completo en una máquina Debian 13:
services:
prometheus:
image: prom/prometheus:v3.14.0
user: "65534:65534" # nobody:nogroup
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./alerts.yml:/etc/prometheus/alerts.yml:ro
- prom_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.retention.time=30d'
- '--web.enable-lifecycle'
restart: unless-stopped
ports:
- "127.0.0.1:9090:9090"
grafana:
image: grafana/grafana:12.0.0
user: "472:472"
volumes:
- grafana_data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD__FILE=/run/secrets/grafana_admin
- GF_USERS_ALLOW_SIGN_UP=false
restart: unless-stopped
depends_on:
- prometheus
ports:
- "127.0.0.1:3000:3000"
volumes:
prom_data:
grafana_data:
Las dos directivas críticas: 127.0.0.1 en los puertos (nunca 0.0.0.0: el acceso remoto va via reverse proxy o VPN), y el --web.enable-lifecycle en Prometheus (te permite recargar la configuración sin reiniciar el contenedor, útil cuando agregues nodos nuevos).
Configurar scrape targets con file_sd_configs
Listar hosts uno por uno en prometheus.yml funciona para cinco servidores. Cuando tienes quince y agregues uno nuevo cada dos meses, se vuelve insostenible. El patrón estándar es file_sd_configs: Prometheus lee archivos JSON en un directorio y scrapea lo que encuentre ahí. Tu script de Ansible o de aprovisionamiento deja un archivo por host y Prometheus lo descubre automáticamente.
El prometheus.yml mínimo con file_sd_configs queda así:
global:
scrape_interval: 30s
evaluation_interval: 30s
scrape_configs:
- job_name: node
file_sd_configs:
- files:
- /etc/prometheus/targets/*.json
refresh_interval: 1m
- job_name: prometheus
static_configs:
- targets: ['localhost:9090']
rule_files:
- /etc/prometheus/alerts.yml
alerting:
alertmanagers:
- static_configs:
- targets: ['alertmanager:9093']
Cada host tiene su archivo en /etc/prometheus/targets/ con este formato:
[
{
"targets": ["10.0.5.21:9100"],
"labels": {
"env": "prod",
"role": "docker-host",
"site": "garage"
}
}
]
Los labels env, role y site son los que después filtrás en Grafana para no mirar todos los nodos como un solo amasijo de líneas. Un dashboard con {env="prod"} te muestra solo producción, otro con {role="docker-host"} te muestra los hosts que corren contenedores. Es la diferencia entre un dashboard navegable y un monitor de saturación visual.
Desplegar node_exporter con Ansible en cinco minutos
Instalar node_exporter host por host es tedioso. La forma sysadmin-correcta es un role de Ansible de diez líneas que se aplica al grupo monitored_hosts. Funciona en cualquier distribución que tenga systemd, que es virtualmente todo lo que corre un homelab moderno.
# roles/node_exporter/tasks/main.yml
- name: Descargar node_exporter
ansible.builtin.get_url:
url: https://github.com/prometheus/node_exporter/releases/download/v1.12.0/node_exporter-1.12.0.linux-amd64.tar.gz
dest: /tmp/node_exporter.tar.gz
checksum: sha256:f6c8b6f7c8d54e3b69d20c40bd9c97c5d3e45eb5c8a3e5b6f7c8d9e0a1b2c3d4e
- name: Extraer binario
ansible.builtin.unarchive:
src: /tmp/node_exporter.tar.gz
dest: /tmp
remote_src: true
- name: Instalar binario
ansible.builtin.copy:
src: "/tmp/node_exporter-1.12.0.linux-amd64/node_exporter"
dest: /usr/local/bin/node_exporter
owner: root
group: root
mode: '0755'
remote_src: true
- name: Crear usuario de sistema
ansible.builtin.user:
name: node_exporter
system: true
shell: /usr/sbin/nologin
create_home: false
- name: Crear servicio systemd
ansible.builtin.copy:
dest: /etc/systemd/system/node_exporter.service
content: |
[Unit]
Description=Prometheus node_exporter
After=network-online.target
[Service]
Type=simple
User=node_exporter
ExecStart=/usr/local/bin/node_exporter --web.listen-address=:9100
Restart=on-failure
[Install]
WantedBy=multi-user.target
notify: restart node_exporter
- name: Habilitar y arrancar
ansible.builtin.systemd:
name: node_exporter
enabled: true
daemon_reload: true
state: started
Para nodos ARM (Raspberry Pi, Odroid, Mac mini M1 con Asahi), cambiá linux-amd64 por linux-arm64 o linux-armv7 según el modelo. El parámetro ansible_architecture detecta esto automáticamente —la forma robusta de hacerlo es parametrizar la URL con {{ ansible_architecture }} en la tarea de get_url.
Una vez desplegado, valida que el endpoint responde antes de declararlo scrapeado:
curl -s http://10.0.5.21:9100/metrics | head -5
# HELP go_gc_duration_seconds A summary of the GC invocation durations.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 5.3e-05
go_gc_duration_seconds{quantile="0.25"} 8.7e-05
Si ves métricas, Prometheus lo va a scrapear sin problema. Si no ves nada, el firewall del host está bloqueando el 9100 o node_exporter no arrancó —revisa con journalctl -u node_exporter -n 50.
Docker containers con cAdvisor
node_exporter te dice cuánto usa el host. Para ver cuánto consume cada contenedor individualmente necesitas cAdvisor, el exporter oficial de Google. Es un solo contenedor por host Docker, expone métricas por contenedor (CPU, memoria, I/O, network) en el puerto 8080, y se integra con el mismo Prometheus que ya tienes.
# docker-compose de cAdvisor en cada Docker host
services:
cadvisor:
image: gcr.io/cadvisor/cadvisor:v0.50.0
privileged: true # necesario para leer cgroups
devices:
- /dev/kmsg
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
ports:
- "127.0.0.1:8080:8080"
Sumá este scrape config a tu prometheus.yml:
- job_name: cadvisor
file_sd_configs:
- files:
- /etc/prometheus/targets/cadvisor-*.json
refresh_interval: 1m
El privileged: true y los mounts de /sys y /var/lib/docker son obligatorios: cAdvisor necesita leer cgroups del kernel y metadata de Docker para aislar las métricas por contenedor. El puerto 127.0.0.1:8080 lo deja accesible solo localmente —exponélo al Prometheus central por la VPN o por SSH tunnel.
El dashboard que quieres en Grafana
No armes un dashboard desde cero. El ID 1860 en grafana.com —”Node Exporter Full”— es mantenido por la comunidad, actualizado para cada release de node_exporter, y cubre CPU, memoria, disco, red, kernel, presión de memoria, filesystem, sockets, y mucho más con paneles limpios y alertas prearmadas. Importalo via API o desde la UI, y después editalo para tus labels. Para Docker, el ID 893 (“Docker / cAdvisor system metrics”) cubre el otro 30% de lo que quieres ver.
Para importar el dashboard via API de Grafana:
GRAFANA_URL="http://127.0.0.1:3000"
GRAFANA_AUTH="admin:${GRAFANA_ADMIN_PASSWORD}"
curl -s -X POST -H "Authorization: Basic $(echo -n admin:${GRAFANA_ADMIN_PASSWORD} | base64)"
-H "Content-Type: application/json"
-d '{
"dashboard": {
"id": null,
"uid": "node-exporter-full",
"title": "Node Exporter Full",
"tags": ["linux", "sysadmin"],
"timezone": "browser",
"schemaVersion": 39,
"version": 1,
"refresh": "30s"
},
"overwrite": false,
"inputs": [
{
"type": "datasource",
"name": "DS_PROMETHEUS",
"pluginId": "prometheus",
"value": "Prometheus"
}
]
}'
${GRAFANA_URL}/api/dashboards/import
El refresh: "30s" hace que el dashboard se re-dibuje cada 30 segundos. Para un homelab es más que suficiente —no necesitas resolución de segundos salvo que estés debugueando un pico específico.
Alertas que importan: tres reglas y listo
El error más común es definir cincuenta alertas que se disparan a las tres de la mañana por un blip. Después terminás ignorando todas. Para un homelab, tres alertas bastan y son las que pagás cuando suenan:
# alerts.yml
groups:
- name: homelab_critical
rules:
- alert: HostDown
expr: up == 0
for: 2m
labels:
severity: critical
annotations:
summary: "Host {{ $labels.instance }} no responde a Prometheus"
description: "node_exporter lleva más de 2 minutos caído. Probable host apagado, red caída o firewall cambió."
- alert: DiskFillingUp
expr: |
(node_filesystem_avail_bytes{mountpoint!~"/boot.*|/snap.*"}
/ node_filesystem_size_bytes) < 0.15
for: 15m
labels:
severity: warning
annotations:
summary: "Disco {{ $labels.mountpoint }} en {{ $labels.instance }} por debajo del 15%"
description: "Quedan {{ $value | humanizePercentage }} libres. Reservá un find antes que se llene."
- alert: HighLoad5min
expr: node_load5 > (count by(instance) (node_cpu_seconds_total{mode="idle"}) * 2)
for: 10m
labels:
severity: warning
annotations:
summary: "Load average alto en {{ $labels.instance }}"
description: "Load5 = {{ $value | printf "%.2f" }}. Revisar procesos con top o htop."
Las tres cubren las caídas que te duelen: host completamente caído, disco llenándose (con 15 minutos de anticipación, así tienes tiempo de actuar antes del desastre), y saturación sostenida de CPU durante 10 minutos —no un pico de un minuto que es ruido normal. Para notificaciones usa Alertmanager con un webhook a Telegram o Ntfy; un canal dedicado de Telegram para alertas del homelab es la forma más barata y confiable.
Backup del TSDB: olvidate del día que lo necesitas
El día que tienes que reconstruir Prometheus —porque se llenó el disco, porque el contenedor se corrompió, porque cambiaste de máquina— vas a agradecer tener un backup. Prometheus incluye una API nativa para snapshots, y un cron semanal guardando en B2 o S3 es suficiente.
#!/bin/bash
# backup_prometheus.sh - ejecutar vía cron semanal
SNAP_DIR="/var/backups/prometheus/$(date +%Y%m%d_%H%M%S)"
mkdir -p "$SNAP_DIR"
curl -s -XPOST http://127.0.0.1:9090/api/v1/admin/tsdb/snapshot
sleep 5
# Mover el snapshot recien creado
SNAPSHOT=$(ls -t /prometheus/snapshots/ | head -1)
rsync -a /prometheus/snapshots/$SNAPSHOT/ "$SNAP_DIR/"
rm -rf /prometheus/snapshots/$SNAPSHOT
# Upload a Backblaze B2 con restic (ver post de backups cifrados)
restic backup "$SNAP_DIR"
restic forget --keep-weekly 4 --prune
El snapshot es un hardlink copy del TSDB, no cambia el tamaño usado, y se hace online sin downtime. La parte de Restic con cifrado AES-256 la cubre el post dedicado a backups en soylinux.com (link al final). Prueba una vez al mes que puedes restaurar el snapshot en otra VM antes que el archivo de backup se vuelva un misterio.
Resumen: lo que vale la pena y lo que no
Vale la pena: Prometheus + Grafana + node_exporter en una VM separada con docker-compose, scrapeando diez hosts vía file_sd_configs, con el dashboard “Node Exporter Full” importado, cAdvisor en los hosts Docker, tres alertas que suenan Telegram, y backup semanal del TSDB a B2. Eso te lleva dos horas armar y quince minutos mantener por semana.
No vale la pena para un homelab chico: Loki para logs (arrancá con journalctl -fu y lnav), Tempo o Jaeger para traces (no vas a necesitar trazar requests en tu homelab), un cluster de Prometheus con Thanos o Mimir (sobrecosto de operación enorme, masticado para la escala de un homelab), ni exporters exóticos (MySQL si no corres MySQL, SNMP si no tienes devices SNMP). Cada exporter que agregues es una superficie de falla más. Mantenete en el mínimo que resuelve tus problemas reales.
El monitoreo no es un destino, es una conversación con tus servidores. Empezá con poco, agrega cuando aparece un dolor real, y borrá cuando dejás de mirar el dashboard. La mejor monitoring es la que entiendes, no la más completa.
Preguntas frecuentes
¿Por qué DevOps para Sysadmins: Configura Grafana y Prometheus en tu Homelab es relevante para sysadmins Linux?
Forma parte del flujo diario de administración. Los conceptos explicados se aplican directamente a servidores en producción y resuelven problemas reales que enfrentan sysadmins hispanohablantes.
¿Qué necesito para empezar con DevOps para Sysadmins: Configura Grafana?
Distribución Linux actualizada (Debian, Ubuntu, RHEL, Fedora o Arch), acceso root, y conexión a internet. Para producción: entorno de staging separado antes de aplicar cambios.
¿Cuáles son los errores más comunes con DevOps para Sysadmins: Configura Grafana?
Los tres más frecuentes: (1) saltar la lectura de logs, (2) aplicar cambios directos en producción sin probar, (3) olvidar permisos y ownership. La documentación y un plan de rollback siempre.
¿Cuándo usar DevOps para Sysadmins: Configura Grafana y cuándo una alternativa?
Esta solución es ideal para el caso descrito. Alternativas como Docker, Ansible o configuración manual pueden ser mejores según contexto: portabilidad, escala y reproducibilidad son los factores clave.
¿Cómo migro desde una configuración previa a DevOps para Sysadmins: Configura Grafana?
Documentar el estado actual, probar la nueva configuración en staging, validar funcionalmente, y aplicar en producción con rollback plan listo. Los posts de SoyLinux incluyen troubleshooting para los problemas más comunes.
Lee también
- Guía Fedora 44: Novedades, Instalación y Upgrade para Sysadmins Linux
- Configura VLANs en Linux con nmcli: Guía paso a paso para sysadmins
- Protege tu SSH: Guía esencial para configurar Fail2ban en Linux
- Guía Definitiva: Configura Kubernetes con kubeadm en Ubuntu para Sysadmins Linux
- Configura Prometheus y Grafana: Guía DevOps para SysAdmins Linux
