Veröffentlicht am

Distributed Tracing: Jaeger auf Kubernetes einrichten

Teilen:
Authors

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.

AnalysezielVorgehen in Jaeger
Langsamster Service findenSearch mit min Duration, Trace-Detail prüfen
N+1 Query-Problem erkennenTrace mit vielen DB-Spans gleichen Typs
Timeout-Ursache lokalisierenSpan mit höchster Duration im Trace
Error-Rate pro ServiceService 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

kubernetesobservability

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.

Weiterlesen →