Wie Kubernetes-Dienste funktionieren

Wie Kubernetes-Dienste funktionieren

  • ITOps & DevOps
6 Minuten Lesezeit Aktualisiert Jun 4, 2021

Auf einen Blick: Kubernetes-Dienste sind unerlässlich, um Anwendungen freizustellen und die Lastverteilung innerhalb von Clustern zu verwalten, indem sie stabile Endpunkte trotz dynamischer Pod-IP-Änderungen bieten. Sie unterstützen verschiedene Servicetypen, darunter ClusterIP, NodePort, LoadBalancer und ExternalName.

  • Dienste können mit oder ohne Selektoren für flexible Pod-Verwaltung erstellt werden.
  • Sie vereinfachen die Service-Entdeckung und überflüssig die Notwendigkeit separater Mechanismen.

Ein Kubernetes-Dienst ist eine logische Sammlung von Pods in einem Kubernetes-Cluster. Wir können einen K8s-Dienst als abstrakte Methode definieren, um die Lastverteilung zwischen den Pods zu verteilen und eine Anwendung auf einem Set von Pods bereitzustellen. Außerdem entfällt die Verwendung des integrierten Service-Mechanismus in Kubernetes die Implementierung eines separaten Service-Discovery-Mechanismus.

In diesem Artikel werden wir die Struktur eines Kubernetes-Dienstes und dessen Nutzung besprechen.

Was sind Kubernetes-Dienste?

Ein Kubernetes-Dienst kann verwendet werden, um eine auf einer Reihe von Pods installierte Anwendung mit einem einzigen Endpunkt einfach offenzulegen. Ein Dienst ist sowohl ein REST-Objekt als auch eine Abstraktion, die definiert:

  • Ein Set von Pods
  • Eine Richtlinie, um darauf zuzugreifen

Pods in einer Kubernetes-Bereitstellung werden regelmäßig erstellt und zerstört, wodurch sich ihre IP-Adressen ständig ändern. Das führt zu Auffindbarkeitsproblemen für die bereitgestellten Anwendung, was es dem Anwendungs-Frontend erschwert, zu erkennen, welche Pods verbunden werden sollen.

Hier kommen die Stärken von Kubernetes-Diensten ins Spiel: Dienste verfolgen die Änderungen der IP-Adressen und DNS-Namen der Pods und stellen sie dem Endnutzer als eine einzige IP oder DNS zur Verfügung.

Kubernetes-Dienste nutzen Selektoren, um eine Reihe von Pods anzusteuern:

  • Für native Kubernetes-Anwendungen (die Kubernetes-APIs zur Service-Discovery verwenden) wird die Endpunkt-API aktualisiert, sobald Änderungen an den Pods im Service vorliegen.
  • Nicht-native Anwendungen können virtuelle IP-basierte Bridge- oder Load-Balancer-Implementierungsmethoden von Kubernetes nutzen, um den Datenverkehr zu den Backend-Pods zu leiten.

Eigenschaften eines Kubernetes-Dienstes

Hier sind allgemeine Merkmale eines Dienstes:

  • Einem Dienst wird eine IP-Adresse ("Cluster-IP") zugewiesen, die die Service-Proxys verwenden.
  • Ein Dienst kann einen eingehenden Port auf jeden TargetPort abbilden. (Standardmäßig ist der TargetPort auf denselben Wert wie das Portfeld gesetzt und kann als Zeichenkette definiert werden.)
  • Die Portnummer, die jedem Namen zugewiesen ist, kann in jedem Backend-Pod variieren. (Zum Beispiel können Sie die Portnummer, die Pods in der nächsten Version Ihrer Backend-Software offenlegen, ändern, ohne die Clients zu beschädigen.)
  • Dienste unterstützen TCP (Standard), UDP und SCTP für Protokolle.
  • Dienste können mit oder ohne Selektor definiert werden.
  • Dienste unterstützen eine Vielzahl von Portdefinitionen

Schauen wir uns nun an, wie die Dienste funktionieren.

Definition eines Kubernetes-Dienstes

Wie oben erwähnt, können wir Kubernetes-Dienste mit oder ohne Selektoren definieren – machen wir beides!

