Kurs › Folge 12
Services: wie Pods sich finden
Pod-IPs ändern sich ständig. Der Service ist die stabile Adresse davor — und kein einziges Programm.
Das Video zu dieser Folge ist noch nicht veröffentlicht. Die Notizen stehen trotzdem schon hier.
Was du danach kannst
- ClusterIP, NodePort und Headless unterscheiden
- einen Service ueber Labels an Pods binden und die Endpoints lesen
- den Weg einer Anfrage vom DNS-Namen bis zum Pod nachvollziehen
- erklaeren, warum ein Service kein laufendes Programm ist
Das Problem
Starte einen Pod, notiere seine IP, lösche ihn, lass ihn neu anlegen — die IP ist eine andere. Bei jedem Update, jedem Neustart, jedem Knotenausfall. Auf eine Pod-IP kann sich niemand verlassen.
Der Service ist die Antwort: eine Adresse, die bleibt.
Ein Service in einem Befehl
kubectl expose deployment web --port=80
Was dabei entsteht:
- Kubernetes nimmt die Labels der Pods (
app=web) als Selektor des Service - Der Service bekommt eine IP aus dem Service-Bereich (
10.96.0.0/12) — die ClusterIP --port=80ist der Port des Service; dertargetPortam Pod wird stillschweigend genauso gesetzt
Vorderseite und Rückseite
kubectl get svc,endpoints
NAME TYPE CLUSTER-IP PORT(S)
service/web ClusterIP 10.96.134.22 80/TCP
NAME ENDPOINTS
endpoints/web 10.244.1.5:80,10.244.1.6:80,10.244.1.7:80
Der Service ist die stabile Vorderseite. Die Endpoints sind die aktuelle Rückseite — die Liste der Pods, die gerade bedient werden.
Diese Liste pflegt ein Controller selbstständig. Er beobachtet, welche Pods
zum Selektor passen und bereit sind. Genau hier hängt die Readiness-Probe
aus Folge 18: Ein Pod, der nicht Ready meldet, verschwindet aus dieser Liste
und bekommt keinen Verkehr mehr. Das ist der gesamte Mechanismus hinter
„Update ohne Ausfall".
In neueren Versionen sind EndpointSlices das eigentliche Objekt (
kubectl get endpointslices). Die alte Endpoints-Ansicht gibt es aus Gewohnheit weiterhin.
Ein Service ist kein Programm
Das ist der Punkt, an dem die meisten ein falsches Bild im Kopf haben. Es gibt keinen Service-Container, keinen Proxy-Prozess, kein Programm, das lauscht.
Die ClusterIP existiert auf keiner Netzwerkkarte. Sie ist ein Ziel für Umschreibungsregeln, die auf jedem Knoten hinterlegt sind — klassisch von kube-proxy als iptables-Regeln, bei Cilium als eBPF-Programme im Kernel.
Deshalb funktioniert ein Service auch auf einem Knoten, auf dem gar kein passender Pod läuft: Die Regel ist überall da.
DNS im Cluster
Jeder Pod bekommt eine /etc/resolv.conf in dieser Art:
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
Deshalb genügt der kurze Name. web wird über die Suchliste zu
web.default.svc.cluster.local — dem vollständigen Namen des Service:
<dienst>.<namensraum>.svc.cluster.local
Aus einem anderen Namensraum heraus brauchst du entsprechend
web.default oder den vollen Namen.
Der Weg einer Anfrage
kubectl run test --rm -it --image=busybox -- wget -qO- web
wgetfragt DNS nachweb→ CoreDNS antwortet mit der ClusterIPwgetverbindet sich zu10.96.134.22:80- Auf dem Knoten greift die Regel und schreibt das Ziel um auf eine Pod-IP aus der Endpoints-Liste
- Das Paket läuft über das Pod-Netz zu diesem Pod — womöglich auf einem anderen Rechner
- nginx antwortet
Die Verteilung geschieht pro Verbindung, nicht pro Anfrage. Wer im Browser zehnmal neu lädt, landet nicht zwingend zehnmal woanders.
Der Wegwerf-Pod
Das Muster --rm -it wirst du hundertmal brauchen:
| Teil | Bedeutung |
|---|---|
--image=busybox |
winziges Image mit sh und wget |
-it |
interaktiv, mit Terminal verbunden |
--rm |
Pod löschen, sobald der Befehl endet |
-- |
alles danach ist der Befehl im Container |
Die drei Arten
| Typ | Erreichbar | Wofür |
|---|---|---|
| ClusterIP | nur im Cluster | der Normalfall |
| NodePort | fester Port auf jedem Knoten (30000–32767) | Labor, einfache Zugänge |
Headless (clusterIP: None) |
keine IP, DNS liefert die Pod-IPs direkt | Datenbanken, StatefulSets |
LoadBalancer fehlt hier bewusst — der braucht jemanden, der externe Adressen
vergibt. Im Heimlabor macht das MetalLB, und das ist Folge 14.
Zum Nachlesen
Eine geordnete Übersicht über die offizielle Dokumentation steht unter Nachlesen.
Befehle aus dieser Folge
kubectl expose deployment web --port=80kubectl get svc,endpointskubectl get endpointsliceskubectl run test --rm -it --image=busybox -- wget -qO- webkubectl run dns --rm -it --image=busybox -- cat /etc/resolv.confkubectl logs -l app=web --prefix -f --tail=1
Begriffe
- Service
- eine Regel, keine Anwendung — die ClusterIP existiert auf keiner Netzwerkkarte
- ClusterIP
- nur im Cluster erreichbar, der Normalfall
- NodePort
- ein fester Port auf jedem Knoten, gut fuers Labor
- Endpoints
- die Liste der Pods, die ein Service gerade bedient — nur bereite Pods stehen darin
- CoreDNS
- der Namensdienst im Cluster; <dienst>.<namensraum>.svc.cluster.local
- kube-proxy / eBPF
- setzt die Service-Regeln auf jedem Knoten um
Übung — mach es selbst
Mach die Verteilung sichtbar.
- Deployment
webmit 3 Repliken, Service davor. - Fenster 1:
kubectl logs -l app=web --prefix -f --tail=1 - Fenster 2: fuenfmal
kubectl run test --rm -it --image=busybox -- wget -qO- web - An den Praefixen ablesen, welcher Pod welche Anfrage bekommen hat.
Dann der eigentliche Test:
kubectl get endpoints web— drei Adressen.- Loesche einen Pod und ruf den Befehl sofort wieder auf. Wie viele Adressen stehen drin, waehrend der Ersatz startet?
- Und wie lautet die ClusterIP dabei? (Sie aendert sich nicht — das ist der ganze Sinn der Sache.)
Zusatz: Aendere den Service auf type: NodePort und ruf ihn von deinem
Laptop aus auf: curl http://192.168.178.75:<nodeport>. Warum antwortet
er auch auf der IP des Knotens, auf dem gar kein Pod laeuft?