Prometheus y node_exporter: monitorización de sistemas Linux

Prometheus es un sistema de monitorización basado en scraping: en lugar de que los agentes empujen métricas hacia un colector central, Prometheus las tira él mismo consultando endpoints HTTP a intervalos configurables. Cada objetivo expone sus métricas en texto plano en una URL (por convención /metrics), y Prometheus las almacena en su TSDB (time-series database) local con etiquetas clave-valor que permiten consultas multidimensionales. Este modelo pull invierte la responsabilidad: el servidor de monitorización controla cuándo y con qué frecuencia muestrea, lo que simplifica el control de acceso y hace trivial detectar cuando un objetivo deja de responder.

node_exporter es el agente estándar para exponer métricas de hardware y sistema operativo. No ejecuta nada activo: lee /proc, /sys y otras fuentes del kernel y las serializa en el formato de exposición de Prometheus. En Debian Bookworm está disponible directamente como prometheus-node-exporter. La decisión de separarlo de Prometheus en sí mismo es deliberada: cada tipo de servicio tiene su propio exporter (mysqld_exporter, blackbox_exporter, redis_exporter), y puedes añadirlos o quitarlos sin tocar la configuración central.

Cuándo usarlo: cualquier servidor en producción. No hay alternativa razonable para tener visibilidad sobre CPU, memoria, disco e interfaces de red con retención histórica y capacidad de alerta. Sin esto, cuando un disco se llena a las 3 AM o un proceso empieza a consumir memoria de forma sostenida, te enteras cuando ya hay un incidente.

Lo que se rompe cuando se configura mal es sutil pero doloroso: un intervalo de scrape demasiado corto bajo carga alta genera back-pressure en el propio Prometheus; etiquetas mal diseñadas causan cardinalidad explosiva que degrada la TSDB; y alertas sin for: disparan falsos positivos en cualquier spike momentáneo.

# ── 1. Instalar node_exporter y Prometheus ──────────────────────────────
apt install prometheus-node-exporter prometheus -y

# node_exporter escucha en :9100 por defecto; prometheus en :9090
# Verificar que ambos servicios están activos
systemctl status prometheus-node-exporter prometheus

# ── 2. Revisar que el endpoint de métricas responde ────────────────────
curl -s http://localhost:9100/metrics | grep -E '^node_cpu_seconds_total' | head -5
# Salida esperada: líneas con etiquetas {cpu="0",mode="idle"} etc.

# ── 3. Configurar Prometheus para hacer scrape de este nodo ────────────
# El archivo principal en Debian está en /etc/prometheus/prometheus.yml
# La instalación por defecto ya incluye un job para localhost:9090 (self-monitoring)
# Añadimos el scrape de node_exporter:

cat >> /etc/prometheus/prometheus.yml << 'EOF'

  - job_name: 'node'
    static_configs:
      - targets: ['localhost:9100']
        labels:
          instance: 'produccion-web-01'
          env: 'prod'
EOF

# La indentación importa: este bloque va dentro de scrape_configs
# Si el archivo ya existe con contenido, edítalo manualmente para
# asegurarte de que la estructura YAML es correcta:
# scrape_configs:
#   - job_name: 'prometheus'
#     ...
#   - job_name: 'node'       ← aquí
#     ...

# Validar la sintaxis antes de recargar
promtool check config /etc/prometheus/prometheus.yml

# Recargar sin reiniciar (Prometheus soporta SIGHUP para reload)
systemctl reload prometheus
# En versiones donde reload no recarga config, usa:
# kill -HUP $(pidof prometheus)

# ── 4. Verificar que Prometheus ve el target ────────────────────────────
# Desde la API HTTP (sin UI):
curl -s http://localhost:9090/api/v1/targets | \
  python3 -m json.tool | grep -A3 '"job":"node"'

# ── 5. Queries PromQL útiles para operaciones diarias ──────────────────
# CPU idle promedio en todos los cores (últimos 5 minutos):
# avg(rate(node_cpu_seconds_total{mode="idle",instance="produccion-web-01"}[5m])) * 100

# Memoria disponible en GiB:
# node_memory_MemAvailable_bytes{instance="produccion-web-01"} / 1024^3

# Espacio libre en / en porcentaje:
# node_filesystem_avail_bytes{mountpoint="/",fstype!="tmpfs"} /
#   node_filesystem_size_bytes{mountpoint="/",fstype!="tmpfs"} * 100

# ── 6. Regla de alerta básica ──────────────────────────────────────────
mkdir -p /etc/prometheus/rules

cat > /etc/prometheus/rules/node_alerts.yml << 'EOF'
groups:
  - name: node_recursos
    rules:
      - alert: DiscoLleno
        # rate() sobre avail_bytes no tiene sentido; usamos el valor directo
        expr: >
          node_filesystem_avail_bytes{mountpoint="/",fstype!="tmpfs"}
          / node_filesystem_size_bytes{mountpoint="/",fstype!="tmpfs"} * 100 < 15
        for: 10m
        # for: evita alertar por un spike de escritura puntual;
        # solo dispara si la condición se mantiene 10 minutos seguidos
        labels:
          severity: warning
        annotations:
          summary: "Disco bajo en {{ $labels.instance }}"
          description: "Queda {{ $value | printf \"%.1f\" }}% en /"

      - alert: MemoriaInsuficiente
        expr: >
          node_memory_MemAvailable_bytes
          / node_memory_MemTotal_bytes * 100 < 10
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Memoria crítica en {{ $labels.instance }}"
          description: "Solo {{ $value | printf \"%.1f\" }}% de RAM disponible"