Definition eines Dienstes mit einem Selektor

Im folgenden Beispiel haben wir einen einfachen Dienst definiert, der Port 80 im Service offenlegt, während er Port 8080 in den Pods mit dem Selektorlabel "app=webserver-nginx" anvisiert.

    apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: webserver-nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

Kubernetes weist automatisch eine IP-Adresse ("Cluster-IP") zu, die dann von Service-Proxys genutzt wird, um den Datenverkehr zu routen. Der Controller des Selektors überwacht konsequent Pods, die dem definierten Label entsprechen.

Einige Anwendungen erfordern, dass mehrere Ports über den Dienst bereitgestellt werden. Kubernetes ermöglicht dies durch Multi-Port-Services, bei denen ein Benutzer mehrere Ports in einem einzigen Service-Objekt definieren kann. Bei der Definition eines Multi-Port-Services besteht die Hauptanforderung darin, für jeden freigestellten Port Namen bereitzustellen, sodass sie eindeutig sind. Diese Portnamen können:

  • Nur alphanumerische Zeichen und das Strichzeichen enthalten
  • Sollte mit einem alphanumerischen Zeichen beginnen und enden.

In diesem Beispiel haben wir sowohl die Ports 80 als auch 443 den Zielports 8080 und 8090 zugänglich gemacht, um HTTP- und HTTPS-Verkehr mit dem Selektor "app=webserver-nginx-multiport" zu den zugrundeliegenden Pods zu leiten.

    apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: webserver-nginx-multiport
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 8080
    - name: https
      protocol: TCP
      port: 443
      targetPort: 8090

Definition eines Dienstes ohne Selektor

Bei der Definition eines Dienstes ohne Selektor müssen Sie den Dienst manuell der entsprechenden IP-Adresse und dem entsprechenden Port zuordnen, indem Sie ein Endpoints-Objekt hinzufügen. Der Grund ist, dass die Endpunktobjekte nicht automatisch erstellt werden wie bei einem Selektor, da Kubernetes nicht weiß, mit welchen Pods der Dienst verbunden sein soll. Dienst:

    apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

Endpunkt:

    apiVersion: v1
kind: Endpoints
metadata:
  name: nginx-service
subsets:
  - addresses:
      - ip: 192.10.0.1
    ports:
      - port: 8080

Bei der Definition eines Dienstes und des Endpunkts ist die Hauptüberlegung, dass sowohl der Name des Dienstes als auch des Endpunkts exakt übereinstimmen müssen.

Einige Anwendungsfälle für Dienste ohne Selektoren sind:

  • Verbindung zu einem anderen Dienst in einem anderen Namespace oder einem anderen Cluster
  • Kommunikation mit externen Diensten, Datenmigration, Testdienste, Deployments usw.

Erstellung eines Kubernetes-Dienstes

Da wir nun die Grundstruktur eines Kubernetes-Dienstes kennen, nehmen wir ein praktisches Beispiel, um besser zu verstehen, wie man einen Dienst erstellt. Zuerst erstellen wir eine kleine Bereitstellung mit vier Repliken eines Apache-Webservers.

apache-deployment.yaml

    apiVersion: apps/v1
kind: Deployment
metadata:
  name: apache-deployment
  labels:
    app: webserver
spec:
  replicas: 4
  selector:
    matchLabels:
      app: webserver
  template:
    metadata:
      labels:
        app: webserver
    spec:
      containers: 
      - name: apache
        image: bitnami/apache:latest
        ports:
        - containerPort: 80

Erstellen Sie die Bereitstellung.

    kubectl apply -f apache-deployment.yaml

Ergebnis:

Apache-Einsatz

Überprüfen Sie den Status des Einsatzes.

    kubectl get deployment apache-deployment

Ergebnis:

Bereitstellung

Jetzt haben wir die Anwendung auf dem Apache-Server bereitgestellt.

Als Nächstes erstellen wir einen Service, um auf unsere bereitgestellte Anwendung zuzugreifen. Dazu gibt es zwei Methoden:

  1. Erstellen Sie ein YAML-Manifest für einen Service
  2. Verwende den Befehl "kubectl expose"

