Containernatives Load-Balancing über Ingress

Auf dieser Seite wird erläutert, wie Sie containernatives Load-Balancing in Google Kubernetes Engine (GKE) verwenden. Containernatives Load-Balancing ermöglicht es Load-Balancern, Pods direkt anzusteuern und Traffic gleichmäßig auf Pods zu verteilen.

Informationen zu den Vorteilen, Anforderungen und Einschränkungen des containernativen Load-Balancing finden Sie unter Containernatives Load-Balancing.

Containernatives Load-Balancing verwenden

In den folgenden Abschnitten werden Sie Schritt für Schritt durch die Konfiguration eines containernativen Load-Balancings in GKE geführt. Beachten Sie, dass für GKE-Cluster ab Version 1.17 und unter bestimmten Bedingungen containernatives Load-Balancing standardmäßig aktiviert und keine explizite cloud.google.com/neg: '{"ingress": true}'-Dienstannotation erforderlich ist.

VPC-nativen Cluster erstellen

Damit containernatives Load-Balancing verwendet werden kann, müssen Sie einen Cluster mit aktivierten Alias-IP-Adressen erstellen.

Mit dem folgenden Befehl wird beispielsweise der Cluster neg-demo-cluster mit einem automatisch bereitgestellten Subnetzwerk in der Zone us-central1-a erstellt:

gcloud container clusters create neg-demo-cluster \
    --enable-ip-alias \
    --create-subnetwork="" \
    --network=default \
    --zone=us-central1-a

Deployment erstellen

Stellen Sie als Nächstes eine Arbeitslast für den Cluster bereit.

Im folgenden Beispiel-Deployment (neg-demo-app) wird eine einzelne Instanz eines containerisierten HTTP-Servers ausgeführt. Wir empfehlen die Verwendung von Arbeitslasten, bei denen Feedback zur Pod-Bereitschaft zum Einsatz kommt, falls dies in der von Ihnen verwendeten GKE-Version verfügbar ist. Weitere Informationen und die GKE-Versionsanforderungen finden Sie oben im Abschnitt Pod-Bereitschaft. Möglicherweise müssen Sie ein Upgrade Ihres Clusters durchführen, um das Feedback zur Pod-Bereitschaft verwenden zu können.

mithilfe von Pod-Bereitschaftsfeedback

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: neg-demo-app # Label for the Deployment
  name: neg-demo-app # Name of Deployment
spec:
  selector:
    matchLabels:
      run: neg-demo-app
  template: # Pod template
    metadata:
      labels:
        run: neg-demo-app # Labels Pods from this Deployment
    spec: # Pod specification; each Pod created by this Deployment has this specification
      containers:
      - image: k8s.gcr.io/serve_hostname:v1.4 # Application to run in Deployment's Pods
        name: hostname # Container name
        ports:
        - containerPort: 9376
          protocol: TCP
  

mithilfe von hartcodierter Verzögerung

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: neg-demo-app # Label for the Deployment
  name: neg-demo-app # Name of Deployment
spec:
  minReadySeconds: 60 # Number of seconds to wait after a Pod is created and its status is Ready
  selector:
    matchLabels:
      run: neg-demo-app
  template: # Pod template
    metadata:
      labels:
        run: neg-demo-app # Labels Pods from this Deployment
    spec: # Pod specification; each Pod created by this Deployment has this specification
      containers:
      - image: k8s.gcr.io/serve_hostname:v1.4 # Application to run in Deployment's Pods
        name: hostname # Container name
      # Note: The following line is necessary only on clusters running GKE v1.11 and lower.
      # For details, see https://cloud.google.com/kubernetes-engine/docs/how-to/container-native-load-balancing#align_rollouts
        ports:
        - containerPort: 9376
          protocol: TCP
      terminationGracePeriodSeconds: 60 # Number of seconds to wait for connections to terminate before shutting down Pods
  

In diesem Deployment führt jeder Container einen HTTP-Server aus. Der HTTP-Server gibt einfach den Hostnamen des Anwendungsservers (den Namen des Pods, auf dem der Server ausgeführt wird) als Antwort zurück.

Speichern Sie dieses Manifest als neg-demo-app.yaml und erstellen Sie dann das Deployment, indem Sie folgenden Befehl ausführen:

kubectl apply -f neg-demo-app.yaml

Dienst für einen containernativen Load-Balancer erstellen

Nachdem Sie ein Deployment erstellt haben, müssen Sie die zugehörigen Pods in einem Dienst zusammenfassen.

Der folgende Beispieldienst neg-demo-svc zielt auf das im vorangegangenen Abschnitt erstellte Beispiel-Deployment ab:

apiVersion: v1
kind: Service
metadata:
  name: neg-demo-svc # Name of Service
  annotations:
    cloud.google.com/neg: '{"ingress": true}' # Creates a NEG after an Ingress is created
spec: # Service's specification
  type: ClusterIP
  selector:
    run: neg-demo-app # Selects Pods labelled run: neg-demo-app
  ports:
  - port: 80 # Service's port
    protocol: TCP
    targetPort: 9376

Das containernative Load-Balancing wird mit der Annotation des Diensts (cloud.google.com/neg: '{"ingress": true}') aktiviert. Der Load-Balancer wird jedoch erst erstellt, wenn Sie für den Dienst eine Ingress-Ressource erstellen.

Speichern Sie dieses Manifest als neg-demo-svc.yaml und erstellen Sie dann den Dienst, indem Sie folgenden Befehl ausführen:

kubectl apply -f neg-demo-svc.yaml

Ingress für den Dienst erstellen

Die folgende exemplarische Ingress-Ressource neg-demo-ing steuert den von Ihnen erstellten Dienst an:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: neg-demo-ing
spec:
  backend:
    serviceName: neg-demo-svc # Name of the Service targeted by the Ingress
    servicePort: 80 # Should match the port used by the Service

Speichern Sie dieses Manifest als neg-demo-ing.yaml und erstellen Sie dann die Ingress-Ressource, indem Sie folgenden Befehl ausführen:

kubectl apply -f neg-demo-ing.yaml

Beim Erstellen der Ingress-Ressource wird im Projekt ein HTTP(S)-Load-Balancer erstellt. Außerdem werden in jeder Zone, in der der Cluster ausgeführt wird, NEGs erstellt. Die Endpunkte in der NEG und die Endpunkte des Dienstes werden synchronisiert.

Ingress-Ressource prüfen

Nachdem Sie eine Arbeitslast bereitgestellt, die Pods in einem Dienst zusammengefasst und eine Ingress-Ressource für den Dienst erstellt haben, sollten Sie prüfen, ob die Ingress-Ressource den containernativen Load-Balancer erfolgreich bereitgestellt hat.

Führen Sie folgenden Befehl aus, um den Status der Ingress-Ressource abzurufen:

kubectl describe ingress neg-demo-ing

Suchen Sie in der Befehlsausgabe nach den Ereignissen ADD und CREATE:

Events:
Type     Reason   Age                From                     Message
----     ------   ----               ----                     -------
Normal   ADD      16m                loadbalancer-controller  default/neg-demo-ing
Normal   Service  4s                 loadbalancer-controller  default backend set to neg-demo-svc:32524
Normal   CREATE   2s                 loadbalancer-controller  ip: 192.0.2.0

Funktionalität des Load-Balancers testen

In den folgenden Abschnitten wird erläutert, wie Sie die Funktionalität eines containernativen Load-Balancers testen können.

Ingress-IP-Adresse aufrufen

Warten Sie einige Minuten, bis der HTTP(S)-Load-Balancer konfiguriert ist.

Sie können die Funktion des containernativen Load-Balancers durch Aufruf der IP-Adresse des Ingress prüfen.

Führen Sie den folgenden Befehl aus, um die Ingress-IP-Adresse abzurufen:

kubectl get ingress neg-demo-ing

In der Befehlsausgabe wird die IP-Adresse des Ingress in der Spalte ADDRESS angezeigt. Rufen Sie in einem Webbrowser die IP-Adresse auf.

Systemstatus des Back-End-Diensts prüfen

Sie können auch den Systemstatus des Back-End-Diensts des Load-Balancers abrufen.

Dazu müssen Sie zuerst eine Liste der Back-End-Dienste abrufen, die in Ihrem Projekt ausgeführt werden:

gcloud compute backend-services list

Kopieren Sie den Namen des Back-Ends, dessen Name den Dienstnamen enthält, z. B. neg-demo-svc. Dann rufen Sie den Systemstatus des Back-End-Diensts ab:

gcloud compute backend-services get-health backend-service-name --global

Ingress-Funktionalität prüfen

Eine weitere Möglichkeit, um zu testen, ob der Load-Balancer wie erwartet funktioniert, besteht darin, das Beispiel-Deployment zu skalieren und Testanfragen an die Ingress-Ressource zu senden. Anschließend prüfen Sie, ob die Anzahl der Replikatantworten stimmt.

Mit dem folgende Befehl wird das neg-demo-app-Deployment von einer Instanz auf zwei Instanzen skaliert:

kubectl scale deployment neg-demo-app --replicas 2

Warten Sie einige Minuten, bis das Rollout abgeschlossen ist. Mit folgendem Befehl können Sie prüfen, ob es so weit ist:

kubectl get deployment neg-demo-app

Prüfen Sie in der Befehlsausgabe, ob zwei verfügbare Replikate vorhanden sind:

NAME           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
neg-demo-app   2         2         2            2           26m

Führen Sie dann folgenden Befehl aus, um die Anzahl der separaten Antworten vom Load-Balancer zu zählen:

for i in `seq 1 100`; do \
  curl --connect-timeout 1 -s ip-address && echo; \
done  | sort | uniq -c

Dabei ist ip-address die IP-Adresse der Ingress-Ressource. Die IP-Adresse der Ingress-Ressource können Sie mit kubectl describe ingress neg-demo-ing abrufen.

Beachten Sie in der Befehlsausgabe, dass die Anzahl der unterschiedlichen Antworten der Anzahl der Replikate entspricht. Dies zeigt an, dass alle Back-End-Pods Traffic verarbeiten:

44 neg-demo-app-7f7dfd7bc6-dcn95
56 neg-demo-app-7f7dfd7bc6-jrmzf

Bereinigen

Wenn Sie mit den Aufgaben auf dieser Seite fertig sind, entfernen Sie die Ressourcen anhand der folgenden Schritte, sodass keine unerwünschten Kosten für Ihr Konto entstehen:

Cluster löschen

gcloud

gcloud container clusters delete neg-demo-cluster

Console

  1. Rufen Sie in der Cloud Console das Kubernetes Engine-Menü auf.

    Zum Google Kubernetes Engine-Menü

  2. Wählen Sie neg-demo-cluster aus.

  3. Klicken Sie auf Löschen.

Fehlerbehebung

Verwenden Sie die folgenden Methoden, um Ihre Netzwerkkonfiguration zu prüfen. In den folgenden Abschnitten wird erläutert, wie Sie spezifische Probleme im Zusammenhang mit containernativem Load-Balancing lösen.

  • Informationen zum Auflisten von Netzwerk-Endpunktgruppen finden Sie in der Dokumentation zum Load-Balancing.

  • Den Namen und die Zonen der NEG, die einem bestimmten Dienst entspricht, finden Sie in der neg-status-Annotation des Diensts. Rufen Sie die Dienstspezifikation mit folgendem Befehl ab:

    kubectl get svc svc-name -o yaml

    In der metadata:annotations:cloud.google.com/neg-status-Annotation sind der Name der NEG des Diensts und die Zonen der NEG aufgelistet.

  • Mit dem folgenden Befehl können Sie den Status des Back-End-Diensts, der einer bestimmten NEG entspricht, prüfen:

    gcloud compute backend-services [--project project-name] \
      get-health backend-service-name --global
    

    Der Back-End-Dienst trägt denselben Namen wie seine NEG.

  • So drucken Sie die Ereignislogs eines Diensts:

    kubectl describe svc service-name
    

    Der Namensstring des Diensts enthält den Namen und den Namespace des zugehörigen GKE-Diensts.

Cluster mit Alias-IP-Adressen kann nicht erstellt werden

Symptome
Wenn Sie einen Cluster mit Alias-IP-Adressen erstellen, wird möglicherweise der folgende Fehler ausgegeben:
ResponseError: code=400, message=IP aliases cannot be used with a legacy network.
Mögliche Ursachen
Dieser Fehler tritt auf, wenn der mit Alias-IP-Adressen zu erstellende Cluster auch ein Legacy-Netzwerk verwendet.
Lösung
Achten Sie darauf, dass Sie keinen Cluster mit Alias-IP-Adressen erstellen, für den gleichzeitig ein Legacy-Netzwerk aktiviert ist. Weitere Informationen zur Verwendung von Alias-IP-Adressen finden Sie unter VPC-nativen Cluster erstellen.

Traffic erreicht keine Endpunkte

Symptome
502-Fehler oder abgelehnte Verbindungen
Mögliche Ursachen

Normalerweise sind neue Endpunkte erreichbar, nachdem sie dem Load-Balancer hinzugefügt wurden – sofern sie auf Systemdiagnosen reagieren. Wenn der Traffic die Endpunkte nicht erreicht, können 502-Fehler auftreten oder Verbindungen abgelehnt werden.