EOF

# Referenciar el directorio de reglas en prometheus.yml
# (si no está ya configurado):
grep -q 'rule_files' /etc/prometheus/prometheus.yml || \
  sed -i '/^global:/a rule_files:\n  - "/etc/prometheus/rules/*.yml"' \
  /etc/prometheus/prometheus.yml

promtool check rules /etc/prometheus/rules/node_alerts.yml
systemctl reload prometheus

# ── 7. Verificar que las alertas están cargadas ─────────────────────────
curl -s http://localhost:9090/api/v1/rules | \
  python3 -m json.tool | grep '"name"'

# ── 8. Instalar Grafana y conectar Prometheus como datasource ──────────
# Grafana no está en los repos de Debian Bookworm; se instala desde
# el repositorio oficial de Grafana:
apt install -y apt-transport-https software-properties-common wget
wget -q -O /usr/share/keyrings/grafana.key \
  https://apt.grafana.com/gpg.key

echo "deb [signed-by=/usr/share/keyrings/grafana.key] \
  https://apt.grafana.com stable main" \
  > /etc/apt/sources.list.d/grafana.list

apt update && apt install grafana -y
systemctl enable --now grafana-server

# Grafana escucha en :3000; credenciales por defecto: admin/admin
# Añadir datasource vía API (evita clicks manuales, reproducible):
curl -s -X POST http://admin:admin@localhost:3000/api/datasources \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Prometheus",
    "type": "prometheus",
    "url": "http://localhost:9090",
    "access": "proxy",
    "isDefault": true
  }'

# Dashboard recomendado para node_exporter: ID 1860 en grafana.com
# Importar via API:
curl -s -X POST http://admin:admin@localhost:3000/api/dashboards/import \
  -H 'Content-Type: application/json' \
  -d '{
    "dashboard": null,
    "folderId": 0,
    "overwrite": true,
    "inputs": [{"name":"DS_PROMETHEUS","type":"datasource","pluginId":"prometheus","value":"Prometheus"}],
    "path": "https://grafana.com/api/dashboards/1860/revisions/latest/download"
  }'
# Nota: este último curl no funciona directamente así;
# descarga el JSON con wget y luego súbelo con la misma llamada a /api/dashboards/import
# Se muestra la estructura para ilustrar el flujo automatizable

Qué está pasando en cada decisión relevante

El bloque for: 10m en las alertas es lo más importante que hay que entender aquí. Prometheus evalúa las reglas cada evaluation_interval (15 segundos por defecto en Debian). Sin for:, cualquier bajada momentánea de espacio en disco mientras se escribe un fichero grande dispara la alerta y la resuelve en el siguiente ciclo. Con for: 10m, la condición tiene que ser verdadera en cada evaluación durante 10 minutos consecutivos antes de que la alerta pase a estado firing. En producción, el 80% de los falsos positivos en alertas de recursos vienen de no usar este campo.

Las etiquetas instance: 'produccion-web-01' y env: 'prod' en static_configs se adjuntan a todas las métricas que Prometheus recoja de ese target. Esto no es cosmético: son la base para filtrar en PromQL ({env="prod"}) y para enrutar alertas en Alertmanager hacia canales distintos según entorno. Definirlas en el scrape config en lugar de en cada query es lo que hace que el modelo de etiquetas de Prometheus escale.

El uso de rate() sobre node_cpu_seconds_total merece atención. Esta métrica es un contador monotónico (nunca decrece, se reinicia solo si el proceso se reinicia). rate() calcula la tasa de incremento por segundo sobre la ventana temporal especificada. Si usas directamente el valor del contador, obtienes un número que solo sube. La ventana [5m] en rate(...[5m]) debe ser al menos 4 veces el intervalo de scrape para que la estimación sea estadísticamente estable; con scrape cada 15 segundos, [1m] ya funciona, pero [5m] suaviza spikes puntuales que no te interesan.

promtool check config y promtool check rules no son opcionales antes de recargar. Un YAML mal indentado en prometheus.yml hace que Prometheus rechace la configuración completa en el reload y continúe con la anterior sin avisar de forma obvia en el log de systemd a menos que mires el nivel warn. Añadir estas validaciones a cualquier pipeline de CI que modifique la configuración es el mínimo indispensable.

La instalación de prometheus-node-exporter desde los repos de Debian crea automáticamente un usuario del sistema prometheus sin shell y el servicio systemd correspondiente con restricciones de seguridad (PrivateTmp, NoNewPrivileges, ProtectSystem). Consulta el unit con systemctl cat prometheus-node-exporter para ver exactamente qué capacidades tiene; si necesitas colectores adicionales que requieran acceso a recursos del sistema no habilitados por defecto (como --collector.systemd), tendrás que editar el override del unit para añadirlos.

[Ubuntu]: En Ubuntu, el paquete se llama igual (prometheus-node-exporter), pero el archivo de configuración de node_exporter para pasar flags al binario está en /etc/default/prometheus-node-exporter en lugar de en el override de systemd. En Debian Bookworm, el mecanismo correcto es systemctl edit prometheus-node-exporter.

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio