Inhaltsverzeichnis
Kubernetes Headless-Service
Übersicht
Ein Service ist eine Kubernetes-Ressource, die einen einzigen Einstiegspunkt zu einem oder mehreren Pods bereitstellt. Genauer gesagt stellt ein Service eine Gruppe von Pods über einen einzigen Domänennamen und eine IP-Adresse im Netzwerk zur Verfügung. Sobald eine Anfrage den Service erreicht, leitet kube-proxy die Anfrage an einen der dahinterliegenden Pods weiter.
In diesem Tutorial lernen wir eine spezialisierte Form von Service-Ressourcen kennen, den sogenannten Headless Service. Im Gegensatz zum herkömmlichen Service erlaubt uns ein Headless Service, die IP-Adressen der einzelnen unterstützenden Pods direkt zu erhalten. Diese Fähigkeit eröffnet interessante Anwendungsfälle, die mit einem normalen Service nicht möglich wären.
Wir werden zunächst die grundlegende Konfiguration eines Headless Service behandeln und anschließend an einer praktischen Demonstration sehen, wie man ihn in der Praxis einsetzen kann.
Headless Service
In Kubernetes bezeichnet man einen Headless Service als eine Service-Ressource, der keine Cluster-IP-Adresse zugewiesen wird.
Um einen solchen Headless Service zu definieren, setzt man in der Ressourcen-Definition das Feld spec.clusterIP
auf den Wert None
:
$ cat headless-svc.yaml apiVersion: v1 kind: Service metadata: name: headless-svc spec: clusterIP: None selector: app: web ports: - protocol: TCP port: 80 targetPort: 8080
Nachdem wir die Ressource auf unserem Cluster erstellt haben, können wir die Details mit dem Befehl kubectl get svc überprüfen:
$ kubectl get svc -o go-template='{{ .spec.clusterIPs }}' headless-svc [None]
Dabei verwenden wir die Option -o go-template, um speziell das Feld clusterIP des Services auszulesen. Wie zu erwarten war, weist die Kubernetes control plane einer Headless-Service-Ressource keine IP-Adresse zu.
Eigenschaften eines Headless Service
Bei der Namensauflösung eines typischen Service liefert der DNS-Server eine einzelne IP-Adresse zurück – die sogenannte Cluster-IP, die von der Control Plane zugewiesen wurde. Anders verhält es sich bei einem Headless Service: Hier gibt eine DNS-Abfrage eine Liste von IP-Adressen zurück, die zu den einzelnen, unterstützenden Pods gehören.
Diese Funktionsweise ermöglicht Anwendungsfälle, die mit einem normalen Service nicht realisierbar wären. Beispielsweise kann ein Monitoring-Dienst mithilfe eines Headless Service gezielt alle IP-Adressen der zugehörigen Pods ermitteln und so individuelle Health-Check-Anfragen verschicken. Bei einem regulären Service wäre nicht sichergestellt, welcher Pod die Anfrage entgegennimmt.
Headless Service in Aktion
In diesem Abschnitt richten wir die notwendigen Ressourcen ein, um die Funktionsweise eines Headless-Services zu demonstrieren.
Zunächst erstellen wir einen Headless-Service:
$ kubectl apply -f - <<EOF apiVersion: v1 kind: Service metadata: name: headless-svc-stateful spec: clusterIP: None selector: app: web-stateful ports: - protocol: TCP port: 80 targetPort: 8080 EOF
Als Nächstes erstellen wir ein StatefulSet-Objekt, das drei Pods im Kubernetes-Cluster bereitstellt:
$ kubectl apply -f - <<EOF apiVersion: apps/v1 kind: StatefulSet metadata: name: app-stateful labels: app: server-stateful spec: replicas: 3 selector: matchLabels: app: web-stateful serviceName: headless-svc-stateful template: metadata: labels: app: web-stateful spec: containers: - name: nginx image: nginx:alpine ports: - containerPort: 80 EOF
Wichtig ist hierbei, dass das StatefulSet einen Wert für das Feld serviceName
benötigt. Dieser serviceName
muss auf den Headless Service verweisen, der das StatefulSet im Netzwerk verfügbar macht. In unserem Fall handelt es sich um die Ressource mit dem Namen headless-svc-stateful
.
Nachdem das Manifest angewendet wurde, wird die Kubernetes Control Plane drei Pods erzeugen:
$ kubectl get pods -l app=web-stateful NAME READY STATUS RESTARTS AGE app-stateful-0 1/1 Running 0 32m app-stateful-1 1/1 Running 0 31m app-stateful-2 1/1 Running 0 31m
Erstellen eines Ephemeral Containers
Ein Ephemeral Container ist eine praktische Möglichkeit, einem bestehenden Pod einen zusätzlichen Container mit einem anderen Image hinzuzufügen. Häufig wird hierfür ein Image mit erweiterten Werkzeugen verwendet, um Probleme innerhalb des Pods zu debuggen. In unserem Beispiel werden wir einen Ephemeral Container mit DNS-Tools auf einem bestehenden Pod erstellen, um verschiedene Funktionen unseres Headless Services zu testen.
Dazu verwenden wir den Befehl kubectl debug:
$ kubectl debug -it app-stateful-0 --image=slongstreet/bind-utils:latest -- bash Defaulting debug container name to debugger-2crmp. $
Der oben gezeigte Befehl startet einen Ephemeral Container im Pod app-stateful-0
unter Verwendung des Images slongstreet/bind-utils. Dieses Image enthält unter anderem das Werkzeug nslookup, mit dem wir die Auflösung von Service-Domainnamen überprüfen können. Anschließend öffnen wir eine Bash-Sitzung innerhalb des Containers.
Auflösung der IP-Adresse des Headless-Services
Innerhalb des flüchtigen Containers wollen wir die IP-Adresse des Headless-Services headless-svc-stateful
mittels des Befehls nslookup
auflösen:
$ nslookup headless-svc-stateful
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: headless-svc-stateful.default.svc.cluster.local
Address: 10.244.0.11
Name: headless-svc-stateful.default.svc.cluster.local
Address: 10.244.0.12
Name: headless-svc-stateful.default.svc.cluster.local
Address: 10.244.0.10
Die Abfrage liefert eine Liste von drei IP-Adressen für diesen Domainnamen. Jede dieser Adressen gehört zu einem Pod, der durch den Service angesprochen wird.
Ein kleiner Haken an der Antwort ist, dass wir anhand der IP-Adressen nicht direkt erkennen können, zu welchen Pods sie jeweils gehören. Glücklicherweise ist es mit einem Headless-Service einfach, diese Zuordnung herauszufinden.
Auflösung der IP-Adresse eines bestimmten Pods
Möchten wir die IP-Adresse eines bestimmten Pods ermitteln, der dem Headless-Service zugeordnet ist, fügen wir den Namen des Pods als Subdomain zum Domainnamen des Headless-Services hinzu.
Konkret können wir so die IP-Adresse des Pods app-stateful-1
mit folgendem Domainnamen auflösen app-stateful-1.headless-svc-stateful
:
$ nslookup app-stateful-1.headless-svc-stateful Server: 10.96.0.10 Address: 10.96.0.10#53 Name: app-stateful-1.headless-svc-stateful.default.svc.cluster.local Address: 10.244.0.11
Anstatt wie zuvor alle IP-Adressen der zugehörigen Pods zurückzugeben, liefert der Befehl nun lediglich die IP-Adresse des spezifischen Pods app-stateful-1
.
Fazit
In diesem Tutorial haben wir uns kurz mit dem Service-Objekt im Kubernetes-Umfeld beschäftigt und dabei erfahren, dass es sich bei einem Headless-Service im Grunde um einen Service ohne Cluster-IP handelt. Aufgrund des Fehlens einer Cluster-IP verhalten sich Headless-Services anders als reguläre Services.
Abschließend haben wir ein Beispiel durchgespielt, das zeigt, wie Headless-Services besonders in StatefulSet-Pods nützlich sind, um gezielt die IP-Adresse eines bestimmten Pods zu ermitteln.