502-Fehler und abgelehnte Verbindungen können auch durch einen Container verursacht werden, der SIGTERM nicht verarbeitet. Wenn ein Container SIGTERM nicht explizit verarbeitet, wird er sofort beendet und verarbeitet keine Anfragen mehr. Der Load-Balancer sendet weiterhin eingehenden Traffic an den beendeten Container, was zu Fehlern führt.

Der containernative Load-Balancer hat nur einen Back-End-Endpunkt. Während eines Rolling Updates wird der alte Endpunkt deprogrammiert, bevor der neue Endpunkt programmiert wird.

Lösung

Konfigurieren Sie die Container so, dass sie SIGTERM verarbeiten und während des gesamten Kulanzzeitraums für die Beendigung, der standardmäßig 30 Sekunden beträgt, weiterhin auf Anfragen antworten. Konfigurieren Sie die Pods so, dass Systemdiagnosen fehlschlagen, wenn sie SIGTERM empfangen. Dies signalisiert dem Load-Balancer, dass er keinen Traffic mehr an den Pod senden soll, solange die Endpunkt-Deprogrammierung ausgeführt wird.

Wenn Ihre Anwendung nicht ordnungsgemäß heruntergefahren wird und nicht mehr auf Anfragen reagiert, wenn sie einen SIGTERM empfängt, kann der PreStop-Hook verwendet werden, um SIGTERM zu verarbeiten und den Traffic weiterhin weiterzuleiten, während die Endpunkt-Deprogrammierung ausgeführt wird.

lifecycle:
  preStop:
    exec:
      # if SIGTERM triggers a quick exit; keep serving traffic instead
      command: ["sleep","60"]

Weitere Informationen finden Sie in der Dokumentation zum Beenden von Pods und in diesem Post zu den Best Practices für das Beenden von Pods.

Wenn das Back-End Ihres Load-Balancers nur eine Instanz hat, konfigurieren Sie die Rollout-Strategie so, dass nicht die einzige Instanz gelöscht wird, bevor die neue Instanz vollständig programmiert ist. Konfigurieren Sie bei Anwendungs-Pods, die von der Deployment-Arbeitslast verwaltet werden, die Rollout-Strategie so, dass der Parameter maxUnavailable dem Wert 0 entspricht.

strategy:
  rollingUpdate:
    maxSurge: 1
    maxUnavailable: 0

Um das Problem zu beheben, dass Traffic die Endpunkte nicht erreicht, prüfen Sie, ob die Firewallregeln eingehenden TCP-Traffic an die Endpunkte in den Bereichen 130.211.0.0/22 und 35.191.0.0/16 zulassen. Weitere Informationen finden Sie in der Dokumentation zu Cloud Load Balancing unter Systemdiagnosen erstellen.

Listen Sie die Back-End-Dienste in Ihrem Projekt auf. Der Namensstring des relevanten Back-End-Diensts enthält den Namen und den Namespace des zugehörigen Google Kubernetes Engine-Diensts:

gcloud compute backend-services list

Rufen Sie den Back-End-Systemstatus aus dem Back-End-Dienst ab:

gcloud compute backend-services get-health backend-service-name

Wenn alle Back-Ends fehlerhaft sind, ist Ihre Firewall, Ihre Ingress-Ressource oder Ihr Dienst möglicherweise falsch konfiguriert.

Wenn einige Back-Ends für kurze Zeit fehlerhaft sind, könnte dies auf Netzwerk-Programmierlatenz zurückzuführen sein.

Wenn einige Back-Ends nicht in der Liste der Back-End-Dienste aufgeführt werden, könnte dies auf Programmierlatenz zurückzuführen sein. Sie können dies mit folgendem Befehl überprüfen, wobei neg der Name des Back-End-Diensts ist. NEGs und Back-End-Dienste haben denselben Namen:

gcloud compute network-endpoint-groups list-network-endpoints neg

Prüfen Sie, ob alle erwarteten Endpunkte in der NEG enthalten sind.

Einführung wurde angehalten

Symptome
Die Einführung eines aktualisierten Deployments wird angehalten und die Anzahl der Replikate, die auf dem neuesten Stand sind, stimmt nicht mit der gewünschten Anzahl an aktualisierten Replikaten überein.
Mögliche Ursachen

