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.
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.
Los Tres Pilares de la Observabilidad
- 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).
- 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).
- 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.
🚀 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.
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).
📊 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.
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 aDashboards->Importe introduce el ID. Selecciona tu fuente de datos Prometheus. -
Crear un Dashboard Personalizado:
- Haz clic en el icono
+en la barra lateral izquierda y seleccionaDashboard. - Haz clic en
Add new panel. - En la pestaña
Query, seleccionaPrometheuscomo fuente de datos. - 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). - Ajusta el tipo de visualización (Graph, Stat, Gauge, etc.).
- Guarda el dashboard.
- Haz clic en el icono
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:
- Inicializar el Tracer: Configura el cliente de Jaeger en tu aplicación para enviar trazas al colector de Jaeger.
- 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.
- 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
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_idde 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.).
💡 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
- Escalado Automático en Kubernetes: Optimizando Recursos con HPA y VPA 🚀intermediate15 min
- Gestión de Configuración en Kubernetes: ConfigMaps y Secrets para Aplicaciones Robustas ⚙️intermediate18 min
- Despliegues Azules/Verdes en Kubernetes: Estrategias de Actualización sin Interrupciones 🔄intermediate20 min
Comentarios (0)
Aún no hay comentarios. ¡Sé el primero!