tutoriales.com

Observabilidad Integral en Kubernetes: Monitorización, Logs y Tracing con Prometheus, Grafana y Jaeger 📊

Este tutorial te guiará a través de la implementación de una estrategia de observabilidad completa en Kubernetes utilizando herramientas líderes de la industria: Prometheus para la recolección de métricas, Grafana para la visualización de datos y creación de dashboards, y Jaeger para el tracing distribuido. Aprenderás a configurar cada componente y a correlacionar datos para una depuración y optimización efectiva de tus aplicaciones desplegadas.

Intermedio20 min de lectura22 views
Reportar error

La observabilidad es crucial para comprender el estado interno de tus aplicaciones y la infraestructura en la que se ejecutan, especialmente en entornos dinámicos como Kubernetes. Sin una visibilidad adecuada, depurar problemas, identificar cuellos de botella y optimizar el rendimiento se convierte en una tarea ardua y reactiva.

En este tutorial, exploraremos los tres pilares fundamentales de la observabilidad: métricas, logs y tracing distribuido. Utilizaremos herramientas open-source ampliamente adoptadas que forman un stack robusto para entornos Kubernetes: Prometheus, Grafana y Jaeger.


🎯 ¿Por qué la Observabilidad es Clave en Kubernetes?

Kubernetes es un orquestador de contenedores poderoso, pero su complejidad intrínseca, con microservicios comunicándose entre sí, redes virtuales y múltiples nodos, hace que sea difícil diagnosticar problemas cuando surgen. Una estrategia de observabilidad bien implementada te permite:

  • Identificar rápidamente la causa raíz de los problemas (Root Cause Analysis).
  • Predecir y prevenir fallos antes de que afecten a los usuarios.
  • Optimizar el uso de recursos y reducir costes.
  • Entender el comportamiento de tus aplicaciones en producción.
  • Medir el rendimiento y la experiencia del usuario.
📌 **Nota:** La observabilidad no es solo la recopilación de datos, sino la capacidad de responder a preguntas arbitrarias sobre el sistema basándose en esos datos.

Los Tres Pilares de la Observabilidad

  1. Métricas: Valores numéricos agregados que representan el estado del sistema en un punto en el tiempo (ej. uso de CPU, latencia de solicitudes, errores por segundo).
  2. Logs: Registros de eventos discretos que ocurren dentro de una aplicación o sistema (ej. un usuario inició sesión, un error de base de datos).
  3. Tracing Distribuido: Seguimiento de una solicitud individual a medida que viaja a través de múltiples servicios en una arquitectura de microservicios, mostrando la latencia y la relación entre los servicios.

🛠️ Herramientas Fundamentales para Kubernetes

Aquí tienes una descripción de las herramientas que utilizaremos:

  • Prometheus: Un sistema de monitorización y alertado basado en métricas. Recopila métricas de los endpoints configurados, las almacena en una base de datos de series temporales y permite consultarlas con su lenguaje PromQL. Es ideal para la monitorización de infraestructura y aplicaciones en Kubernetes.
  • Grafana: Una plataforma de visualización de datos de código abierto que se integra con múltiples fuentes de datos, incluyendo Prometheus. Permite crear dashboards interactivos y altamente personalizables para visualizar métricas de manera efectiva.
  • Jaeger: Un sistema de tracing distribuido de código abierto. Ayuda a monitorizar y solucionar problemas en arquitecturas de microservicios, rastreando las solicitudes a medida que se propagan a través de varios servicios.
Kubernetes (Aplicaciones) Prometheus Jaeger Grafana Métricas Traces Visualización Consulta Traces Integración de Traces

🚀 Configuración de Prometheus en Kubernetes

Prometheus es el corazón de nuestra solución de monitorización de métricas. Lo desplegaremos en Kubernetes utilizando Helm, un gestor de paquetes para Kubernetes.

Paso 1: Añadir el Repositorio de Helm para Prometheus

Primero, asegurémonos de tener Helm instalado y añade el repositorio de Prometheus Operator.

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

Paso 2: Desplegar Prometheus Operator

El Prometheus Operator facilita el despliegue y la gestión de Prometheus y sus componentes relacionados en Kubernetes. Crea ServiceMonitors y PodMonitors que Prometheus utiliza para descubrir automáticamente objetivos de scrape.

helm install prometheus prometheus-community/kube-prometheus-stack \
    --namespace monitoring --create-namespace \
    --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesPods=false

Este comando instala un stack completo que incluye Prometheus, Grafana (lo configuraremos más adelante, pero se instala con este stack), Alertmanager y Kube-State-Metrics.

💡 Consejo: El flag `--set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesPods=false` es importante en versiones recientes para asegurar que Prometheus Operator funcione correctamente con `ServiceMonitors`.

Paso 3: Verificar el Despliegue de Prometheus

Comprueba que los pods de Prometheus están en funcionamiento:

kubectl get pods -n monitoring

Deberías ver pods para prometheus-kube-prometheus-prometheus, grafana, alertmanager, etc., todos en estado Running.

Para acceder a la interfaz web de Prometheus, puedes usar kubectl port-forward:

kubectl port-forward svc/prometheus-kube-prometheus-prometheus 9090:9090 -n monitoring

Luego, abre tu navegador en http://localhost:9090.

Paso 4: Instrumentar tus Aplicaciones para Prometheus

Para que Prometheus pueda recolectar métricas de tus aplicaciones, estas deben exponer un endpoint /metrics en el formato de Prometheus. La mayoría de los lenguajes tienen bibliotecas cliente para esto (ej. promclient para Python, micrometer para Java).

Aquí un ejemplo simplificado de cómo una aplicación podría exponer métricas:

from prometheus_client import start_http_server, Counter, Gauge
import time

# Crear métricas
c = Counter('my_app_requests_total', 'Total number of requests to my app.')
g = Gauge('my_app_in_progress_requests', 'Number of requests currently in progress.')

if __name__ == '__main__':
    # Iniciar un servidor HTTP en el puerto 8000 para exponer métricas
    start_http_server(8000)
    print("Servidor de métricas Prometheus iniciado en el puerto 8000")
    while True:
        # Simular una solicitud
        g.inc()
        c.inc()
        time.sleep(1)
        g.dec()

Para que Prometheus descubra este endpoint en Kubernetes, puedes usar un ServiceMonitor. Aquí un ejemplo para una aplicación llamada my-app que expone métricas en el puerto 8000:

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: my-app-monitor
  labels:
    app: my-app
  namespace: default # O el namespace de tu aplicación
spec:
  selector:
    matchLabels:
      app: my-app # Selector para el Service de tu aplicación
  endpoints:
  - port: http-metrics # Nombre del puerto en el Service de tu aplicación
    path: /metrics
  namespaceSelector:
    matchNames:
    - default # O el namespace de tu aplicación

Asegúrate de que tu Deployment de la aplicación tenga etiquetas (app: my-app) y un Service que exponga el puerto 8000 con un nombre (http-metrics).

🔥 Importante: La instrumentación de tus aplicaciones es un paso crítico. Sin métricas significativas, la monitorización será limitada.

📊 Visualización con Grafana

Grafana ya está instalado como parte del stack kube-prometheus-stack. Ahora necesitamos acceder a él y configurarlo.

Paso 1: Obtener la Contraseña de Grafana

El nombre de usuario por defecto es admin. La contraseña se genera automáticamente y se almacena en un Secret de Kubernetes.

kubectl get secret prometheus-grafana -n monitoring -o jsonpath="{.data.admin-password}" | base64 --decode

Guarda esta contraseña.

Paso 2: Acceder a la Interfaz Web de Grafana

Reenvía el puerto de Grafana a tu máquina local:

kubectl port-forward svc/prometheus-grafana 3000:80 -n monitoring

Ahora, abre tu navegador en http://localhost:3000. Inicia sesión con admin y la contraseña que obtuviste.

Paso 3: Configurar Prometheus como Fuente de Datos

Grafana debería tener Prometheus configurado automáticamente como fuente de datos (Prometheus) si lo instalaste con kube-prometheus-stack. Puedes verificarlo en Configuration -> Data Sources.

Prometheus como Fuente de Datos: Configurado ✅

Paso 4: Importar y Crear Dashboards

Grafana brilla con sus dashboards. Puedes importar dashboards preconstruidos o crear los tuyos propios.

  • Importar Dashboards: Visita https://grafana.com/grafana/dashboards/ y busca dashboards para Kubernetes. Por ejemplo, el dashboard 1860 (Kubernetes / Kubelet) es muy útil. Una vez que encuentres uno, copia su ID y en Grafana, ve a Dashboards -> Import e introduce el ID. Selecciona tu fuente de datos Prometheus.

  • Crear un Dashboard Personalizado:

    1. Haz clic en el icono + en la barra lateral izquierda y selecciona Dashboard.
    2. Haz clic en Add new panel.
    3. En la pestaña Query, selecciona Prometheus como fuente de datos.
    4. Escribe una consulta PromQL. Por ejemplo, para ver el uso de CPU de un pod: sum(rate(container_cpu_usage_seconds_total{container="POD", namespace="default"}[5m])) by (pod).
    5. Ajusta el tipo de visualización (Graph, Stat, Gauge, etc.).
    6. Guarda el dashboard.
Ejemplo de Consulta PromQL útil para uso de memoria `sum(container_memory_working_set_bytes{container="POD", namespace="default"}) by (pod)`

🕵️ Tracing Distribuido con Jaeger

Jaeger nos permite seguir la vida de una solicitud a través de múltiples microservicios, identificando cuellos de botella y errores.

Paso 1: Desplegar Jaeger en Kubernetes

La forma más sencilla de desplegar Jaeger es usando el Jaeger Operator o un chart de Helm. Para este tutorial, usaremos Helm.

Primero, añade el repositorio de Helm de Jaeger:

helm repo add jaegertracing https://jaegertracing.github.io/helm-charts
helm repo update

Luego, instala Jaeger. Usaremos un despliegue all-in-one para simplicidad en este tutorial, aunque en producción se recomienda un despliegue distribuido con almacenamiento persistente (ej. Elasticsearch).

helm install jaeger jaegertracing/jaeger \
    --namespace tracing --create-namespace \
    --set allInOne.enabled=true \
    --set agent.strategy=daemonset \
    --set provisionDataStore.enabled=false # Desactivar almacenamiento en este ejemplo simple

Paso 2: Verificar el Despliegue de Jaeger

Comprueba los pods de Jaeger:

kubectl get pods -n tracing

Deberías ver un pod jaeger-all-in-one y jaeger-agent en cada nodo (si agent.strategy es daemonset).

Accede a la interfaz web de Jaeger:

kubectl port-forward svc/jaeger-query 16686:16686 -n tracing

Navega a http://localhost:16686.

Paso 3: Instrumentar tus Aplicaciones para Tracing

Este es el paso más complejo y requiere modificar el código de tus aplicaciones. Necesitas usar una biblioteca de instrumentación que sea compatible con OpenTracing o OpenTelemetry, que son estándares para la instrumentación de trazas.

Aquí hay un esquema general de cómo funciona la instrumentación:

  1. Inicializar el Tracer: Configura el cliente de Jaeger en tu aplicación para enviar trazas al colector de Jaeger.
  2. Crear Spans: Cada operación (ej. una solicitud HTTP entrante, una llamada a una base de datos) se encapsula en un span. Los spans tienen un nombre, una hora de inicio y fin, etiquetas y logs.
  3. Context Propagation: El contexto de la traza (ID de traza y ID de span) debe ser propagado a través de los límites del servicio (ej. en los encabezados HTTP) para que Jaeger pueda reconstruir la traza completa.

Ejemplo de código (Python con OpenTracing/Jaeger client):

from jaeger_client import Config
from opentracing import Tracer

# Configuración de Jaeger
def init_jaeger_tracer(service_name):
    config = Config(
        config={
            'sampler': {
                'type': 'const',
                'param': 1,
            },
            'logging': True,
        },
        service_name=service_name,
        validate=True,
    )
    return config.initialize_tracer()

# En tu aplicación, por ejemplo, en una función de manejo de solicitud:
# tracer = init_jaeger_tracer('my-microservice')

def process_request(tracer: Tracer, request_id):
    with tracer.start_active_span('process_request') as scope:
        span = scope.span
        span.log_kv({'event': 'request_received', 'request_id': request_id})
        # Simula trabajo
        time.sleep(0.05)

        # Llamada a otro servicio, propagando el contexto
        # headers = {}
        # tracer.inject(span.context, Format.HTTP_HEADERS, headers)
        # response = call_another_service(headers)

        span.log_kv({'event': 'request_processed', 'status': 'success'})
        return "Response"

# Para ejecutar esto, necesitarías un servidor HTTP que use el tracer
⚠️ Advertencia: La instrumentación de tracing requiere cambios en el código de tu aplicación y puede ser intensiva en tiempo y recursos. Planifica con cuidado.

Paso 4: Configurar los Agentes de Jaeger en tus Pods

Los agentes de Jaeger son proxies ligeros que reciben las trazas de tus aplicaciones y las envían al colector de Jaeger. Lo ideal es que cada pod tenga acceso a un agente local para reducir la latencia y la sobrecarga de la red.

Si instalaste Jaeger con agent.strategy=daemonset, un agente de Jaeger se ejecutará en cada nodo. Tus aplicaciones pueden enviar trazas a jaeger-agent.tracing.svc.cluster.local:6831 (UDP) o localhost:6831 si el agente se despliega como un sidecar en cada pod. La configuración del sidecar es más robusta y fácil de gestionar.

Ejemplo de Sidecar Jaeger en un Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-with-jaeger
spec:
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app
        image: my-app-image:latest
        ports:
        - containerPort: 8080
        env:
        - name: JAEGER_AGENT_HOST
          value: localhost
        - name: JAEGER_AGENT_PORT
          value: "6831"
        - name: JAEGER_SERVICE_NAME
          value: my-app-service
      - name: jaeger-agent # Sidecar container
        image: jaegertracing/jaeger-agent:latest
        ports:
        - containerPort: 6831
          protocol: UDP
        - containerPort: 5775
          protocol: UDP
        command:
        - /usr/bin/jaeger-agent
        - --reporter.grpc.host-port=jaeger-collector.tracing.svc.cluster.local:14250

Este sidecar asegura que cada aplicación tenga un agente Jaeger local para enviar sus trazas, que luego el agente reenvía al jaeger-collector central.


🔗 Correlación de Datos: La Clave de la Observabilidad

La verdadera potencia de la observabilidad reside en la capacidad de correlacionar métricas, logs y trazas. Esto te permite, por ejemplo, ver un pico en el uso de CPU (métrica), luego examinar los logs de ese período para encontrar errores, y finalmente usar el tracing para entender qué microservicio causó ese pico y por qué.

Estrategias de Correlación:

  • ID de Traza en Logs: Asegúrate de que tus aplicaciones incluyan el trace_id de Jaeger en sus logs. Así, cuando encuentres un error en los logs, podrás buscar directamente la traza correspondiente en Jaeger.
  • Enlaces en Dashboards de Grafana: Grafana permite añadir enlaces a los dashboards para que, al hacer clic en un panel de métricas, puedas ir directamente a una búsqueda de logs o trazas en Jaeger/Loki/Elasticsearch con el contexto adecuado (hora, servicio, etc.).
Identificar Anomalía: Observas un pico de latencia en Grafana (Métricas).
Investigar Logs: Usas el ID de traza de los logs (si está disponible) o el rango de tiempo para buscar logs relevantes y encontrar un error recurrente.
Analizar Trazas: Con el ID de traza o buscando por servicio/tiempo en Jaeger, visualizas la traza completa para identificar el servicio exacto y la operación que causa el problema.
Resolver Problema: Utilizas la información combinada para depurar y resolver la causa raíz.

💡 Buenas Prácticas y Consejos Adicionales

  • Estandariza la Instrumentación: Utiliza bibliotecas comunes (OpenTelemetry es el estándar emergente) y patrones de instrumentación en todas tus aplicaciones.
  • Etiquetado Consistente: Usa etiquetas (labels) consistentes en tus métricas y logs (ej. app, environment, service_name, version) para facilitar la agregación y filtrado en Grafana y Jaeger.
  • Alertas Inteligentes: Configura alertas en Prometheus Alertmanager para notificar sobre desviaciones significativas en tus métricas (ej. latencia alta, errores incrementando). Integra estas alertas con tus sistemas de comunicación (Slack, PagerDuty).
  • Almacenamiento Persistente: Para entornos de producción, considera soluciones de almacenamiento a largo plazo para métricas (Thanos, Cortex) y trazas (Elasticsearch para Jaeger) para análisis históricos y cumplimiento.
  • Seguridad: Protege el acceso a tus dashboards de Grafana y a la API de Prometheus/Jaeger.
  • Gestión de Logs: Para una gestión de logs robusta, considera añadir un stack ELK (Elasticsearch, Logstash, Kibana) o Grafana Loki al setup para recolectar y visualizar logs de forma centralizada.

Importante La observabilidad es un viaje, no un destino. Refina constantemente tus métricas, dashboards y alertas a medida que tus aplicaciones evolucionan.


Conclusión ✨

La implementación de un sistema de observabilidad completo con Prometheus para métricas, Grafana para visualización y Jaeger para tracing distribuido es fundamental para gestionar eficazmente aplicaciones en Kubernetes. Te proporciona las herramientas para entender profundamente el comportamiento de tus sistemas, depurar problemas de manera proactiva y asegurar la resiliencia de tus servicios. Al dominar estos componentes y la correlación de sus datos, estarás bien equipado para mantener tus aplicaciones saludables y optimizadas en un entorno de microservicios complejo.

Tutoriales relacionados

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!