Der Befehl Expose ermöglicht es den Nutzern, den Dienst direkt über die Kommandozeile zu erstellen.

Wir können den folgenden Befehl verwenden, um das "apache-deployment" mit dem ClusterIP-Servicetyp anzuzeigen. Wir werden den Service auf Port 8080 verweisen, da das "bitnami/apache"-Image Port 8080 als HTTP-Port verwendet.

    kubectl expose deployment apache-deployment --name=apache-http-service --type=ClusterIP --port=8080 --target-port=8080

Ergebnis:

Expose Deployment

Überprüfen Sie, ob der Dienst korrekt erstellt wurde.

    kubectl get service apache-http-service

Ergebnis:

HTTP-Dienst

Jetzt müssen wir den Datenverkehr an den von uns erstellten Dienst weiterleiten, und wir können dafür den Befehl "kubectl port-forward" verwenden. Wir werden den Datenverkehr vom Host-Port 8090 zum Service-Port 8080 leiten.

    kubectl port-forward service/apache-http-service 8090:8080

Ergebnis:

Vorwärtspost

Wenn wir zum "http://localhost:8090" navigieren, werden wir zu einer Nginx-Landingpage wie der folgenden weitergeleitet.

Lokale Arbeit

Wir hätten auch einen Dienst mit einer YAML-Datei für das obige Szenario definieren können, wie unten gezeigt. Dort haben wir den Selektor als "app=Webserver" gesetzt.

    apiVersion: v1
kind: Service
metadata:
  name: apache-http-service
spec:
  selector:
    app: webserver
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 8080

Arten von Kubernetes-Diensten

Es gibt vier Arten von Kubernetes-Diensten:

Kubernates-Services

Dies ist der Standardtyp, der den Dienst auf einer internen IP des Clusters offenlegt. Diese Dienste sind nur innerhalb des Clusters zugänglich. Daher müssen Nutzer Port Forwarding oder einen Proxy implementieren, um eine ClusterIP einem breiteren Datenverkehr zugänglich zu machen.

Ein NodePort-Dienst stellt den Dienst auf der IP jedes Knotens an einem statischen Port frei. Ein ClusterIP-Dienst wird automatisch erstellt, um den Datenverkehr an den NordPort-Dienst weiterzuleiten. Nutzer können von außen mit dem Dienst kommunizieren, indem sie anfordern :

Dies ist die bevorzugte Lösung, um den Cluster dem weiteren Internet zugänglich zu machen. Der LoadBalancer-Typ von Service erstellt einen Load Balancer (der Load Balancer-Typ hängt vom Cloud-Anbieter ab) und stellt den Service extern zur Verfügung.

Es erstellt außerdem automatisch ClusterIP- und NodePort-Dienste und routet den Datenverkehr entsprechend.

Dieser Diensttyp ordnet den Service den Inhalt des externalName-Feldes (z.B.: app.test.com) zu. Dies geschieht, indem ein Wert für den CNAME-Datensatz zurückgegeben wird.

Implementierungen von Service-Proxys

Der kube-Proxy-Prozess implementiert eine Form virtueller IPs für alle Servicetypen, mit Ausnahme des ExternalName-Typs. Die Nutzung von Proxying für Services ermöglicht es Benutzern, einige DNS-Auflösungsprobleme zu mindern.

Wenn beispielsweise ein DNS-Datensatz abgelaufen ist, kann es vorherige DNS-Abfragen noch mit dem abgelaufenen Datensatz zwischengespeichert werden, was zu Lösungen führt. Ebenso kann es zu Lösungen führen, wenn DNS-Datensätze nicht richtig weitergeleitet werden.

Die folgenden drei Methoden können vom kube-Proxy zum Routing von Verkehr verwendet werden:

  • Proxy-Modus: Benutzerraum
  • Proxy-Modus: iptables
  • Proxy-Modus: ipvs

Proxy-Modus: Benutzerraum

In diesem Modus überwacht kube-proxy den Kubernetes-Master, und wann immer ein Dienst oder Endpunkt erstellt oder entfernt wird, wird ein zufälliger Port am lokalen Knoten zugeteilt oder freigegeben.

