Saltearse al contenido

Monitoreo y Logging

Tabla de Contenidos

  1. Propósito
  2. Descripción General del Stack de Observabilidad
  3. Configuración de Grafana
  4. Métricas de Prometheus
  5. Logging con Loki
  6. Grafana Alloy
  7. Instrumentación de Aplicaciones
  8. Consultas y Dashboards Comunes
  9. 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

ComponentePropósitoPuertoHost de Ingress
GrafanaDashboards y visualización3000algesta.grafana.3astronautas.com
PrometheusRecopilación y almacenamiento de métricas9090Solo interno
LokiAgregación de logs3100Solo interno
Grafana AlloyRecopilación de telemetría (reemplaza Promtail)12345Solo 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: v1
kind: PersistentVolumeClaim
metadata:
name: grafana-pvc
namespace: monitoring
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: default

Tareas Comunes:

Acceder a Grafana:

Ventana de terminal
# Port-forward para acceso local (si no está configurado ingress)
kubectl port-forward -n monitoring svc/grafana-service 3000:3000
# Abrir http://localhost:3000

Restablecer Contraseña de Administrador de Grafana:

Ventana de terminal
# Conectar al pod de Grafana
kubectl exec -it <grafana-pod> -n monitoring -- /bin/sh
# Restablecer contraseña usando grafana-cli
grafana-cli admin reset-admin-password <new-password>

Métricas de Prometheus

Prometheus recopila métricas de:

  • Clúster de Kubernetes (nodos, pods, despliegues)
  • Endpoints /metrics de 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 contenedor
  • container_memory_usage_bytes: Uso de memoria por contenedor
  • http_request_duration_seconds: Latencia de solicitudes de API
  • http_requests_total: Conteo de solicitudes de API
  • algesta_orders_created_total: Métrica de negocio personalizada (pedidos creados)

Consultar Prometheus:

Ventana de terminal
# Port-forward a Prometheus
kubectl port-forward -n monitoring svc/prometheus-service 9090:9090
# Abrir http://localhost:9090 y ejecutar consultas PromQL

Ejemplos 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: 24h

Consultar 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:

Ventana de terminal
# Verificar pods de Alloy
kubectl get pods -n monitoring -l app=alloy
# Ver logs de Alloy
kubectl logs -n monitoring -l app=alloy --tail=100

Instrumentació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):

AlertaCondiciónSeveridadAcción
Uso Alto de CPUCPU > 80% por 5 minWarningEscalar pods
Uso Alto de MemoriaMemoria > 90% por 5 minCriticalInvestigar fuga de memoria
Pod en CrashLoopConteo de reinicios > 5 en 10 minCriticalRevisar logs, hacer rollback
Tasa Alta de ErroresErrores 5xx > 5% de solicitudesCriticalInvestigar errores de aplicación
Certificado por VencerCertificado TLS vence en < 7 díasWarningVerificar 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:

Para Soporte: