Modernización de un stack de observabilidad con Grafana y Prometheus
El stack se había quedado atrás: Grafana ya sin soporte, Prometheus con ocho versiones menores de atraso y los dashboards pesados tardando decenas de segundos en renderizar. Así fue como llevé ambos a LTS e hice que esos dashboards fueran unas 30 veces más rápidos, sin pérdida de datos y sin tocar ninguna alerta.
El trabajo combinó actualizaciones de versión, recording rules y validación operativa.
Contribución de un vistazo
- Mi responsabilidad
- Actualizaciones escalonadas del monitoreo, limpieza de dashboards y trabajo con recording rules.
- Alcance
- Modernización de Grafana y Prometheus con backups y validación operativa.
- Colaboración y límites
- Mantuve el stack de monitoreo y verifiqué el comportamiento de las consultas y los dashboards a través de los cambios de versión.
- Resultado
- Actualicé el stack de monitoreo y persistí los dashboards migrados; este caso no establece una mejora de latency a nivel de toda la flota.
Los stacks de observabilidad se deterioran en silencio. Las actualizaciones parecen riesgosas, así que se posponen, y un día te encuentras con un Grafana sin soporte, con dashboards en los que nadie confía y consultas que tardan medio minuto. Este es el relato de cómo devolví uno al día: dos versiones mayores de Grafana, un salto de Prometheus a LTS y las recording rules que fueron la verdadera victoria.
Grafana: de fin de soporte a 11.6 LTS
Grafana estaba en una versión sin soporte, a solo una versión mayor de distancia de que el runtime de plugins de Angular desapareciera por completo. Lo llevé a 11.6 LTS de forma deliberada y reversible:
- Salto de imagen en dos pasos (a través de una versión menor intermedia) en lugar de un gran salto único, de modo que cada paso fuera pequeño y fácil de revertir.
- Eliminación del runtime de Angular. Grafana 11 deshabilita el runtime de plugins de Angular, así que primero desinstalé los plugins de panel heredados en Angular y luego llevé los dashboards con el esquema antiguo por la migración automática para que los nuevos tipos de panel en React se persistieran.
- Limpieza de dashboards. Exporté cada dashboard de la instancia en vivo a git (se había desincronizado de la base de datos) y luego eliminé los abandonados.
- Backups defensivos. Snapshots de disco antes de cada cambio. Los dos quedaron sin usar, que es exactamente como deberían terminar los backups.
- Cero interrupciones. Todas las alert rules y los datasources pasaron por la actualización sin cambios. Una pasada posterior lo llevó a la siguiente versión mayor con una auditoría completa de dashboards.
La verdadera victoria: las recording rules de Prometheus
Los dashboards pesados de ingress eran un suplicio: de 8 a 33 segundos por render. La causa era que histogram_quantile() se recalculaba a partir de decenas de miles de series de buckets (unas 57k) en cada actualización. La solución es un clásico que es fácil olvidar: las recording rules.
Agregué tres recording rules por entorno que preagregan el P50, el P90 y el P99 del histograma de duración de las solicitudes, y apunté los dashboards a las series precomputadas en lugar de a los buckets crudos.
| Entorno | Antes | Después | Aceleración |
|---|---|---|---|
| Producción (mayor cardinalidad) | 8 a 33 s | ~0.66 s | ~30× |
| Sandbox (menor cardinalidad) | 3.5 a 9 s | ~0.66 s | ~5 a 13× |
Prometheus: de 2.45 a 2.53 LTS
Actualicé Prometheus ocho versiones menores hasta 2.53 LTS, de forma escalonada y segura: primero el cluster de sandbox y luego producción tras un periodo de estabilización de 24 horas. Vale la pena mencionar una restricción del mundo real: el stack usa el fork gestionado (GMP) de Prometheus porque las alertas y los dashboards de Cloud Monitoring del entorno dependen de su exporter integrado. El Prometheus upstream ya va por la 3.x, pero el fork gestionado llega como máximo a 2.53 LTS, así que ese era el techo. Saber en qué fork estás, y por qué, es la mitad de la actualización.
Un refactor de configuración que vale la pena
Las configuraciones de Prometheus por entorno se habían desviado hacia órdenes de sección distintos, lo que convertía en una molestia comparar (diff) un entorno con otro. Las reordené a una única estructura canónica (persistent volumes, config, RBAC, StatefulSet, services, ingress). Sin cambios funcionales, pero ahora un diff lado a lado muestra solo las diferencias que importan.
Un bug latente, encontrado de paso
Mientras validaba las recording rules encontré un panel que mostraba "No data" sobre una consulta que claramente tenía datos. La causa era una configuración de thresholds de Grafana (thresholdsStyle: line+area) con un último paso de threshold al que le faltaba su valor. El tipo de bug que se esconde durante meses hasta que alguien mira con atención el panel correcto.
Lo que le diría a alguien que recién empieza con esto
- Recurre a las recording rules antes de culpar al dashboard. Si un panel recalcula un cuantil sobre decenas de miles de series en cada render, preagrégalo.
- Actualiza en pasos pequeños y reversibles, y toma un snapshot antes de cada uno. El salto de fin de soporte a LTS da menos miedo como dos saltos pequeños que como uno grande.
- Conoce tu fork. El fork gestionado de Prometheus y el upstream no son el mismo tren de versiones; elige la LTS más alta que tu fork realmente publique.
- Mantén la configuración en un orden canónico en todos los entornos. La desviación en la estructura esconde la desviación en el significado.
Decisiones y próximos pasos
Una mirada retrospectiva al enfoque y sus límites. La próxima mejora es una propuesta, no un resultado entregado.
Alternativa y justificación
Una única actualización grande reduce los pasos, pero combina los modos de falla. Los cambios escalonados y los backups facilitan aislar las incompatibilidades.
Contrapartida
Las recording rules reducen el trabajo repetido de consultas, pero introducen definiciones adicionales cuyo significado y vigencia deben mantenerse.
Lo que mejoraría a continuación
Próxima mejora: mantener consultas representativas de dashboards y pruebas de reglas en una suite repetible de aceptación de actualizaciones.