Alle Verbindungen zu diesem "Proxy-Port" sind mit dem Dienst und den notwendigen Endpunkten verbunden.

Proxy-Modus: iptables

Dieser Modus überwacht auch den Kubernetes-Master auf Dienste und Endpunkte. Allerdings werden auch iptable-Regeln installiert, um den Datenverkehr zur ClusterIP des Dienstes und des Ports zu erfassen und den Datenverkehr dann umzuleiten.

Zusätzlich werden iptable-Regeln für Endpunktobjekte installiert, um den Backend-Pod auszuwählen, während das Standardverhalten darin besteht, ein zufälliges Backend auszuwählen. (Pod)

In diesem Modus überwacht der Kube-Proxy die Dienste und Endpunkte und ruft dann die Netlink-Schnittstelle auf, um entsprechende IPvS-Regeln (IP Virtual Server) zu erstellen. Dieser Modus synchronisiert die IPvVs-Regeln regelmäßig mit den Diensten und dem Endpunkt, um alles aktuell zu halten.

Entdeckung von Kubernetes-Diensten

Sie können zwei Methoden verwenden, um einen Dienst zu entdecken – DNS oder Environment Variable.

Dies ist die bevorzugte Methode zur Service-Discovery. Hier wird der DNS-Server dem Kubernetes-Cluster hinzugefügt, der die Kubernetes-API überwacht und für jeden neuen Dienst DNS-Datensätze erstellt. Wenn das DNS aktiviert ist, können clusterweit alle Pods die Namensauflösung der Dienste durchführen.

Umweltvariablen

Bei dieser Methode fügt Kubelet für jeden aktiven Service Umweltvariablen zu den Pods hinzu. Bei dieser Methode muss der gewünschte Service erstellt werden, bevor die Pods erstellt werden, die diesen Dienst nutzen werden. Andernfalls erhalten die Pods nicht die notwendigen Umgebungsvariablen für den gewünschten Service.

Wenn keine Lastverteilung und eine einzelne Dienst-IP erforderlich sind, können Nutzer einen headless Service erstellen, indem sie explizit "none" für das Cluster-IP-Feld angeben (.spec.clusterIP). Diese headless Services haben keine zugehörigen Cluster-IPs, und die Plattform bietet keine Lastverteilung oder Proxying für sie. Der Kube-Proxy ignoriert diese Services ebenfalls.

Die DNS-Konfiguration dieser Dienste hängt von den in den Diensten definierten Selektoren ab.

  • Headless-Service mit Selektoren. Der Endpunkt-Controller erstellt die Endpunkt-Datensätze in der API und verändert den DNS-Datensatz, um einen A-Datensatz zurückzugeben, der auf die erforderlichen Pods verweist.
  • Headless-Service ohne Selektoren. Der Endpunkt-Controller erstellt keine Endpunktdatensätze, ohne dass die Selektoren konfiguriert sind.

Zusammenfassung der K8s-Dienste

Damit haben wir alle Grundlagen von Kubernetes-Diensten abgedeckt. Wir kennen uns jetzt mit Diensten aus, einschließlich der verschiedenen Typen, der Service-Entdeckung und der Nutzung von Service-Proxys. Services sind ein integraler Bestandteil von Kubernetes und bieten Möglichkeiten, die Kommunikation zwischen Pods, externen Diensten und Nutzern zu erleichtern.

Diese Beiträge sind meine eigenen und spiegeln nicht unbedingt die Position, Strategien oder Meinung von BMC wider.

Mehr aus ITOps & DevOps

Interessieren Sie sich für mehr von BMC?

The Brief ist unsere monatliche E-Mail zum Mainframe und zur Enterprise-Orchestrierung: Recherchen, Kundenberichte, Produktnachrichten, Events.

Mit der Registrierung für dieses Angebot bestätigen Sie, dass Sie die Datenschutzrichtlinie von BMC gelesen und zugestimmt haben.

Sie haben The Brief abonniert

Das Briefing umfasst die Mainframe- und Enterprise-Orchestrierung – BMC AMI und Control-M – sowie die Analystenforschung, Kundeneinsätze und Events in beiden Bereichen.