Monitoreo y Logging
Tabla de Contenidos
- Propósito
- Descripción General del Stack de Observabilidad
- Configuración de Grafana
- Métricas de Prometheus
- Logging con Loki
- Grafana Alloy
- Instrumentación de Aplicaciones
- Consultas y Dashboards Comunes
- Alertas
Propósito
Este documento describe el stack de observabilidad para la plataforma Algesta, incluyendo Grafana para visualización, Prometheus para métricas, Loki para logs y Grafana Alloy para recopilación de telemetría. Todos los componentes se ejecutan en el namespace monitoring en AKS.
Descripción General del Stack de Observabilidad
| Componente | Propósito | Puerto | Host de Ingress |
|---|---|---|---|
| Grafana | Dashboards y visualización | 3000 | algesta.grafana.3astronautas.com |
| Prometheus | Recopilación y almacenamiento de métricas | 9090 | Solo interno |
| Loki | Agregación de logs | 3100 | Solo interno |
| Grafana Alloy | Recopilación de telemetría (reemplaza Promtail) | 12345 | Solo interno |
Flujo de Datos:
graph LR
A[Applications<br/>Pods] -->|Logs| B[Grafana Alloy]
A -->|Metrics| C[Prometheus]
B -->|Forward Logs| D[Loki]
C -->|Query| E[Grafana]
D -->|Query| E
E -->|Display| F[Users/Engineers]
Configuración de Grafana
Acceso: https://algesta.grafana.3astronautas.com (detrás de ingress con TLS)
Configuración:
- Almacenamiento: PersistentVolumeClaim (
grafana-pvc, 10 GB) - Fuentes de Datos: Prometheus, Loki (preconfiguradas)
- Autenticación: Usuario administrador (credenciales en Azure Key Vault)
Grafana PVC (ops-algesta/resources-k8s/monitoring/grafana-prometheus/grafana-pvc.yaml):
apiVersion: v1kind: PersistentVolumeClaimmetadata: name: grafana-pvc namespace: monitoringspec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi storageClassName: defaultTareas Comunes:
Acceder a Grafana:
# Port-forward para acceso local (si no está configurado ingress)kubectl port-forward -n monitoring svc/grafana-service 3000:3000# Abrir http://localhost:3000Restablecer Contraseña de Administrador de Grafana:
# Conectar al pod de Grafanakubectl exec -it <grafana-pod> -n monitoring -- /bin/sh
# Restablecer contraseña usando grafana-cligrafana-cli admin reset-admin-password <new-password>Métricas de Prometheus
Prometheus recopila métricas de:
- Clúster de Kubernetes (nodos, pods, despliegues)
- Endpoints
/metricsde aplicaciones (las aplicaciones NestJS exponen métricas de Prometheus) - Métricas de negocio personalizadas (conteo de pedidos, tasa de entrega de notificaciones)
Métricas Clave:
container_cpu_usage_seconds_total: Uso de CPU por contenedorcontainer_memory_usage_bytes: Uso de memoria por contenedorhttp_request_duration_seconds: Latencia de solicitudes de APIhttp_requests_total: Conteo de solicitudes de APIalgesta_orders_created_total: Métrica de negocio personalizada (pedidos creados)
Consultar Prometheus:
# Port-forward a Prometheuskubectl port-forward -n monitoring svc/prometheus-service 9090:9090
# Abrir http://localhost:9090 y ejecutar consultas PromQLEjemplos de Consultas PromQL:
Uso de CPU por Pod:
sum(rate(container_cpu_usage_seconds_total{namespace="production"}[5m])) by (pod)Uso de Memoria por Despliegue:
sum(container_memory_usage_bytes{namespace="production"}) by (deployment)Tasa de Solicitudes de API (últimos 5 minutos):
sum(rate(http_requests_total{namespace="production"}[5m])) by (service)Percentil 95 de Tiempo de Respuesta:
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket{namespace="production"}[5m]))Logging con Loki
Loki almacena logs de:
- Todos los pods en el clúster de AKS
- stdout/stderr de aplicaciones
- Logs estructurados (formato JSON recomendado)
Retención de Logs: 30 días (configurable en Valors.yaml)
Configuración (ops-algesta/resources-k8s/monitoring/loki/Valors.yaml):
loki: auth_enabled: false commonConfig: replication_factor: 1 storage: type: "filesystem" schemaConfig: configs: - from: "2024-01-01" store: tsdb object_store: filesystem schema: v13 index: prefix: loki_index_ period: 24hConsultar Logs en Grafana:
Ver Logs de un Pod Específico:
{namespace="production", pod="api-gateway-production-xxxxx-yyyyy"}Filtrar por Nivel de Log (ERROR):
{namespace="production", app="api-gateway"} |= "ERROR"Contar Errores en la Última Hora:
count_over_time({namespace="production"} |= "ERROR" [1h])Parsear Logs JSON:
{namespace="production", app="api-gateway"} | json | level="error"Grafana Alloy
Grafana Alloy reemplaza a Promtail como el agente de recopilación de telemetría.
Funcionalidades:
- Recopila logs de todos los pods
- Reenvía a Loki
- Soporta filtrado y transformación de logs
- Menor uso de recursos que Promtail
Configuración (ops-algesta/resources-k8s/monitoring/alloy/Valors.yaml):
alloy: configMap: content: | logging { level = "info" format = "logfmt" }
discovery.kubernetes "pods" { role = "pod" }
discovery.kubernetes "nodes" { role = "node" }
loki.source.kubernetes "pods" { targets = discovery.kubernetes.pods.targets forward_to = [loki.write.default.receiver] }
loki.write "default" { endpoint { url = "http://loki-service.monitoring.svc.cluster.local:3100/loki/api/v1/push" } }Verificar Estado de Alloy:
# Verificar pods de Alloykubectl get pods -n monitoring -l app=alloy
# Ver logs de Alloykubectl logs -n monitoring -l app=alloy --tail=100Instrumentación de Aplicaciones
Verificaciones de Salud de NestJS
Todos los microservicios exponen endpoints /health para pruebas de liveness/readiness.
Implementación (src/health/health.controller.ts):
import { Controller, Get } from "@nestjs/common";import { HealthCheck, HealthCheckService, MongooseHealthIndicator,} from "@nestjs/terminus";
@Controller("health")export class HealthController { constructor( private health: HealthCheckService, private db: MongooseHealthIndicator ) {}
@Get() @HealthCheck() check() { return this.health.check([() => this.db.pingCheck("database")]); }}Respuesta de Verificación de Salud:
{ "status": "ok", "info": { "database": { "status": "up" } }, "error": {}, "details": { "database": { "status": "up" } }}Endpoint de Métricas de Prometheus
Habilitar en NestJS (main.ts):
import { NestFactory } from "@nestjs/core";import * as promClient from "prom-client";
async function bootstrap() { const app = await NestFactory.create(AppModule);
// Crear registro de Prometheus const register = new promClient.Registry(); promClient.collectDefaultMetrics({ register });
// Exponer endpoint /metrics app.use("/metrics", (req, res) => { res.set("Content-Type", register.contentType); res.end(register.metrics()); });
await app.listen(3000);}bootstrap();Logging Estructurado
Usar Winston con formato JSON:
import { WinstonModule } from "nest-winston";import * as winston from "winston";
const logger = WinstonModule.createLogger({ transports: [ new winston.transports.Console({ format: winston.format.combine( winston.format.timestamp(), winston.format.json() ), }), ],});Ejemplo de Log:
{ "level": "info", "message": "Order created", "timestamp": "2025-11-20T10:15:30.123Z", "context": "OrdersService", "orderId": "ord_123456", "userId": "usr_789"}Consultas y Dashboards Comunes
Dashboards Preconfigurados
1. Descripción General del Clúster de Kubernetes:
- Uso de CPU/Memoria de nodos
- Conteo de pods por namespace
- Uso de PersistentVolume
2. Rendimiento de Aplicaciones:
- Tasa de solicitudes (solicitudes/segundo)
- Tiempo de respuesta (p50, p95, p99)
- Tasa de errores (4xx, 5xx)
3. Métricas de Negocio:
- Pedidos creados por hora
- Notificaciones enviadas
- Usuarios activos
Ejemplo de Dashboard JSON
Dashboard de Rendimiento del API Gateway:
{ "dashboard": { "title": "API Gateway Performance", "panels": [ { "title": "Request Rate", "targets": [ { "expr": "sum(rate(http_requests_total{service=\"api-gateway\"}[5m]))" } ] }, { "title": "Response Time (p95)", "targets": [ { "expr": "histogram_quantile(0.95, rate(http_request_duration_seconds_bucket{service=\"api-gateway\"}[5m]))" } ] } ] }}Alertas
Alertas Recomendadas (configurar en Grafana):
| Alerta | Condición | Severidad | Acción |
|---|---|---|---|
| Uso Alto de CPU | CPU > 80% por 5 min | Warning | Escalar pods |
| Uso Alto de Memoria | Memoria > 90% por 5 min | Critical | Investigar fuga de memoria |
| Pod en CrashLoop | Conteo de reinicios > 5 en 10 min | Critical | Revisar logs, hacer rollback |
| Tasa Alta de Errores | Errores 5xx > 5% de solicitudes | Critical | Investigar errores de aplicación |
| Certificado por Vencer | Certificado TLS vence en < 7 días | Warning | Verificar renovación de cert-manager |
Ejemplo de Configuración de Alerta:
groups: - name: algesta-production interval: 30s rules: - alert: HighCPUUsage expr: sum(rate(container_cpu_usage_seconds_total{namespace="production"}[5m])) by (pod) > 0.8 for: 5m labels: severity: warning annotations: summary: "High CPU usage on {{ $labels.pod }}" description: "CPU usage is above 80% for 5 minutes"Documentación Relacionada:
- Operaciones de Kubernetes: Logs de pods y depuración
- Runbooks: Procedimientos operacionales comunes
- Respuesta a Incidentes: Uso de métricas durante incidentes
Para Soporte:
- Acceder a Grafana: https://algesta.grafana.3astronautas.com
- Consultar Prometheus:
kubectl port-forward -n monitoring svc/prometheus-service 9090:9090 - Ver logs: Grafana → Explore → Loki