- Authors

- Name
- Phillip Pham
- @ddppham
Distributed Tracing: Jaeger auf Kubernetes einrichten
TL;DR
Jaeger visualisiert den Weg eines Requests durch alle beteiligten Microservices als Trace mit Spans. Der Jaeger Operator vereinfacht das Deployment auf Kubernetes. OpenTelemetry liefert die standardisierte Instrumentation -- SDKs für Go, Python, Java und weitere Sprachen senden Spans automatisch an den Jaeger Collector. Trace-Context wird per W3C-Header zwischen Services propagiert.
Warum Distributed Tracing?
Ein Request an /api/orders durchläuft den API-Gateway, den Order-Service, den Payment-Service und die Datenbank. Wenn die Antwort 3 Sekunden dauert, zeigen Logs nur isolierte Einträge pro Service. Tracing zeigt den gesamten Pfad:
[Trace: abc123]
├── API-Gateway 12ms
├── Order-Service 145ms
│ ├── DB Query 38ms
│ └── Payment-Service 2.8s ← Engpass
│ └── Stripe API 2.7s
└── Total 3.1s
Ohne Tracing bleiben solche Latenzketten unsichtbar. Besonders in Kubernetes-Umgebungen mit 20+ Services und dynamischen Pod-IPs ist manuelles Korrelieren von Logs nicht praktikabel.
Jaeger Operator installieren
Der Operator verwaltet Jaeger-Instanzen als Custom Resources. Zuerst cert-manager (falls nicht vorhanden), dann den Operator:
# cert-manager installieren (Voraussetzung)
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.0/cert-manager.yaml
# Jaeger Operator via Helm
helm repo add jaegertracing https://jaegertracing.github.io/helm-charts
helm repo update
helm install jaeger-operator jaegertracing/jaeger-operator \
--namespace observability --create-namespace \
--set rbac.clusterRole=true
Danach eine Jaeger-Instanz als Custom Resource deployen:
# jaeger-instance.yaml
apiVersion: jaegertracing.io/v1
kind: Jaeger
metadata:
name: jaeger-production
namespace: observability
spec:
strategy: production
collector:
replicas: 2
resources:
requests:
cpu: 500m
memory: 512Mi
storage:
type: elasticsearch
options:
es:
server-urls: http://elasticsearch.observability:9200
index-prefix: jaeger
esIndexCleaner:
enabled: true
numberOfDays: 14
schedule: "55 23 * * *"
query:
replicas: 1
ingress:
enabled: true
kubectl apply -f jaeger-instance.yaml
Der Operator erstellt automatisch Collector, Query-Service und UI. Die production-Strategie nutzt Elasticsearch als Backend -- für Entwicklungsumgebungen reicht allInOne mit In-Memory-Speicher.
OpenTelemetry Instrumentation
OpenTelemetry ist der CNCF-Standard für Telemetriedaten. Die SDKs instrumentieren den Code und senden Spans an den Jaeger Collector per OTLP (OpenTelemetry Protocol).
Python-Beispiel (Flask)
# app.py
from flask import Flask, request
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from opentelemetry.instrumentation.requests import RequestsInstrumentor
# Tracer konfigurieren
provider = TracerProvider()
otlp_exporter = OTLPSpanExporter(
endpoint="jaeger-production-collector.observability:4317",
insecure=True
)
provider.add_span_processor(BatchSpanProcessor(otlp_exporter))
trace.set_tracer_provider(provider)
app = Flask(__name__)
FlaskInstrumentor().instrument_app(app)
RequestsInstrumentor().instrument()
tracer = trace.get_tracer("order-service")
@app.route("/orders", methods=["POST"])
def create_order():
with tracer.start_as_current_span("validate_order") as span:
order_data = request.json
span.set_attribute("order.item_count", len(order_data.get("items", [])))
# Ausgehender Request -- Trace-Context wird automatisch propagiert
import requests
payment = requests.post("http://payment-service:8080/charge",
json={"amount": order_data["total"]})
return {"status": "created", "payment": payment.json()}
Die Auto-Instrumentation (FlaskInstrumentor, RequestsInstrumentor) erzeugt Spans für eingehende und ausgehende HTTP-Requests automatisch. Der W3C traceparent-Header wird bei ausgehenden Requests mitgesendet.
Go-Beispiel
package main
import (
"context"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/sdk/trace"
"net/http"
)
func initTracer() (*trace.TracerProvider, error) {
exporter, err := otlptracegrpc.New(context.Background(),
otlptracegrpc.WithEndpoint("jaeger-production-collector.observability:4317"),
otlptracegrpc.WithInsecure(),
)
if err != nil {
return nil, err
}
tp := trace.NewTracerProvider(trace.WithBatcher(exporter))
otel.SetTracerProvider(tp)
return tp, nil
}
func handleOrder(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
tracer := otel.Tracer("order-service")
ctx, span := tracer.Start(ctx, "process_order")
defer span.End()
// DB-Abfrage als Child-Span
_, dbSpan := tracer.Start(ctx, "db_query")
// ... Datenbankabfrage
dbSpan.End()
w.WriteHeader(http.StatusCreated)
}
Trace-Propagation zwischen Services
Damit ein Trace über Service-Grenzen hinweg zusammenhängend bleibt, muss der Trace-Context weitergegeben werden. OpenTelemetry nutzt dafür den W3C traceparent-Header:
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
│ │ │ │
│ │ │ └─ Flags (sampled)
│ │ └─ Parent-Span-ID
│ └─ Trace-ID (128-bit)
└─ Version
In Kubernetes mit Service Mesh (Istio, Linkerd) wird der Header automatisch propagiert. Ohne Service Mesh muss die Applikation den Header aus dem eingehenden Request extrahieren und bei ausgehenden Requests mitsenden. Die OpenTelemetry-SDKs erledigen das bei instrumentierten HTTP-Clients automatisch.
Kubernetes Deployment mit OTEL-Umgebungsvariablen
# order-service-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 3
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: order-service
image: registry.example.com/order-service:v2.1.0
env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "http://jaeger-production-collector.observability:4317"
- name: OTEL_SERVICE_NAME
value: "order-service"
- name: OTEL_RESOURCE_ATTRIBUTES
value: "k8s.namespace=production,k8s.deployment=order-service"
ports:
- containerPort: 8080
Die Umgebungsvariablen OTEL_EXPORTER_OTLP_ENDPOINT und OTEL_SERVICE_NAME werden von allen OpenTelemetry-SDKs automatisch ausgelesen -- kein Hardcoding im Applikationscode nötig.
Traces analysieren: Latenz-Probleme finden
Die Jaeger-UI (erreichbar über den Query-Service) bietet drei zentrale Ansichten:
Search: Traces nach Service, Operation, Duration und Tags filtern. Beispiel: Alle Traces des order-service mit Duration > 2s der letzten Stunde.
Trace Detail: Wasserfall-Darstellung aller Spans eines Traces. Jeder Balken zeigt die Dauer eines Spans. Lücken zwischen Spans deuten auf Netzwerk-Latenz oder fehlende Instrumentation hin.
Compare: Zwei Traces nebeneinander vergleichen -- schneller Request vs. langsamer Request. Sofort sichtbar, welcher Span den Unterschied ausmacht.
| Analyseziel | Vorgehen in Jaeger |
|---|---|
| Langsamster Service finden | Search mit min Duration, Trace-Detail prüfen |
| N+1 Query-Problem erkennen | Trace mit vielen DB-Spans gleichen Typs |
| Timeout-Ursache lokalisieren | Span mit höchster Duration im Trace |
| Error-Rate pro Service | Service Dependencies Graph |
Sampling-Strategien
Bei hohem Traffic alle Requests zu tracen ist nicht sinnvoll. Jaeger unterstützt drei Sampling-Strategien:
# Im Jaeger Custom Resource
spec:
sampling:
options:
default_strategy:
type: probabilistic
param: 0.1 # 10% aller Requests
per_operation_strategies:
- operation: "/api/orders"
type: probabilistic
param: 0.5 # 50% fuer kritische Endpoints
- operation: "/health"
type: probabilistic
param: 0.001 # Health-Checks fast nie
Für Produktionsumgebungen empfiehlt sich Adaptive Sampling: Jaeger passt die Rate automatisch an, sodass sowohl häufige als auch seltene Operationen ausreichend repräsentiert sind.
FAQ
Wie viel Overhead erzeugt Tracing?
Die OpenTelemetry-SDKs nutzen asynchrones Batching. Der CPU-Overhead liegt typisch bei 1-3%, der Speicher-Overhead bei 10-30 MB pro Pod. Bei 10% Sampling-Rate ist der Netzwerk-Overhead vernachlässigbar.
Jaeger oder Grafana Tempo?
Jaeger hat die ausgereiftere UI und ist der CNCF-Graduated-Standard. Tempo speichert Traces in Object Storage (günstiger bei grossen Volumen) und integriert sich nahtlos mit Grafana, Loki und Prometheus. Wer bereits den Grafana-Stack nutzt, fährt mit Tempo besser.
Funktioniert Tracing mit gRPC?
Ja. OpenTelemetry bietet Auto-Instrumentation für gRPC in Go, Java und Python. Der Trace-Context wird über gRPC-Metadata propagiert, analog zum HTTP-Header.
Wie korreliere ich Traces mit Logs?
Die Trace-ID in den Log-Output schreiben. In Python: logging.info("order created", extra={"trace_id": span.get_span_context().trace_id}). In Grafana lassen sich Loki-Logs und Jaeger-Traces dann per Trace-ID verlinken.
Brauche ich ein Service Mesh für Tracing?
Nein. OpenTelemetry-SDKs funktionieren ohne Service Mesh. Ein Mesh wie Istio kann zusätzliche Netzwerk-Spans erzeugen (L7 Proxy), ersetzt aber nicht die Applikations-Instrumentation für Business-relevante Spans.
Kubernetes-Expertise gesucht?
Managed Services, Beratung, Training oder Security – wir unterstützen deutsche Unternehmen bei allen Kubernetes-Themen.
Kubernetes-Beratung gesucht?
Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.
📖 Verwandte Artikel
Weitere interessante Beiträge zu ähnlichen Themen
OpenTelemetry auf Kubernetes: Observability-Stack
OpenTelemetry auf Kubernetes einrichten: OTel Collector als DaemonSet, Auto-Instrumentation per Operator und herstellerunabhängige Pipelines.
OpenTelemetry auf Kubernetes: Observability DSGVO-konform
OpenTelemetry auf Kubernetes einrichten und DSGVO-konform betreiben. Metriken, Traces und Logs mit Prometheus, Jaeger und Grafana im deutschen Rechenzentrum.
Kubernetes CQRS Pattern Microservices in Deutschland optimal nutzen
Optimieren Sie Skalierbarkeit und Performance Ihrer komplexen Microservices auf Kubernetes in Deutschland mit dem CQRS Pattern. Erfahren Sie, wie diese zukunftsweisende Architektur Compliance-Anforderungen erfüllt und digitale Souveränität für deutsche Unternehmen sichert.
Prometheus PCA Zertifizierung für Kubernetes Monitoring
Die Prometheus Certified Associate (PCA) Zertifizierung bietet eine fundierte Validierung von Kubernetes Monitoring-Kenntnissen mit Prometheus. Erfahren Sie, wie diese offizielle CNCF-Zertifizierung deutschen Unternehmen hilft, ihre Observability-Strategien zu professionalisieren und die Betriebsstabilität ihrer Cloud-nativen Infrastrukturen zu gewährleisten – essenziell für ein zuverlässiges Kubernetes Monitoring in Deutschland.
Kubernetes Alerting: Prometheus-Regeln richtig setzen
Prometheus Alerting für Kubernetes richtig aufbauen: Alert-Hierarchie, symptombasierte Regeln und Routing zu Slack oder PagerDuty ohne Alert Fatigue.