Trazado distribuido de Istio
Versiones compatibles: Istio 1.28 Última actualización: February 19, 2026
El trazado distribuido rastrea y visualiza los flujos de solicitudes entre microservicios, lo que permite identificar cuellos de botella de latencia, analizar causas raíz de errores y comprender las dependencias de los servicios.
Tabla de contenidos
- Descripción general del trazado distribuido
- Integración con OpenTelemetry
- Integración con Jaeger
- Integración con Zipkin
- Propagación de contexto
- Estrategias de muestreo
- Análisis de trazas
- Adición de Spans personalizados
- Optimización del rendimiento
- Solución de problemas
Descripción general del trazado distribuido
Contexto de trazas de W3C
Istio admite el estándar W3C Trace Context para garantizar una propagación estandarizada de las trazas.
Conceptos principales
Trace
Una colección de spans que representa la ruta completa de una única solicitud a través del sistema
Span
Una unidad que representa el inicio y el final de una operación específica
- ID de Span: Identificador único
- ID de Span padre: Referencia al Span padre
- ID de Trace: Identificador de toda la traza
- Nombre de operación: Nombre de la operación (p. ej.,
HTTP GET /api/products) - Duración: Tiempo que tarda la operación
- Etiquetas: Metadatos (nombre del servicio, estado HTTP, etc.)
- Logs: Eventos con marca de tiempo
Baggage
Pares clave-valor propagados a lo largo de toda la traza
Integración con OpenTelemetry
OpenTelemetry es el estándar moderno de observabilidad y el backend de trazado recomendado para Istio 1.28.
1. Instalación de OpenTelemetry Collector
apiVersion: v1
kind: ConfigMap
metadata:
name: otel-collector-config
namespace: observability
data:
config.yaml: |
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
timeout: 10s
send_batch_size: 1024
send_batch_max_size: 2048
memory_limiter:
check_interval: 1s
limit_mib: 1024
# Add span attributes
attributes:
actions:
- key: cluster.name
value: production-k8s
action: insert
- key: deployment.environment
value: production
action: insert
# Span filtering
filter:
spans:
include:
match_type: regexp
services:
- ".*"
exclude:
match_type: strict
span_names:
- /health
- /readiness
- /liveness
# Tail sampling (intelligent sampling)
tail_sampling:
policies:
# 100% sampling for traces with errors
- name: errors-policy
type: status_code
status_code:
status_codes:
- ERROR
# 100% sampling for slow requests
- name: slow-requests-policy
type: latency
latency:
threshold_ms: 1000
# 10% sampling for normal requests
- name: probabilistic-policy
type: probabilistic
probabilistic:
sampling_percentage: 10
exporters:
# Export to Jaeger
jaeger:
endpoint: jaeger-collector.observability.svc.cluster.local:14250
tls:
insecure: true
# Export to Zipkin
zipkin:
endpoint: http://zipkin.observability.svc.cluster.local:9411/api/v2/spans
# Export to Tempo (Grafana ecosystem)
otlp/tempo:
endpoint: tempo.observability.svc.cluster.local:4317
tls:
insecure: true
# Logging for debugging
logging:
loglevel: info
sampling_initial: 5
sampling_thereafter: 200
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch, attributes, filter, tail_sampling]
exporters: [jaeger, otlp/tempo, logging]
telemetry:
logs:
level: info
metrics:
address: :8888
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: otel-collector
namespace: observability
spec:
replicas: 3
selector:
matchLabels:
app: otel-collector
template:
metadata:
labels:
app: otel-collector
spec:
containers:
- name: otel-collector
image: otel/opentelemetry-collector-contrib:0.96.0
args:
- --config=/etc/otel/config.yaml
ports:
- containerPort: 4317
name: otlp-grpc
protocol: TCP
- containerPort: 4318
name: otlp-http
protocol: TCP
- containerPort: 8888
name: metrics
protocol: TCP
volumeMounts:
- name: config
mountPath: /etc/otel
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2000m
memory: 4Gi
livenessProbe:
httpGet:
path: /
port: 13133
readinessProbe:
httpGet:
path: /
port: 13133
volumes:
- name: config
configMap:
name: otel-collector-config
---
apiVersion: v1
kind: Service
metadata:
name: otel-collector
namespace: observability
spec:
selector:
app: otel-collector
ports:
- name: otlp-grpc
port: 4317
targetPort: 4317
- name: otlp-http
port: 4318
targetPort: 4318
- name: metrics
port: 8888
targetPort: 8888
type: ClusterIP2. Habilitación de OpenTelemetry en Istio
Configuración de MeshConfig
apiVersion: v1
kind: ConfigMap
metadata:
name: istio
namespace: istio-system
data:
mesh: |
defaultConfig:
tracing:
sampling: 100.0 # Initially 100% sampling, tail sampling at collector
max_path_tag_length: 256
extensionProviders:
- name: otel-tracing
opentelemetry:
service: otel-collector.observability.svc.cluster.local
port: 4317
resource_detectors:
environment: {}
dynatrace: {}Habilitación del trazado con Telemetry API
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: otel-tracing
namespace: istio-system
spec:
tracing:
- providers:
- name: otel-tracing
randomSamplingPercentage: 100.0
customTags:
cluster_id:
literal:
value: "production-cluster"
environment:
literal:
value: "production"3. Configuración de trazado por Namespace
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: namespace-tracing
namespace: production
spec:
tracing:
- providers:
- name: otel-tracing
randomSamplingPercentage: 100.0
customTags:
namespace:
literal:
value: "production"
team:
literal:
value: "backend-team"
# Add request headers as tags
user_id:
header:
name: x-user-id
defaultValue: "unknown"
request_id:
header:
name: x-request-id
# Add environment variables as tags
pod_name:
environment:
name: POD_NAME
defaultValue: "unknown"Integración con Jaeger
Jaeger es el sistema de trazado distribuido de código abierto más utilizado.
Deployment todo en uno de Jaeger (desarrollo/pruebas)
apiVersion: apps/v1
kind: Deployment
metadata:
name: jaeger
namespace: observability
spec:
replicas: 1
selector:
matchLabels:
app: jaeger
template:
metadata:
labels:
app: jaeger
spec:
containers:
- name: jaeger
image: jaegertracing/all-in-one:1.55
env:
- name: COLLECTOR_ZIPKIN_HOST_PORT
value: :9411
- name: COLLECTOR_OTLP_ENABLED
value: "true"
ports:
- containerPort: 5775
protocol: UDP
- containerPort: 6831
protocol: UDP
- containerPort: 6832
protocol: UDP
- containerPort: 5778
protocol: TCP
- containerPort: 16686
protocol: TCP
- containerPort: 14250
protocol: TCP
- containerPort: 14268
protocol: TCP
- containerPort: 14269
protocol: TCP
- containerPort: 4317 # OTLP gRPC
protocol: TCP
- containerPort: 4318 # OTLP HTTP
protocol: TCP
- containerPort: 9411
protocol: TCP
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 1Gi
---
apiVersion: v1
kind: Service
metadata:
name: jaeger-collector
namespace: observability
spec:
selector:
app: jaeger
ports:
- name: jaeger-collector-http
port: 14268
targetPort: 14268
- name: jaeger-collector-grpc
port: 14250
targetPort: 14250
- name: otlp-grpc
port: 4317
targetPort: 4317
- name: otlp-http
port: 4318
targetPort: 4318
- name: zipkin
port: 9411
targetPort: 9411
---
apiVersion: v1
kind: Service
metadata:
name: jaeger-query
namespace: observability
spec:
selector:
app: jaeger
ports:
- name: query-http
port: 16686
targetPort: 16686
type: LoadBalancerDeployment de Jaeger para producción (backend de Elasticsearch)
# Elasticsearch (Storage Backend)
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
name: jaeger-es
namespace: observability
spec:
version: 8.12.0
nodeSets:
- name: default
count: 3
config:
node.store.allow_mmap: false
volumeClaimTemplates:
- metadata:
name: elasticsearch-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
storageClassName: gp3
---
# Jaeger Collector (Collection)
apiVersion: apps/v1
kind: Deployment
metadata:
name: jaeger-collector
namespace: observability
spec:
replicas: 3
selector:
matchLabels:
app: jaeger-collector
template:
metadata:
labels:
app: jaeger-collector
spec:
containers:
- name: jaeger-collector
image: jaegertracing/jaeger-collector:1.55
env:
- name: SPAN_STORAGE_TYPE
value: elasticsearch
- name: ES_SERVER_URLS
value: https://jaeger-es-es-http:9200
- name: ES_USERNAME
value: elastic
- name: ES_PASSWORD
valueFrom:
secretKeyRef:
name: jaeger-es-elastic-user
key: elastic
- name: COLLECTOR_OTLP_ENABLED
value: "true"
- name: COLLECTOR_ZIPKIN_HOST_PORT
value: :9411
ports:
- containerPort: 14250
name: grpc
- containerPort: 14268
name: http
- containerPort: 4317
name: otlp-grpc
- containerPort: 4318
name: otlp-http
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2000m
memory: 4Gi
---
# Jaeger Query (UI)
apiVersion: apps/v1
kind: Deployment
metadata:
name: jaeger-query
namespace: observability
spec:
replicas: 2
selector:
matchLabels:
app: jaeger-query
template:
metadata:
labels:
app: jaeger-query
spec:
containers:
- name: jaeger-query
image: jaegertracing/jaeger-query:1.55
env:
- name: SPAN_STORAGE_TYPE
value: elasticsearch
- name: ES_SERVER_URLS
value: https://jaeger-es-es-http:9200
- name: ES_USERNAME
value: elastic
- name: ES_PASSWORD
valueFrom:
secretKeyRef:
name: jaeger-es-elastic-user
key: elastic
ports:
- containerPort: 16686
name: query
resources:
requests:
cpu: 200m
memory: 512Mi
limits:
cpu: 1000m
memory: 2GiUso de Jaeger directamente con Istio
apiVersion: v1
kind: ConfigMap
metadata:
name: istio
namespace: istio-system
data:
mesh: |
defaultConfig:
tracing:
sampling: 100.0
zipkin:
address: jaeger-collector.observability:9411
extensionProviders:
- name: jaeger
zipkin:
service: jaeger-collector.observability.svc.cluster.local
port: 9411
maxTagLength: 256apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: jaeger-tracing
namespace: istio-system
spec:
tracing:
- providers:
- name: jaeger
randomSamplingPercentage: 100.0Integración con Zipkin
Zipkin es otro sistema popular de trazado distribuido.
Deployment de Zipkin
apiVersion: apps/v1
kind: Deployment
metadata:
name: zipkin
namespace: observability
spec:
replicas: 1
selector:
matchLabels:
app: zipkin
template:
metadata:
labels:
app: zipkin
spec:
containers:
- name: zipkin
image: openzipkin/zipkin:2.24
ports:
- containerPort: 9411
env:
- name: STORAGE_TYPE
value: elasticsearch
- name: ES_HOSTS
value: elasticsearch:9200
resources:
requests:
cpu: 200m
memory: 512Mi
limits:
cpu: 1000m
memory: 2Gi
---
apiVersion: v1
kind: Service
metadata:
name: zipkin
namespace: observability
spec:
selector:
app: zipkin
ports:
- port: 9411
targetPort: 9411
type: LoadBalancerConfiguración de Zipkin en Istio
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: zipkin-tracing
namespace: istio-system
spec:
tracing:
- providers:
- name: zipkin
randomSamplingPercentage: 100.0Propagación de contexto
La clave del trazado distribuido es propagar correctamente el contexto de traza entre los servicios.
Encabezados HTTP obligatorios
Las aplicaciones deben propagar los siguientes encabezados:
W3C Trace Context (recomendado)
traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
tracestate: congo=t61rcWkgMzEEncabezados B3 (heredados)
Formato de encabezado único (recomendado):
b3: 80f198ee56343ba864fe8b2a57d3eff7-e457b5a2e4d86bd1-1-05e3ac9a4f6e3b90Formato de encabezados múltiples:
X-B3-TraceId: 80f198ee56343ba864fe8b2a57d3eff7
X-B3-SpanId: e457b5a2e4d86bd1
X-B3-ParentSpanId: 05e3ac9a4f6e3b90
X-B3-Sampled: 1
X-B3-Flags: 0Propagación de contexto por aplicación
Python (Flask + OpenTelemetry)
from flask import Flask, request
from opentelemetry import trace
from opentelemetry.propagators import extract
from opentelemetry.instrumentation.requests import RequestsInstrumentor
from opentelemetry.propagate import inject
import requests
app = Flask(__name__)
# Enable automatic instrumentation
RequestsInstrumentor().instrument()
@app.route('/api/service-a')
def service_a():
# Extract incoming trace context
ctx = extract(request.headers)
with trace.get_tracer(__name__).start_as_current_span("process-request", context=ctx):
# Business logic
result = do_something()
# Call another service
headers = {}
inject(headers) # Automatically adds traceparent header
response = requests.get(
'http://service-b:8080/api/service-b',
headers=headers
)
return resultGo (Gin + OpenTelemetry)
package main
import (
"context"
"net/http"
"github.com/gin-gonic/gin"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)
func main() {
router := gin.Default()
// Add OpenTelemetry middleware (auto context extraction/propagation)
router.Use(otelgin.Middleware("service-a"))
router.GET("/api/service-a", func(c *gin.Context) {
ctx := c.Request.Context()
// Create child span
_, span := otel.Tracer("service-a").Start(ctx, "process-request")
defer span.End()
// Call another service (auto trace context propagation)
client := http.Client{Transport: otelhttp.NewTransport(http.DefaultTransport)}
req, _ := http.NewRequestWithContext(ctx, "GET", "http://service-b:8080/api/service-b", nil)
resp, _ := client.Do(req)
c.JSON(200, gin.H{"status": "ok"})
})
router.Run(":8080")
}Java (Spring Boot + OpenTelemetry)
@RestController
@RequestMapping("/api")
public class ServiceAController {
@Autowired
private WebClient webClient;
@Autowired
private Tracer tracer;
@GetMapping("/service-a")
public Mono<String> serviceA(@RequestHeader HttpHeaders headers) {
// Spring Boot + OpenTelemetry auto instrumentation automatically extracts and propagates context
Span span = tracer.spanBuilder("process-request")
.setSpanKind(SpanKind.INTERNAL)
.startSpan();
try (Scope scope = span.makeCurrent()) {
// WebClient automatically propagates trace context
return webClient.get()
.uri("http://service-b:8080/api/service-b")
.retrieve()
.bodyToMono(String.class);
} finally {
span.end();
}
}
}Node.js (Express + OpenTelemetry)
const express = require('express');
const { trace, context, propagation } = require('@opentelemetry/api');
const axios = require('axios');
const app = express();
const tracer = trace.getTracer('service-a');
app.get('/api/service-a', async (req, res) => {
// Express instrumentation automatically extracts context
const span = tracer.startSpan('process-request');
try {
await context.with(trace.setSpan(context.active(), span), async () => {
// Automatic trace context propagation on axios calls
const response = await axios.get('http://service-b:8080/api/service-b');
res.json({ result: response.data });
});
} finally {
span.end();
}
});
app.listen(8080);Verificación del contexto de traza
# 1. Verify trace context is included in request headers
kubectl logs -n <namespace> <pod-name> -c istio-proxy --tail=50 | grep -i traceparent
# 2. Check trace ID in Envoy access logs
istioctl proxy-config log <pod-name> -n <namespace> --level debug
kubectl logs -n <namespace> <pod-name> -c istio-proxy | grep "x-b3-traceid"
# 3. Verify trace ID is included in application logs
kubectl logs -n <namespace> <pod-name> -c <container-name>Estrategias de muestreo
Niveles de muestreo
1. Head Sampling (muestreo inicial)
La decisión de muestreo se toma cuando la solicitud entra en el sistema:
Nivel de malla:
apiVersion: v1
kind: ConfigMap
metadata:
name: istio
namespace: istio-system
data:
mesh: |
defaultConfig:
tracing:
sampling: 10.0 # 10% samplingNivel de Namespace:
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: sampling-config
namespace: production
spec:
tracing:
- providers:
- name: otel-tracing
randomSamplingPercentage: 25.0 # 25% samplingNivel de carga de trabajo:
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: critical-service-tracing
namespace: production
spec:
selector:
matchLabels:
app: payment-service
tracing:
- providers:
- name: otel-tracing
randomSamplingPercentage: 100.0 # 100% sampling for critical services2. Tail Sampling (muestreo posterior)
La decisión de muestreo se toma en el Collector después de que se completa la traza:
# OpenTelemetry Collector's tail_sampling processor
processors:
tail_sampling:
decision_wait: 10s # Wait time for trace completion
num_traces: 100000 # Number of traces to keep in memory
expected_new_traces_per_sec: 1000
policies:
# Keep all traces with errors
- name: errors
type: status_code
status_code:
status_codes: [ERROR]
# Keep all slow requests (> 1 second)
- name: slow-traces
type: latency
latency:
threshold_ms: 1000
# 100% sampling for specific services
- name: critical-services
type: string_attribute
string_attribute:
key: service.name
values:
- payment-service
- auth-service
# Keep all HTTP 5xx errors
- name: http-errors
type: numeric_attribute
numeric_attribute:
key: http.status_code
min_value: 500
max_value: 599
# 5% sampling for the rest
- name: probabilistic
type: probabilistic
probabilistic:
sampling_percentage: 5Muestreo adaptativo
Ajuste automáticamente la tasa de muestreo según los patrones de tráfico:
processors:
tail_sampling:
policies:
- name: adaptive-sampling
type: rate_limiting
rate_limiting:
spans_per_second: 1000 # Keep maximum 1000 spans per secondGuía de estrategia de muestreo
| Entorno | Tasa de muestreo recomendada | Estrategia |
|---|---|---|
| Desarrollo | 100% | Head sampling |
| Staging | 50% | Head sampling |
| Producción (tráfico bajo) | 100% | Head sampling |
| Producción (tráfico alto) | 1-10% | Tail sampling |
| Servicios críticos | 100% | Tail sampling (conservar todos los errores/solicitudes lentas) |
Análisis de trazas
Búsqueda de trazas en la UI de Jaeger
# Access Jaeger UI
kubectl port-forward -n observability svc/jaeger-query 16686:16686
# Browser: http://localhost:16686Opciones de búsqueda:
- Servicio: Nombre del Service
- Operación: Nombre de la operación (p. ej.,
GET /api/products) - Etiquetas: Filtro de etiquetas (p. ej.,
http.status_code=500) - Duración mínima: Latencia mínima
- Duración máxima: Latencia máxima
- Limitar resultados: Límite de cantidad de resultados
Consultas de trazas útiles
1. Buscar trazas con errores
Tags: error=trueO
Tags: http.status_code=5002. Buscar solicitudes lentas
Min Duration: 1s3. Rastrear solicitudes de usuarios específicos
Tags: user.id=123454. Analizar endpoints de API específicos
Operation: GET /api/products/{id}Análisis programático mediante Jaeger API
# Query traces for a specific service
curl "http://jaeger-query:16686/api/traces?service=productpage&limit=10"
# Query specific trace ID
curl "http://jaeger-query:16686/api/traces/0af7651916cd43dd8448eb211c80319c"
# Query service list
curl "http://jaeger-query:16686/api/services"
# Query operations for a specific service
curl "http://jaeger-query:16686/api/services/productpage/operations"Identificación de cuellos de botella de latencia
- Busque el Span más largo en la vista Waterfall
- Revise la ruta crítica: La ruta que más afecta al tiempo total de solicitud
- Ejecución paralela frente a secuencial: Compruebe si las tareas que podrían ejecutarse en paralelo se ejecutan secuencialmente
Integración con Grafana Tempo
apiVersion: v1
kind: ConfigMap
metadata:
name: grafana-datasources
namespace: observability
data:
tempo.yaml: |
apiVersion: 1
datasources:
- name: Tempo
type: tempo
access: proxy
url: http://tempo:3100
jsonData:
tracesToLogs:
datasourceUid: 'loki'
tags: ['job', 'instance', 'pod', 'namespace']
mappedTags: [{ key: 'service.name', value: 'service' }]
tracesToMetrics:
datasourceUid: 'prometheus'
tags: [{ key: 'service.name', value: 'service' }]
queries:
- name: 'Request rate'
query: 'sum(rate(istio_requests_total{$__tags}[5m]))'
serviceMap:
datasourceUid: 'prometheus'
search:
hide: false
nodeGraph:
enabled: trueAdición de Spans personalizados
Agregue Spans personalizados en el código de la aplicación para obtener un trazado más detallado.
Ejemplo de Python
from opentelemetry import trace
tracer = trace.get_tracer(__name__)
def process_order(order_id):
with tracer.start_as_current_span("process-order") as span:
span.set_attribute("order.id", order_id)
span.set_attribute("order.amount", 99.99)
# Check inventory
with tracer.start_as_current_span("check-inventory"):
inventory = check_inventory(order_id)
span.set_attribute("inventory.available", inventory)
# Process payment
with tracer.start_as_current_span("process-payment") as payment_span:
try:
payment_result = process_payment(order_id)
payment_span.set_attribute("payment.status", "success")
except PaymentError as e:
payment_span.set_status(Status(StatusCode.ERROR))
payment_span.record_exception(e)
raise
# Record event
span.add_event("Order processed successfully", {
"order.id": order_id,
"timestamp": time.time()
})
return {"status": "success"}Ejemplo de Go
import (
"context"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
)
func processOrder(ctx context.Context, orderID string) error {
tracer := otel.Tracer("order-service")
ctx, span := tracer.Start(ctx, "process-order")
defer span.End()
span.SetAttributes(
attribute.String("order.id", orderID),
attribute.Float64("order.amount", 99.99),
)
// Check inventory
ctx, inventorySpan := tracer.Start(ctx, "check-inventory")
inventory, err := checkInventory(ctx, orderID)
if err != nil {
inventorySpan.RecordError(err)
inventorySpan.SetStatus(codes.Error, err.Error())
inventorySpan.End()
return err
}
inventorySpan.SetAttributes(attribute.Bool("inventory.available", inventory))
inventorySpan.End()
// Process payment
ctx, paymentSpan := tracer.Start(ctx, "process-payment")
err = processPayment(ctx, orderID)
if err != nil {
paymentSpan.RecordError(err)
paymentSpan.SetStatus(codes.Error, err.Error())
paymentSpan.End()
return err
}
paymentSpan.SetAttributes(attribute.String("payment.status", "success"))
paymentSpan.End()
// Record event
span.AddEvent("Order processed successfully")
return nil
}Optimización del rendimiento
Optimización del tamaño de los datos de trazas
apiVersion: v1
kind: ConfigMap
metadata:
name: istio
namespace: istio-system
data:
mesh: |
defaultConfig:
tracing:
sampling: 10.0
max_path_tag_length: 256 # Limit URL path length
custom_tags:
# Add only necessary tags
cluster_id:
literal:
value: "prod"Ajuste del rendimiento del Collector
processors:
batch:
timeout: 10s
send_batch_size: 1024
send_batch_max_size: 2048
memory_limiter:
check_interval: 1s
limit_mib: 2048
spike_limit_mib: 512Optimización del almacenamiento
Gestión de índices de Elasticsearch
# Delete old indices (using Curator)
curator --config curator.yml delete_indices.yml# delete_indices.yml
actions:
1:
action: delete_indices
description: Delete jaeger indices older than 7 days
options:
ignore_empty_list: True
disable_action: False
filters:
- filtertype: pattern
kind: prefix
value: jaeger-span-
- filtertype: age
source: name
direction: older
timestring: '%Y-%m-%d'
unit: days
unit_count: 7Solución de problemas
Cuando las trazas no son visibles
1. Compruebe si Envoy genera trazas
# Check Envoy access logs
kubectl logs -n <namespace> <pod-name> -c istio-proxy | grep -i trace
# Check tracing in Envoy config
istioctl proxy-config bootstrap <pod-name> -n <namespace> -o json | jq '.bootstrap.tracing'2. Compruebe si el Collector recibe trazas
# Check Collector logs
kubectl logs -n observability deployment/otel-collector
# Check Collector metrics
kubectl port-forward -n observability svc/otel-collector 8888:8888
curl http://localhost:8888/metrics | grep otelcol_receiver_accepted_spans3. Compruebe si las trazas se almacenan en Jaeger/Zipkin
# Check Jaeger storage
kubectl logs -n observability deployment/jaeger-query
# Check Elasticsearch indices
curl -X GET "elasticsearch:9200/_cat/indices/jaeger-*?v"Cuando el contexto de traza no se propaga
# 1. Check headers in application logs
kubectl logs -n <namespace> <pod-name> -c <container> | grep -i "traceparent\|x-b3"
# 2. Enable Envoy access log
kubectl exec -n <namespace> <pod-name> -c istio-proxy -- \
curl -X POST http://localhost:15000/logging?level=debug
# 3. Test for header propagation verification
kubectl run -it --rm debug --image=curlimages/curl --restart=Never -- \
curl -H "traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01" \
http://service-a:8080/api/testCuando no se aplica la tasa de muestreo
# 1. Check Telemetry resources
kubectl get telemetry -A
# 2. Check Telemetry configuration details
kubectl describe telemetry <name> -n <namespace>
# 3. Check if reflected in Envoy config
istioctl proxy-config bootstrap <pod-name> -n <namespace> -o json | \
jq '.bootstrap.tracing.http.config.sampling'