Dienste

Auf dieser Seite werden Kubernetes-Dienste und ihre Verwendung in Google Kubernetes Engine beschrieben. Informationen zum Erstellen eines Diensts finden Sie unter Anwendungen über Dienste freigeben.

Was ist ein Dienst?

Ein Service dient dazu, eine Reihe von Pod-Endpunkten in einer Ressource zu gruppieren. Sie können verschiedene Zugriffsmöglichkeiten für die Gruppierung konfigurieren. Standardmäßig erhalten Sie eine stabile Cluster-IP-Adresse, über die Clients innerhalb des Clusters Pods im Service kontaktieren können. Ein Client sendet eine Anfrage an die stabile IP-Adresse. Die Anfrage wird dann an einen der Pods im Dienst weitergeleitet.

Die Mitglieds-Pods eines Diensts werden mithilfe eines Selektors ermittelt. Damit ein Pod Mitglied des Diensts sein kann, muss der Pod über alle im Selektor angegebenen Labels verfügen. Ein Label ist ein beliebiges Schlüssel/Wert-Paar, das an ein Objekt angehängt ist.

Das folgende Dienstmanifest hat einen Selektor, mit dem zwei Labels festgelegt werden. Im Feld selector wird angegeben, dass jeder Pod mit den beiden Labels app: metrics und Label department:engineering ein Mitglied dieses Dienstes ist.

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: metrics
    department: engineering
  ports:
  ...

Vorteile von Diensten

In einem Kubernetes-Cluster hat jeder Pod eine interne IP-Adresse. Die Pods wechseln jedoch häufig und ihre IP-Adressen ändern sich. Daher ist es nicht sinnvoll, IP-Adressen von Pods direkt zu verwenden. Ein Dienst bietet Ihnen eine stabile IP-Adresse, die für die gesamte Lebensdauer des Diensts gilt, auch wenn sich die IP-Adressen der Mitglieds-Pods ändern.

Außerdem bieten Dienste eine Load-Balancing-Funktion, sodass Clients eine einzelne, stabile IP-Adresse aufrufen und ihre Anfragen auf die Pods verteilt werden, die Mitglieder des Diensts sind.

Diensttypen

Es gibt fünf Diensttypen:

  • ClusterIP (Standard): Interne Clients senden Anfragen an eine stabile interne IP-Adresse.

  • NodePort: Clients senden Anforderungen an die IP-Adresse eines Knotens über einen oder mehrere nodePort-Werte, die vom Dienst angegeben werden.

  • LoadBalancer: Clients senden Anfragen an die IP-Adresse eines Netzwerk-Load-Balancers.

  • ExternalName: Interne Clients verwenden den DNS-Namen eines Diensts als Alias für einen externen DNS-Namen.

  • Headless: Wenn Sie eine Pod-Gruppierung wünschen, aber keine stabile IP-Adresse benötigen, können Sie einen monitorlosen Service verwenden.

Der Typ NodePort ist eine Erweiterung des Typs ClusterIP. Ein Dienst des Typs NodePort hat also eine Cluster-IP-Adresse.

Der Typ LoadBalancer ist eine Erweiterung des Typs NodePort. Ein Dienst vom Typ LoadBalancer hat also eine Cluster-IP-Adresse und einen oder mehrere nodePort-Werte.

Dienste vom Typ ClusterIP

Wenn Sie einen Dienst vom Typ ClusterIP erstellen, erstellt Kubernetes eine stabile IP-Adresse, auf die von Knoten im Cluster aus zugegriffen werden kann.

Hier ist ein Manifest für einen Dienst vom Typ ClusterIP:

apiVersion: v1
kind: Service
metadata:
  name: my-cip-service
spec:
  selector:
    app: metrics
    department: sales
  type: ClusterIP
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

Mithilfe von kubectl apply -f [MANIFEST_FILE] können Sie den Dienst erstellen. Nachdem Sie den Dienst erstellt haben, können Sie kubectl get service verwenden, um die stabile IP-Adresse anzuzeigen:

NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)
my-cip-service   ClusterIP   10.11.247.213   none          80/TCP

Clients im Cluster rufen den Dienst über die Cluster-IP-Adresse und den TCP-Port auf, der im Feld port des Dienstmanifests angegeben ist. Die Anfrage wird an einen der Mitglieds-Pods an dem TCP-Port weitergeleitet, der im Feld targetPort angegeben ist. Für das obige Beispiel ruft ein Client den Dienst unter 10.11.247.213 über TCP-Port 80 auf. Die Anfrage wird über TCP-Port 8080 an einen der Mitglieds-Pods weitergeleitet. Dafür muss der Mitglieds-Pod einen Container haben, der TCP-Port 8080 überwacht. Wenn kein Container Port 8080 überwacht, wird für die Clients die Meldung "Verbindung fehlgeschlagen" oder "Die Website ist nicht erreichbar" angezeigt.