Die Systemdiagnosen des Deployments können nicht ausgeführt werden. Möglicherweise ist das Container-Image fehlerhaft oder die Systemdiagnose falsch konfiguriert. Mit dem rollierenden Ersetzen der Pods wird gewartet, bis das Pod-Readiness-Gate des neu gestarteten Pods den Status "True" aufweist. Dies geschieht nur, wenn der Pod auf Load-Balancer-Systemdiagnosen reagiert. Wenn der Pod nicht reagiert oder die Systemdiagnose falsch konfiguriert ist, können die Bedingungen des Readiness-Gates nicht erfüllt werden und die Einführung kann nicht fortgesetzt werden.

Wenn Sie kubectl ab Version 1.13 verwenden, können Sie den Status der Readiness-Gates eines Pods mit dem folgenden Befehl prüfen:

kubectl get my-pod -o wide

Prüfen Sie die Spalte READINESS GATES.

Diese Spalte ist in kubectl bis zu Version 1.12 nicht vorhanden. Ein Pod, für den der Status READY angegeben wird, weist möglicherweise ein fehlgeschlagenes Readiness-Gate auf. Verwenden Sie den folgenden Befehl, um dies zu prüfen:

kubectl get my-pod -o yaml

Die Readiness-Gates und der Status der einzelnen Gates werden in der Ausgabe aufgeführt.

Lösung

Prüfen Sie, ob das in der Pod-Spezifikation Ihres Deployments genannte Container-Image richtig funktioniert und auf Systemdiagnosen reagieren kann. Prüfen Sie, ob die Systemdiagnosen korrekt konfiguriert sind.

Bekannte Probleme

Beim containernativen Load-Balancing in Google Kubernetes Engine treten die folgenden bekannten Probleme auf:

Unvollständige automatische Speicherbereinigung

Google Kubernetes Engine führt für containernative Load-Balancer alle zwei Minuten eine automatische Speicherbereinigung aus. Wenn ein Cluster gelöscht wird, bevor Load-Balancer vollständig entfernt wurden, müssen Sie die NEGs des Load-Balancers manuell löschen.

Führen Sie folgenden Befehl aus, um die NEGs in Ihrem Projekt aufzulisten:

gcloud compute network-endpoint-groups list

Suchen Sie in der Befehlsausgabe nach den relevanten NEGs.

Führen Sie zum Löschen einer NEG folgenden Befehl aus, wobei neg der Name der NEG ist:

gcloud compute network-endpoint-groups delete neg

Arbeitslast-Rollouts auf Endpunktweitergabe abstimmen

Wenn Sie eine Arbeitslast in Ihrem Cluster bereitstellen oder eine vorhandene Arbeitslast aktualisieren, kann der containernative Load-Balancer zur Weitergabe neuer Endpunkte mehr Zeit benötigen als für das Arbeitslast-Rollout erforderlich ist. Das im Rahmen dieser Anleitung bereitgestellte Beispiel-Deployment verwendet zwei Felder, um seine Einführung auf die Weitergabe von Endpunkten abzustimmen: terminationGracePeriodSeconds und minReadySeconds

terminationGracePeriodSeconds ermöglicht, dass der Pod richtig heruntergefahren wird. Dafür wird auf das Beenden von Verbindungen gewartet, nachdem ein Pod zum Löschen vorgemerkt wurde.

Mit minReadySeconds wird nach dem Erstellen eines Pods eine Latenzzeit hinzugefügt. Sie sollten einen Mindestzeitraum in Sekunden angeben, in dem sich ein neuer Pod ohne Absturz eines zugehörigen Containers im Status Ready befinden muss, um als verfügbar angesehen zu werden.

Für Ihre Arbeitslasten sollten Sie die Werte von minReadySeconds und terminationGracePeriodSeconds auf mindestens 60 Sekunden festlegen, damit der Dienst nicht aufgrund von Arbeitslast-Einführungen unterbrochen wird.

terminationGracePeriodSeconds ist in allen Pod-Spezifikationen verfügbar und minReadySeconds ist für Deployments und DaemonSets verfügbar.

Weitere Informationen zur Feinabstimmung von Rollouts finden Sie unter RollingUpdateStrategy.

initialDelaySeconds in Pod readinessProbe nicht berücksichtigt

Man könnte erwarten, dass die Konfigurationseinstellung initialDelaySeconds in der readinessProbe des Pods vom containernativen Load-Balancer berücksichtigt wird. readinessProbe wird jedoch von kubelet implementiert und die Konfigurationseinstellung initialDelaySeconds steuert die kubelet-Systemdiagnose, nicht den containernativen Load-Balancer. Das containernative Load-Balancing hat eine eigene Systemdiagnose für das Load-Balancing.

Nächste Schritte