- Authors

- Name
- Phillip Pham
- @ddppham
Kubernetes Adapter Pattern: Legacy-Systeme ohne Code-Aenderungen integrieren
TL;DR
- Das Adapter Pattern setzt einen Sidecar-Container ein, der Protokolle und Datenformate zwischen inkompatiblen Services uebersetzt
- Typische Einsatzfelder: REST-zu-gRPC-Konvertierung, XML-zu-JSON-Transformation, SOAP-Anbindung an moderne APIs
- Implementierung als Sidecar (pro Pod) oder als dedizierter Proxy-Service (zentral fuer mehrere Consumer)
- Der Hauptcontainer bleibt komplett unveraendert -- kein Refactoring noetig
- Latenz-Overhead liegt typischerweise unter 2ms pro Hop bei effizienter Implementierung in Go oder Rust
Worum geht es?
In fast jeder gewachsenen IT-Landschaft existieren Systeme, die unterschiedliche Protokolle oder Datenformate sprechen. Ein ERP-System liefert SOAP/XML, die neue Analyseplattform erwartet REST/JSON, und die Produktionsmaschinen senden Modbus-TCP. Diese Systeme komplett neu zu schreiben ist unrealistisch. Punkt-zu-Punkt-Integrationen skalieren nicht.
Das Adapter Pattern loest genau dieses Problem. Ein zwischengeschalteter Container uebernimmt die Uebersetzung, ohne dass der urspruengliche Service veraendert werden muss. In Kubernetes laesst sich das elegant als Sidecar-Container im selben Pod realisieren.
Adapter-Typen im Ueberblick
| Adapter-Typ | Aufgabe | Beispiel |
|---|---|---|
| Protokoll-Adapter | Kommunikationsprotokoll konvertieren | REST zu gRPC, MQTT zu Kafka, SOAP zu REST |
| Format-Adapter | Datenformat transformieren | XML zu JSON, CSV zu Protobuf, proprietaer zu OpenAPI |
| Auth-Adapter | Authentifizierung uebersetzen | OAuth2 zu API-Key, mTLS zu Basic Auth |
| Filter-Adapter | Daten selektieren und reduzieren | Nur relevante Felder weiterleiten, PII entfernen |
Implementierung als Sidecar
Die gaengigste Variante: Der Adapter laeuft als zweiter Container im selben Pod. Der Hauptcontainer kommuniziert ueber localhost mit dem Adapter. Der Adapter uebersetzt und leitet an das Zielsystem weiter.
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 2
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: order-service
image: registry.internal/order-service:2.4.1
ports:
- containerPort: 8080
env:
- name: ERP_ENDPOINT
# Service spricht mit dem lokalen Adapter statt direkt mit dem ERP
value: "http://localhost:9000/api/orders"
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
- name: soap-adapter
image: registry.internal/soap-json-adapter:1.1.0
ports:
- containerPort: 9000
env:
- name: TARGET_WSDL
value: "https://erp.internal.corp/OrderService?wsdl"
- name: LISTEN_PORT
value: "9000"
- name: LOG_LEVEL
value: "info"
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 250m
memory: 256Mi
livenessProbe:
httpGet:
path: /healthz
port: 9000
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /readyz
port: 9000
initialDelaySeconds: 3
periodSeconds: 5
Der order-service schickt normale REST-Requests an localhost:9000. Der soap-adapter uebersetzt diese in SOAP-Calls gegen das ERP-System. Fuer den order-service sieht es so aus, als spreche er mit einer REST-API.
Wichtig: Beide Container teilen sich das Netzwerk-Namespace im Pod. Deshalb funktioniert die Kommunikation ueber localhost ohne Service-Discovery.
Implementierung als dedizierter Proxy-Service
Wenn mehrere Services denselben Legacy-Endpunkt ansprechen, lohnt sich ein zentraler Adapter als eigenstaendiges Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: erp-adapter
namespace: integration
spec:
replicas: 3
selector:
matchLabels:
app: erp-adapter
template:
metadata:
labels:
app: erp-adapter
spec:
containers:
- name: erp-adapter
image: registry.internal/erp-adapter:2.0.0
ports:
- containerPort: 8080
env:
- name: ERP_HOST
value: "https://erp.internal.corp"
- name: CACHE_TTL
value: "60s"
- name: MAX_CONCURRENT
value: "50"
---
apiVersion: v1
kind: Service
metadata:
name: erp-adapter
namespace: integration
spec:
selector:
app: erp-adapter
ports:
- port: 80
targetPort: 8080
Andere Services im Cluster sprechen dann http://erp-adapter.integration.svc.cluster.local an und erhalten eine saubere REST/JSON-Schnittstelle.
Sidecar vs. Proxy: Wann welchen Ansatz?
| Kriterium | Sidecar | Dedizierter Proxy |
|---|---|---|
| Anzahl Consumer | 1 Service | Mehrere Services |
| Latenz | Minimal (localhost) | Etwas hoeher (Netzwerk-Hop) |
| Ressourcen-Overhead | Pro Pod dupliziert | Einmalig zentral |
| Fehler-Isolation | Gut, auf Pod beschraenkt | Single Point of Failure moeglich |
| Skalierung | Skaliert mit dem Service | Unabhaengig skalierbar |
| Konfiguration | Pro Deployment individuell | Zentral verwaltbar |
Fuer die meisten Faelle empfehle ich den Sidecar-Ansatz, wenn nur ein Consumer existiert, und den Proxy-Ansatz, wenn drei oder mehr Services denselben Adapter benoetigen.
Einen minimalen Adapter in Go schreiben
Ein einfacher HTTP-zu-gRPC-Adapter laesst sich in Go mit wenigen hundert Zeilen bauen. Hier die Grundstruktur:
# Projektstruktur initialisieren
mkdir -p erp-adapter/cmd erp-adapter/internal/converter
cd erp-adapter
# Go Modul initialisieren
go mod init github.com/your-org/erp-adapter
# Abhaengigkeiten
go get google.golang.org/grpc
go get github.com/gorilla/mux
# Build fuer Container
CGO_ENABLED=0 GOOS=linux go build -o /bin/adapter ./cmd/main.go
# Multi-Stage Dockerfile
cat <<'DOCKERFILE'
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /bin/adapter ./cmd/main.go
FROM gcr.io/distroless/static:nonroot
COPY --from=builder /bin/adapter /adapter
ENTRYPOINT ["/adapter"]
DOCKERFILE
Die Verwendung von Distroless-Images ist hier bewusst gewaehlt. Weniger Angriffsoberflaeche, kleines Image, kein Shell-Zugriff im Container. Genau das, was man fuer einen Infrastruktur-Adapter will.
Monitoring und Observability
Ein Adapter ohne Monitoring ist ein blindes Stueck Infrastruktur. Drei Metriken sollte jeder Adapter mindestens exponieren:
- Request-Latenz (Histogram): Wie lange dauert die Uebersetzung plus der Aufruf zum Zielsystem?
- Fehlerrate (Counter): Wie viele Requests scheitern bei der Konvertierung oder am Zielsystem?
- Durchsatz (Counter): Wie viele Requests verarbeitet der Adapter pro Sekunde?
Prometheus-Metriken lassen sich in Go mit dem prometheus/client_golang Package in wenigen Zeilen einbauen. Ein ServiceMonitor fuer Prometheus Operator sieht so aus:
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: erp-adapter
namespace: integration
spec:
selector:
matchLabels:
app: erp-adapter
endpoints:
- port: metrics
interval: 15s
path: /metrics
Wer den Monitoring-Stack noch nicht aufgesetzt hat, findet eine Anleitung in unserem Beitrag zu Kubernetes Monitoring mit Open-Source-Tools.
Fehlerbehandlung und Resilienz
Adapter muessen robust mit Ausfaellen des Zielsystems umgehen. Folgende Patterns sind Pflicht:
Circuit Breaker: Wenn das Zielsystem nicht antwortet, schaltet der Adapter nach einer konfigurierbaren Anzahl von Fehlern in den Open-State und gibt sofort einen Fehler zurueck, statt weiter Last auf das kaputte System zu schicken.
Retry mit Exponential Backoff: Transiente Fehler (Timeouts, 503er) werden automatisch wiederholt, mit steigendem Abstand zwischen den Versuchen. Maximal 3 Retries, danach Fehler an den Client zurueck.
Timeout: Jeder Request an das Zielsystem bekommt ein striktes Timeout. 5 Sekunden ist ein guter Startwert. Besser ein schneller Fehler als ein haengender Request.
Health Checks: Liveness- und Readiness-Probes sind nicht optional. Kubernetes muss wissen, ob der Adapter noch funktioniert. Die Readiness-Probe sollte die Erreichbarkeit des Zielsystems mit einbeziehen.
Typische Stolperfallen
Shared Lifecycle: Sidecar und Hauptcontainer starten und stoppen nicht immer synchron. Seit Kubernetes 1.28 gibt es native Sidecar-Container (initContainers mit restartPolicy: Always), die vor dem Hauptcontainer starten und nach ihm stoppen. Das loest viele Race Conditions.
Resource Limits vergessen: Der Adapter braucht eigene Resource Requests und Limits. Ohne diese wird er bei Ressourcenknappheit als erster vom Scheduler gekillt.
Logging-Konsistenz: Adapter-Logs sollten eine Correlation-ID aus dem eingehenden Request uebernehmen, damit man im Fehlerfall die gesamte Kette nachverfolgen kann.
Wann das Adapter Pattern nicht passt
Das Pattern ist kein Allheilmittel. In folgenden Situationen gibt es bessere Alternativen:
- Komplexe Geschaeftslogik noetig: Wenn zwischen den Systemen nicht nur uebersetzt, sondern auch transformiert, aggregiert und orchestriert werden muss, ist ein vollstaendiger Integration-Service oder ein Event-driven Ansatz mit Kafka besser geeignet.
- Hoher Durchsatz bei minimaler Latenz: Bei Sub-Millisekunden-Anforderungen ist jeder zusaetzliche Hop zu viel. Hier lieber die Services direkt kompatibel machen.
- Einmalige Migration: Wenn das Legacy-System in 6 Monaten abgeloest wird, lohnt der Aufwand fuer einen produktionsreifen Adapter nicht. Ein einfaches Skript fuer die Uebergangszeit reicht.
Fuer eine breitere Uebersicht zu Kubernetes Design Patterns empfehle ich den Beitrag zu Kubernetes Production Cluster Setup.
Zusammenfassung
Das Adapter Pattern ist eines der nuetzlichsten Patterns fuer Kubernetes-Umgebungen mit gewachsener Infrastruktur. Es entkoppelt Legacy-Systeme von modernen Services, ohne dass bestehender Code angefasst werden muss. Die Implementierung als Sidecar oder zentraler Proxy ist mit Kubernetes-Bordmitteln moeglich und laesst sich sauber in bestehende CI/CD-Pipelines einbinden.
Wer seine Kubernetes-Deployments absichern moechte, findet im Beitrag zu Kubernetes Security Hardening weiterfuehrende Informationen. Fuer die Automatisierung von Security Scans in der Pipeline lohnt sich ein Blick auf Security Scanning in Kubernetes.
Wenn Sie Unterstuetzung bei der Integration von Legacy-Systemen in Ihre Kubernetes-Umgebung brauchen, sprechen Sie uns an unter /kontakt.
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
Ambassador Pattern in Kubernetes: Envoy als Sidecar-Proxy
Das Ambassador Pattern in Kubernetes erklärt: Envoy als Sidecar-Proxy für TLS-Termination, Retry-Logik und Routing mit YAML-Beispielen.
Dapr auf Kubernetes: Sidecar-Pattern für Microservices
Dapr auf Kubernetes einrichten: Building Blocks für Service Invocation, State Management, Pub/Sub und Secrets mit produktionsreifen YAML-Beispielen.
Kubernetes Sidecar Pattern: Multi-Container Pods erklärt
Sidecar Pattern in Kubernetes mit YAML-Beispielen: Logging, Monitoring und Security-Sidecars konfigurieren und native Sidecar Containers ab v1.28 nutzen.
Kubernetes in Deutschland: ChromaDB Vector-Store für schnelle KI-Prototypen
ChromaDB Vector-Store für KI-Prototypen auf Kubernetes in Deutschland? Erfahren Sie, wie der deutsche Mittelstand agile RAG-Anwendungen kostengünstig implementiert und dabei bestehende Kubernetes-Ressourcen optimal nutzt.
Kubernetes Zertifizierung im Lebenslauf richtig platzieren
Steigere deine Karrierechancen im deutschen Mittelstand! Erfahre, wie du deine Kubernetes-Zertifikate (CKA, CKAD, CKS) strategisch im Lebenslauf und auf LinkedIn positionierst, um Recruiter von deiner Cloud-Native-Expertise und deinem Praxisbezug zu überzeugen.