Dienste vom Typ NodePort

Wenn Sie einen Dienst vom Typ NodePort erstellen, erhalten Sie in Kubernetes den Wert nodePort. Anschließend kann auf den Dienst zugegriffen werden, indem die IP-Adresse eines beliebigen Knotens zusammen mit dem Wert nodePort verwendet wird.

Dies ist ein Manifest für einen Dienst vom Typ NodePort:

apiVersion: v1
kind: Service
metadata:
  name: my-np-service
spec:
  selector:
    app: products
    department: sales
  type: NodePort
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

Nachdem Sie den Dienst erstellt haben, können Sie kubectl get service -o yaml verwenden, um seine Spezifikation und den Wert nodePort anzusehen.

spec:
  clusterIP: 10.11.254.114
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 32675
    port: 80
    protocol: TCP
    targetPort: 8080

Externe Clients rufen den Dienst auf, indem sie die externe IP-Adresse eines Knotens zusammen mit dem durch nodePort angegebenen TCP-Port verwenden. Die Anfrage wird an einen der Mitglieds-Pods am TCP-Port weitergeleitet, der im Feld targetPort angegeben ist.

Angenommen, die externe IP-Adresse eines der Clusterknoten lautet 203.0.113.2. Für das obige Beispiel ruft der externe Client den Dienst unter 203.0.113.2 über TCP-Port 32675 auf. Die Anfrage wird über TCP-Port 8080 an einen der Mitglieds-Pods weitergeleitet. Dafür muss der Mitglieds-Pod einen Container haben, der TCP-Port 8080 überwacht.

Der Diensttyp NodePort ist eine Erweiterung des Diensttyps ClusterIP. Interne Clients haben also zwei Möglichkeiten, den Service aufzurufen:

  • clusterIP und port verwenden
  • Interne IP-Adresse eines Knotens und nodePort verwenden

Für einige Clusterkonfigurationen verwendet der Google Cloud-HTTP(S)-Load-Balancer einen Service vom Typ NodePort. Weitere Informationen finden Sie unter HTTP-Load-Balancing mit Ingress einrichten.

Ein HTTP(S)-Load-Balancer ist ein Proxyserver und unterscheidet sich dadurch grundlegend von dem Netzwerk-Load-Balancer, der in diesem Thema unter Dienste vom Typ LoadBalancer beschrieben wird.

Dienst vom Typ LoadBalancer

Wenn Sie einen Dienst vom Typ LoadBalancer erstellen, wird ein Google Cloud-Controller aktiviert, der einen Netzwerk-Load-Balancer im Projekt konfiguriert. Der Load-Balancer hat eine stabile IP-Adresse, auf die von außerhalb des Projekts zugegriffen werden kann.

Ein Netzwerk-Load-Balancer ist kein Proxyserver. Er leitet Pakete ohne Änderung der Quell- und Ziel-IP-Adressen weiter.

Dies ist ein Manifest für einen Dienst vom Typ LoadBalancer:

apiVersion: v1
kind: Service
metadata:
  name: my-nlb-service
spec:
  selector:
    app: metrics
    department: engineering
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 8080

Nachdem Sie den Dienst erstellt haben, können Sie mit kubectl get service -o yaml dessen Spezifikation und die stabile externe IP-Adresse ansehen:

spec:
  clusterIP: 10.11.242.115
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 32676
    port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: metrics
    department: engineering
  sessionAffinity: None
  type: LoadBalancer
  status:
    loadBalancer:
      ingress:
      - ip: 203.0.113.100

In der Ausgabe wird die IP-Adresse des Netzwerk-Load-Balancers unter loadBalancer:ingress: angezeigt. Externe Clients rufen den Dienst mit der IP-Adresse des Load-Balancers und dem durch port angegebenen TCP-Port auf. Die Anfrage wird an einen der Mitglieds-Pods an dem TCP-Port weitergeleitet, der im Feld targetPort angegeben wurde. Für das obige Beispiel ruft ein Client den Dienst unter 203.0.113.100 über TCP-Port 80 auf. Die Anfrage wird über TCP-Port 8080 an einen der Mitglieds-Pods weitergeleitet. Dafür muss der Mitglieds-Pod einen Container haben, der TCP-Port 8080 überwacht.

Der Diensttyp "LoadBalancer" ist eine Erweiterung des Diensttyps "NodePort", der wiederum eine Erweiterung des Diensttyps "ClusterIP" ist.

