- Authors

- Name
- Phillip Pham
- @ddppham
Kubernetes Service Discovery: DNS, Headless Services und Service Mesh im Vergleich
TL;DR
- Kubernetes nutzt CoreDNS als Standard-Mechanismus: Jeder Service bekommt einen DNS-Eintrag unter
<name>.<namespace>.svc.cluster.local. - ClusterIP ist der Default-Service-Typ und reicht fuer 90% aller internen Kommunikation aus.
- Headless Services (clusterIP: None) liefern direkte Pod-IPs zurueck -- notwendig fuer StatefulSets und Datenbank-Cluster.
- Ein Service Mesh (Istio, Linkerd) lohnt sich erst ab ca. 20+ Microservices mit Anforderungen an mTLS, Traffic Splitting oder detailliertes Tracing.
- Umgebungsvariablen fuer Service Discovery sind ein Legacy-Mechanismus -- bei neuen Projekten ausschliesslich DNS verwenden.
Wie Service Discovery in Kubernetes funktioniert
Wenn ein Pod mit einem anderen Service kommunizieren will, braucht er dessen Adresse. In einer dynamischen Umgebung, in der Pods staendig neu erstellt und zerstoert werden, sind statische IPs keine Option. Kubernetes loest das mit Service-Objekten und DNS.
Jeder Kubernetes-Cluster betreibt CoreDNS als Cluster-internen DNS-Server. Sobald ein Service-Objekt erstellt wird, registriert CoreDNS automatisch einen DNS-Eintrag. Pods koennen den Service dann ueber seinen Namen ansprechen, ohne die tatsaechlichen Pod-IPs zu kennen.
Die DNS-Aufloesung folgt einem klaren Schema:
# Innerhalb des gleichen Namespace
<service-name>
# Namespace-uebergreifend
<service-name>.<namespace>
# Vollqualifiziert (FQDN)
<service-name>.<namespace>.svc.cluster.local
Das ist im Grunde alles. Kein Framework noetig, keine externe Registry -- CoreDNS erledigt das out of the box.
ClusterIP Service: Der Standardfall
Der ClusterIP-Service ist der Default und deckt die meisten Anwendungsfaelle ab. Kubernetes weist dem Service eine virtuelle IP zu, die sich waehrend der gesamten Lebensdauer des Service nicht aendert. Der kube-proxy auf jedem Node sorgt fuer die Weiterleitung an die dahinterliegenden Pods.
apiVersion: v1
kind: Service
metadata:
name: order-api
namespace: production
spec:
selector:
app: order-api
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP
Ein anderer Pod im gleichen Namespace kann diesen Service so erreichen:
curl http://order-api/v1/orders
Aus einem anderen Namespace heraus:
curl http://order-api.production/v1/orders
Die Lastverteilung uebernimmt kube-proxy per iptables- oder IPVS-Regeln. Das ist kein intelligentes Load Balancing (kein Least-Connections, kein Health-basiertes Routing), aber es funktioniert zuverlaessig fuer die meisten Workloads.
Headless Services: Wenn Sie direkte Pod-IPs brauchen
Fuer bestimmte Workloads reicht ein ClusterIP nicht aus. Datenbank-Cluster, Message Queues oder andere StatefulSets muessen gezielt einzelne Pods ansprechen koennen. Dafuer gibt es Headless Services.
apiVersion: v1
kind: Service
metadata:
name: postgres
namespace: production
spec:
clusterIP: None
selector:
app: postgres
ports:
- port: 5432
Der entscheidende Unterschied: clusterIP: None. Statt einer einzelnen virtuellen IP liefert DNS jetzt die IPs aller dahinterliegenden Pods zurueck. In Kombination mit einem StatefulSet bekommt jeder Pod einen stabilen DNS-Eintrag:
postgres-0.postgres.production.svc.cluster.local
postgres-1.postgres.production.svc.cluster.local
postgres-2.postgres.production.svc.cluster.local
Das ist essenziell fuer Anwendungen, die Leader-Election oder Replikation zwischen bekannten Nodes durchfuehren muessen.
ClusterIP vs. Headless Service im Vergleich
| Eigenschaft | ClusterIP Service | Headless Service |
|---|---|---|
| Virtuelle IP | Ja (stabil) | Nein |
| DNS-Antwort | Eine IP (ClusterIP) | Alle Pod-IPs |
| Load Balancing | Automatisch via kube-proxy | Muss die Anwendung selbst machen |
| Typischer Einsatz | Stateless APIs, Web-Frontends | StatefulSets, DB-Cluster |
| Pod-spezifisches DNS | Nein | Ja (mit StatefulSet) |
| Komplexitaet | Gering | Mittel |
ExternalName: Externe Dienste intern verfuegbar machen
Wenn ein Microservice auf eine externe Datenbank oder SaaS-API zugreifen muss, koennen Sie einen ExternalName-Service erstellen. Das gibt Ihnen einen internen DNS-Alias:
apiVersion: v1
kind: Service
metadata:
name: external-db
namespace: production
spec:
type: ExternalName
externalName: db.example.eu-central-1.rds.amazonaws.com
Pods koennen jetzt external-db als Hostnamen verwenden. Der Vorteil: Wenn sich der externe Endpunkt aendert, muessen Sie nur das Service-Objekt aktualisieren, nicht jede einzelne Anwendungskonfiguration.
CoreDNS Debugging: Wenn die Aufloesung nicht funktioniert
Bevor Sie an der Anwendung suchen, pruefen Sie immer zuerst, ob DNS korrekt funktioniert. Dafuer starten Sie einen Debug-Pod:
# DNS-Aufloesung testen
kubectl run dns-debug --rm -it --image=busybox:1.36 --restart=Never -- nslookup order-api.production.svc.cluster.local
# CoreDNS-Pods pruefen
kubectl get pods -n kube-system -l k8s-app=kube-dns
# CoreDNS-Logs bei Problemen
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50
# DNS-Policy eines Pods pruefen
kubectl get pod <pod-name> -o yaml | grep -A5 dnsPolicy
Typische DNS-Probleme und ihre Ursachen:
| Symptom | Wahrscheinliche Ursache | Loesung |
|---|---|---|
NXDOMAIN | Service existiert nicht oder falscher Namespace | kubectl get svc -A pruefen |
| Timeout | CoreDNS-Pod nicht gesund oder NetworkPolicy blockt | CoreDNS-Pods und Logs pruefen |
| Falsche IP | Veralteter DNS-Cache | Pod neu starten, ndots pruefen |
| Langsame Aufloesung | Zu hoher ndots-Wert | ndots: 2 in dnsConfig setzen |
Ein haeufiges Performance-Problem: Die Default-ndots: 5 Einstellung fuehrt dazu, dass jede DNS-Anfrage zuerst mehrere Suchdomaenen durchprobiert. Das koennen Sie mit einer expliziten dnsConfig optimieren:
spec:
dnsConfig:
options:
- name: ndots
value: "2"
Wann ein Service Mesh sinnvoll wird
CoreDNS und ClusterIP-Services decken die grundlegende Kommunikation ab. Aber ab einer gewissen Komplexitaet stossen Sie an Grenzen: kein automatisches mTLS zwischen Services, kein feingranulares Traffic Splitting, kein verteiltes Tracing ohne Instrumentierung.
Hier kommen Service Meshes wie Istio oder Linkerd ins Spiel. Sie injizieren einen Sidecar-Proxy (Envoy bei Istio, linkerd2-proxy bei Linkerd) in jeden Pod, der den gesamten Netzwerkverkehr abfaengt und steuert.
Istio vs. Linkerd -- eine ehrliche Einschaetzung:
| Kriterium | Istio | Linkerd |
|---|---|---|
| Ressourcenverbrauch | Hoch (100-200 MB pro Sidecar) | Gering (20-30 MB pro Sidecar) |
| Komplexitaet | Hoch, steile Lernkurve | Moderat, schneller Einstieg |
| Feature-Umfang | Sehr umfangreich | Fokussiert auf Kern-Features |
| mTLS | Ja, vollstaendig | Ja, per Default |
| Traffic Splitting | Ja, sehr feingranular | Ja, ueber TrafficSplit CRD |
| Multicluster | Ja | Ja (ab 2.14) |
| CNCF-Status | Graduated | Graduated |
Faustregeln fuer die Entscheidung:
- Unter 10 Microservices: Kein Service Mesh noetig. NetworkPolicies und manuelle mTLS-Konfiguration reichen.
- 10-30 Microservices: Linkerd evaluieren. Geringer Overhead, schnelle Installation.
- 30+ Microservices mit komplexem Traffic Management: Istio in Betracht ziehen.
Service Types im Ueberblick: Wann welchen verwenden
Neben ClusterIP und Headless gibt es weitere Service-Typen, die fuer die Service Discovery relevant sind:
| Service-Typ | Erreichbarkeit | Typischer Einsatz | DNS-Verhalten |
|---|---|---|---|
| ClusterIP | Nur intern | APIs, Backends, Microservices | Loest zu virtueller IP auf |
| Headless | Nur intern | StatefulSets, DB-Cluster | Loest zu allen Pod-IPs auf |
| NodePort | Extern via Node-IP:Port | Entwicklung, Tests | Wie ClusterIP + externer Port |
| LoadBalancer | Extern via Cloud-LB | Produktions-Ingress | Wie ClusterIP + externe IP |
| ExternalName | Intern als Alias | Externe Abhaengigkeiten | CNAME auf externen Host |
Fuer die interne Service Discovery sind nur ClusterIP und Headless relevant. NodePort und LoadBalancer sind Mechanismen, um Services nach aussen zu exponieren -- sie aendern nichts an der internen Discovery.
NetworkPolicies und Service Discovery
Ein haeufig uebersehener Punkt: NetworkPolicies koennen die Service Discovery brechen, wenn sie nicht korrekt konfiguriert sind. Wenn Sie eine Default-Deny-Policy fuer Ihren Namespace setzen, muessen Sie explizit den DNS-Traffic zu CoreDNS erlauben:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
Ohne diese Regel koennen Pods im Namespace keine DNS-Anfragen mehr stellen und finden keinen anderen Service -- obwohl die Services korrekt konfiguriert sind. Das fuehrt zu verwirrenden Timeouts, die auf den ersten Blick nicht nach einem DNS-Problem aussehen.
Stellen Sie sicher, dass Sie auch den Traffic zum eigentlichen Ziel-Service erlauben:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-backend-access
namespace: production
spec:
podSelector:
matchLabels:
app: frontend
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app: order-api
ports:
- protocol: TCP
port: 8080
Multicluster Service Discovery
Sobald Sie mehr als einen Kubernetes-Cluster betreiben, wird Service Discovery komplexer. Ein Service in Cluster A muss einen Service in Cluster B finden koennen. Es gibt mehrere Ansaetze:
Service Mesh mit Multicluster-Support: Istio und Linkerd koennen Services cluster-uebergreifend erreichbar machen. Das funktioniert, fuegt aber die Komplexitaet eines Service Mesh hinzu.
Kubernetes MCS API (Multi-Cluster Services): Ein relativ neues API, das ServiceExport und ServiceImport Objekte definiert. Damit koennen Services explizit fuer andere Cluster freigegeben werden. Die Implementierung haengt vom Cloud-Provider ab.
Externer DNS mit gemeinsamer Domain: Der pragmatischste Ansatz fuer viele Teams. Jeder Cluster registriert seine Services per ExternalDNS in einer gemeinsamen DNS-Zone (z.B. Route53 oder Cloud DNS). Services finden sich dann ueber regulaere DNS-Namen.
Fuer die meisten Teams mit zwei bis drei Clustern ist der externe DNS-Ansatz der einfachste Einstieg.
Umgebungsvariablen: Der Legacy-Weg
Kubernetes injiziert fuer jeden Service, der vor einem Pod existiert, automatisch Umgebungsvariablen im Format <SERVICE_NAME>_SERVICE_HOST und <SERVICE_NAME>_SERVICE_PORT. Dieser Mechanismus hat zwei gravierende Nachteile:
Services, die nach dem Pod-Start erstellt werden, sind nicht sichtbar. Und bei vielen Services im Namespace wird die Umgebung schnell unuebersichtlich. Verwenden Sie diesen Mechanismus nur, wenn Sie eine Legacy-Anwendung migrieren, die Umgebungsvariablen erwartet und nicht auf DNS umgestellt werden kann.
Es gibt sogar Szenarien, in denen Umgebungsvariablen aktiv Probleme verursachen. Bei Namespaces mit mehr als 50 Services kann die Anzahl der Umgebungsvariablen die OS-Limits erreichen. In solchen Faellen koennen Sie den Mechanismus komplett deaktivieren:
spec:
enableServiceLinks: false
containers:
- name: app
image: myapp:v1
Zusammenfassung: Entscheidungshilfe
Fuer die meisten Kubernetes-Deployments ist die Service-Discovery-Strategie einfach:
- ClusterIP + CoreDNS als Basis fuer alle internen Services verwenden.
- Headless Services fuer StatefulSets und Workloads, die direkte Pod-Adressierung brauchen.
- ExternalName Services als Alias fuer externe Abhaengigkeiten.
- Service Mesh erst einfuehren, wenn konkrete Anforderungen an mTLS, Traffic Splitting oder Observability bestehen.
Starten Sie einfach und erweitern Sie bei Bedarf. Die meisten Teams, die sofort mit Istio anfangen, verbringen mehr Zeit mit dem Mesh als mit der eigentlichen Anwendung.
Weiterführende Artikel
- Kubernetes Monitoring: Kosten senken mit Open Source
- Kubernetes Security Hardening Checkliste
- OpenTelemetry auf Kubernetes einsetzen
- Kubernetes Networking und Storage im Detail
- Service nicht erreichbar? Troubleshooting Guide
Wenn Sie Unterstuetzung bei der Architektur Ihrer Service-Kommunikation brauchen oder eine Service-Mesh-Evaluierung planen, sprechen Sie uns an. Wir helfen bei Konzeption, Implementierung und Betrieb -- hier Kontakt aufnehmen.
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
CoreDNS Debugging: Kubernetes-DNS Probleme lösen
DNS-Probleme in Kubernetes systematisch debuggen: CoreDNS-Logs, ndots-Konfiguration, NXDOMAIN-Fehler und Corefile-Optimierung für schnellere Auflösung.
Kubernetes DNS Auflösung fehlgeschlagen: CoreDNS debuggen
Kubernetes DNS Auflösung fehlgeschlagen? Systematisches CoreDNS Debugging mit ndots, search domains und DNS Policy für schnelle Problemlösung.
CoreDNS Troubleshooting: Kubernetes DNS Probleme lösen
CoreDNS-Probleme systematisch debuggen: DNS-Auflösung testen, ndots konfigurieren, DNS-Policies verstehen und Performance optimieren.
Istio Ambient Mesh: Service Mesh ohne Sidecars
Istio Ambient Mesh ersetzt Sidecar-Proxies durch ztunnel und Waypoint Proxies und spart dabei 40-50% Ressourcen gegenüber dem klassischen Sidecar-Modell.
Kubernetes Service Discovery: DNS, ClusterIP und Mesh
Service Discovery in Kubernetes von A bis Z: CoreDNS-Interna, ClusterIP, Headless Services, ExternalName und wann ein Service Mesh den Unterschied macht.