Dienste vom Typ ExternalName

Ein Dienst vom Typ ExternalName stellt einen internen Alias für einen externen DNS-Namen bereit. Interne Clients senden Anfragen unter Verwendung des internen DNS-Namens und die Anfragen werden an den externen Namen umgeleitet.

Dies ist ein Manifest für einen Dienst vom Typ ExternalName:

apiVersion: v1
kind: Service
metadata:
  name: my-xn-service
spec:
  type: ExternalName
  externalName: example.com

Wenn Sie einen Dienst erstellen, erzeugt Kubernetes einen DNS-Namen, den interne Clients verwenden können, um den Dienst aufzurufen. Im obigen Beispiel lautet der DNS-Name "my-xn-service.default.svc.cluster.local". Wenn ein interner Client eine Anfrage an "my-xn-service.default.svc.cluster.local" sendet, wird die Anfrage an "example.com" umgeleitet.

Der Diensttyp ExternalName unterscheidet sich grundlegend von den anderen Diensttypen. Tatsächlich entspricht ein Dienst des Typs ExternalName nicht der Definition von Diensten, die zu Beginn dieses Themas angegeben wurde. Ein Dienst vom Typ ExternalName ist nicht mit einer Gruppe von Pods verknüpft und hat keine stabile IP-Adresse. Stattdessen stellt ein Dienst vom Typ ExternalName eine Zuordnung von einem internen zu einem externen DNS-Namen dar.

Dienstabstraktion

Ein Service ist kein Prozess, mit dem eine bestimmte Netzwerkschnittstelle überwacht wird. In diesem Sinne handelt es sich dabei um eine Abstraktion. Ein Teil der Abstraktion ist in den iptables-Regeln der Clusterknoten implementiert. Je nach Diensttyp werden andere Teile der Abstraktion durch Netzwerk-Load-Balancing oder HTTP(S)-Load-Balancing implementiert.

Beliebige Dienstports

Der Wert des Felds port in einem Dienstmanifest ist beliebig. Der Wert von targetPort ist dagegen nicht beliebig. Jeder Mitglieds-Pod muss einen Container haben, der targetPort überwacht.

Dies ist ein Dienst vom Typ LoadBalancer mit einem port-Wert von 50.000:

apiVersion: v1
kind: Service
metadata:
  name: my-ap-service
spec:
  clusterIP: 10.11.241.93
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 30641
    port: 50000
    protocol: TCP
    targetPort: 8080
  selector:
    app: parts
    department: engineering
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 203.0.113.200

Ein Client ruft den Dienst unter 203.0.113.200 über TCP-Port 50000 auf. Die Anfrage wird über TCP-Port 8080 an einen der Mitglieds-Pods weitergeleitet.

Mehrere Ports

Das Feld ports eines Dienstes ist ein Array von ServicePort-Objekten. Das ServicePort-Objekt hat folgende Felder:

  • name
  • protocol
  • port
  • targetPort
  • nodePort

Wenn Sie mehr als einen ServicePort haben, muss jeder ServicePort einen eindeutigen Namen haben.

Dies ist ein Dienst vom Typ LoadBalancer mit zwei ServicePort-Objekten:

apiVersion: v1
kind: Service
metadata:
  name: my-tp-service
spec:
  clusterIP: 10.11.242.196
  externalTrafficPolicy: Cluster
  ports:
  - name: my-first-service-port
    nodePort: 31233
    port: 60000
    protocol: TCP
    targetPort: 50000
  - name: my-second-service-port
    nodePort: 31081
    port: 60001
    protocol: TCP
    targetPort: 8080
  selector:
    app: tests
    department: engineering
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 203.0.113.201

Wenn ein Client den Dienst im obigen Beispiel unter 203.0.113.201 über TCP-Port 60000 aufruft, wird die Anfrage über TCP-Port 50000 an einen Mitglieds-Pod weitergeleitet. Erfolgt der Aufruf unter 203.0.113.201 jedoch über TCP-Port 60001, wird die Anfrage über TCP-Port 8080 an einen Mitglieds-Pod weitergeleitet.

Dafür muss jeder Mitglieds-Pod einen Container haben, der TCP-Port 50000 überwacht, und einen Container, der TCP-Port 8080 überwacht. Sie können entweder einen einzelnen Container mit zwei Threads verwenden oder zwei Container auf demselben Pod.

Dienstendpunkte

Wenn Sie einen Dienst erstellen, erzeugt Kubernetes ein Endpoints-Objekt, das denselben Namen wie der Dienst hat. Kubernetes verwendet das Endpoints-Objekt, um nachzuverfolgen, welche Pods Mitglieder des Diensts sind.

Weitere Informationen