Zum Inhalt springen
BlogContainer (Kubernetes, Docker)Skalierung von Kubernetes auf Null (und zurück)

Skalierung von Kubernetes auf Null (und zurück)

Bild zur Kubernetes-Skalierung

Dieser Beitrag ist Teil unserer Serie zur Skalierung von Kubernetes. Registrieren Sie sich um ihn live zu sehen oder auf die Aufzeichnung zuzugreifen, und sehen Sie sich unsere anderen Beiträge in dieser Serie an:

Die Reduzierung der Infrastrukturkosten läuft darauf hinaus, Ressourcen abzuschalten, wenn sie nicht genutzt werden. Die Herausforderung besteht jedoch darin, herauszufinden, wie man diese Ressourcen bei Bedarf automatisch einschalten kann. Gehen wir die erforderlichen Schritte durch, um einen Kubernetes-Cluster mit der Linode Kubernetes Engine (LKE) einzurichten und den Kubernetes Events-Driven Autoscaler (KEDA) zur Skalierung auf Null und zurück zu verwenden.

Warum Scale to Zero

Nehmen wir an, Sie führen eine relativ ressourcenintensive Anwendung auf Kubernetes aus, die nur während der Arbeitszeiten benötigt wird.

Vielleicht möchten Sie es ausschalten, wenn die Mitarbeiter das Büro verlassen, und wieder einschalten, wenn sie den Tag beginnen.

Skalierung von Kubernetes auf Null für Entwicklungs-Workloads, die nur während der Arbeitszeiten benötigt werden, im Gegensatz zu Produktions-Workloads, die rund um die Uhr laufen müssen.
Schalten Sie Ihre Entwicklungsumgebung ab, wenn niemand sie benutzt!

Sie könnten zwar einen CronJob verwenden, um die Instanz hoch- und runterzuskalieren, aber diese Lösung ist eine Notlösung, die nur nach einem vorgegebenen Zeitplan ausgeführt werden kann.

Was passiert am Wochenende? Und was ist mit Feiertagen? Oder wenn das Team krank ist?

Anstatt eine ständig wachsende Liste von Regeln zu erstellen, können Sie Ihre Workloads auf der Grundlage des Datenverkehrs skalieren. Wenn der Datenverkehr zunimmt, können Sie die Replikate skalieren. Wenn es keinen Datenverkehr gibt, können Sie die App abschalten. Wenn die App ausgeschaltet ist und eine neue Anfrage eingeht, startet Kubernetes mindestens eine Replik, um den Datenverkehr zu bewältigen.

Skalierung des Kubernetes-Diagramms - Skalierung und Nutzung von Ressourcen nur bei aktivem Datenverkehr.
Skalierung von Anwendungen auf Null, um Ressourcen zu sparen.

Als Nächstes wollen wir über das "Wie" sprechen:

  • den gesamten Verkehr zu Ihren Anwendungen abfangen;
  • den Verkehr zu überwachen; und
  • den Autoscaler einrichten, um die Anzahl der Replikate anzupassen oder die Anwendungen zu deaktivieren.

Wenn Sie den Code für dieses Tutorial lesen möchten, können Sie das auf LearnK8s GitHub tun.

Erstellen eines Clusters

Beginnen wir mit der Erstellung eines Kubernetes-Clusters.

Die folgenden Befehle können zur Erstellung des Clusters und zum Speichern der kubeconfig-Datei verwendet werden.

bash
$ linode-cli lke cluster-create \
 --label cluster-manager \
 --region eu-west \
 --k8s_version 1.23
 
$ linode-cli lke kubeconfig-view "insert cluster id here" --text | tail +2 | base64 -d > kubeconfig

Mit können Sie überprüfen, ob die Installation erfolgreich war:

bash
$ kubectl get pods -A --kubeconfig=kubeconfig

Das Exportieren der kubeconfig-Datei mit einer Umgebungsvariablen ist in der Regel bequemer.

Sie können dies mit tun:

bash
$ export KUBECONFIG=${PWD}/kubeconfig
$ kubectl get pods

Lassen Sie uns nun eine Anwendung bereitstellen.

Eine Anwendung bereitstellen

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
 name: podinfo
spec:
 selector:
   matchLabels:
     app: podinfo
 template:
   metadata:
     labels:
       app: podinfo
   spec:
     containers:
     - name: podinfo
       image: stefanprodan/podinfo
       ports:
       - containerPort: 9898
---
apiVersion: v1
kind: Service
metadata:
 name: podinfo
spec:
 ports:
   - port: 80
     targetPort: 9898
 selector:
   app: podinfo

Sie können die YAML-Datei mit übermitteln:

terminal|command=1|title=bash
$ kubectl apply -f 1-deployment.yaml

Und Sie können die App mit besuchen:

Öffnen Sie Ihren Browser auf localhost:8080.

bash
$ kubectl port-forward svc/podinfo 8080:80

Jetzt sollten Sie die App sehen.

Screenshot der podinfo-App im Browser.

Als nächstes installieren wir KEDA - den Autoscaler.

KEDA - der ereignisgesteuerte Kubernetes-Autoscaler

Kubernetes bietet den Horizontal Pod Autoscaler (HPA) als Controller, um Replikate dynamisch zu erhöhen und zu verringern.

Leider hat die HPA auch einige Nachteile:

  1. Es funktioniert nicht sofort - Sie müssen einen Metrics Server installieren, um die Metriken zu aggregieren und zu veröffentlichen.
  2. Er skaliert nicht auf null Replikate.
  3. Es skaliert die Replikate auf der Grundlage von Metriken und fängt den HTTP-Verkehr nicht ab.

Glücklicherweise müssen Sie nicht den offiziellen Autoscaler verwenden, sondern können stattdessen KEDA einsetzen.

KEDA ist ein Auto-Scaler, der aus drei Komponenten besteht:

  1. Ein Zahnsteinentferner
  2. Ein Metrik-Adapter
  3. Ein Controller
KEDA-Architekturdiagramm, das die Komponenten anzeigt.
KEDA-Architektur

Skalierer sind wie Adapter, die Metriken von Datenbanken, Message Brokern, Telemetriesystemen usw. sammeln können.

Der HTTP-Scaler ist beispielsweise ein Adapter, der HTTP-Datenverkehr abfangen und sammeln kann.

Ein Beispiel für einen Scaler mit RabbitMQ finden Sie hier.

Der Metrics Adapter ist dafür verantwortlich, die von den Scalern gesammelten Metriken in einem Format darzustellen, das von der Kubernetes-Metriken-Pipeline genutzt werden kann.

Und schließlich klebt der Controller alle Komponenten zusammen:

  • Er sammelt die Metriken mithilfe des Adapters und stellt sie der Metrik-API zur Verfügung.
  • Sie registriert und verwaltet die KEDA-spezifischen benutzerdefinierten Ressourcendefinitionen (Custom Resource Definitions, CRDs), d. h. ScaledObject, TriggerAuthentication usw.
  • Er erstellt und verwaltet den Horizontal Pod Autoscaler in Ihrem Namen.

Das ist die Theorie, aber schauen wir mal, wie es in der Praxis funktioniert.

Ein schnellerer Weg zur Installation des Controllers ist die Verwendung von Helm.

Die Installationsanweisungen finden Sie auf der offiziellen Helm-Website.

bash
$ helm repo add kedacore https://kedacore.github.io/charts
$ helm install keda kedacore/keda

KEDA enthält standardmäßig keinen HTTP-Skalierer, Sie müssen ihn also separat installieren:

bash
$ helm install http-add-on kedacore/keda-add-ons-http

Jetzt sind Sie bereit, die Anwendung zu skalieren.

Festlegen einer Autoskalierungsstrategie

Das KEDA HTTP Add-on stellt ein CRD zur Verfügung, in dem Sie beschreiben können, wie Ihre Anwendung skaliert werden soll.

Schauen wir uns ein Beispiel an:

yaml
kind: HTTPScaledObject
apiVersion: http.keda.sh/v1alpha1
metadata:
   name: podinfo
spec:
   host: example.com
   targetPendingRequests: 100
   scaleTargetRef:
       deployment: podinfo
       service: podinfo
       port: 80
   replicas:
       min: 0
       max: 10

Diese Datei weist die Abfangjäger an, Anfragen für example.com an den podinfo-Dienst weiterzuleiten.

KEDA-Autoskalierungsstrategie für Kubernetes. Eingehender Datenverkehr erreicht den KEDA HTTP-Interceptor, bevor er den Kubernetes-API-Server erreicht.
KEDA und der HTTP-Interceptor.

Sie enthält auch den Namen des Einsatzes, der skaliert werden soll - in diesem Fall podinfo.

Übermitteln wir die YAML an den Cluster mit:

bash
$ kubectl apply -f scaled-object.yaml

Sobald Sie die Definition eingereicht haben, wird der Pod gelöscht!

Aber warum?

Nachdem ein HTTPScaledObject erstellt wurde, skaliert KEDA die Bereitstellung sofort auf Null, da kein Datenverkehr stattfindet.

Sie müssen HTTP-Anfragen an die Anwendung senden, um sie zu skalieren.

Testen wir dies, indem wir uns mit dem Dienst verbinden und eine Anfrage stellen.

bash
$ kubectl port-forward svc/podinfo 8080:80

Der Befehl bleibt hängen!

Das macht Sinn, denn es gibt keine Pods, die die Anfrage bedienen könnten.

Aber warum skaliert Kubernetes die Bereitstellung nicht auf 1?

Prüfung des KEDA Abfangjägers

Ein Kubernetes-Dienst namens keda-add-ons-http-interceptor-proxy wurde erstellt, als Sie Helm zur Installation des Add-ons verwendet haben.

Damit die automatische Skalierung ordnungsgemäß funktioniert, muss der HTTP-Verkehr zuerst durch diesen Dienst geleitet werden.
Sie können verwenden kubectl port-forward um es zu testen:

shell
$ kubectl port-forward svc/keda-add-ons-http-interceptor-proxy 8080:8080

Dieses Mal können Sie die URL nicht in Ihrem Browser aufrufen.

Ein einziger KEDA HTTP-Interceptor kann mehrere Einsätze bewältigen.

Woher weiß es also, wohin es den Verkehr leiten soll?

yaml
kind: HTTPScaledObject
apiVersion: http.keda.sh/v1alpha1
metadata:
   name: podinfo
spec:
   host: example.com
   targetPendingRequests: 100
   scaleTargetRef:
       deployment: podinfo
       service: podinfo
       port: 80
   replicas:
       min: 0
       max: 10

Das HTTPScaledObject hat ein Host-Feld, das genau dafür verwendet wird.

In diesem Beispiel wird angenommen, dass die Anfrage von example.com kommt.

Sie können dies tun, indem Sie den Host-Header setzen:

bash
$ curl localhost:8080 -H 'Host: example.com'

Sie werden eine Antwort erhalten, wenn auch mit einer leichten Verzögerung.

Wenn Sie sich die Pods ansehen, werden Sie feststellen, dass die Bereitstellung auf ein einziges Replikat skaliert wurde:

bash
$ kubectl get pods

Was ist also gerade passiert?

Wenn Sie den Datenverkehr an den KEDA-Dienst weiterleiten, verfolgt der Interceptor die Anzahl der ausstehenden HTTP-Anfragen, auf die noch keine Antwort eingegangen ist.

Der KEDA-Skalierer überprüft regelmäßig die Größe der Warteschlange des Interceptors und speichert die Metriken.

Der KEDA-Controller überwacht die Metriken und erhöht oder verringert die Anzahl der Replikate je nach Bedarf. In diesem Fall steht eine einzige Anforderung an - genug für den KEDA-Controller, um die Bereitstellung auf eine einzige Replik zu skalieren.

Sie können den Status der Warteschlange für ausstehende HTTP-Anfragen eines einzelnen Interceptors mit abrufen:

bash
$ kubectl proxy &
$ curl -L localhost:8001/api/v1/namespaces/default/services/keda-add-ons-http-interceptor-admin:9090/proxy/queue
{"example.com":0,"localhost:8080":0}

Aufgrund dieses Designs müssen Sie darauf achten, wie Sie den Verkehr zu Ihren Anwendungen leiten.

KEDA kann den Verkehr nur skalieren, wenn er abgefangen werden kann.

Wenn Sie einen vorhandenen Ingress-Controller haben und diesen für die Weiterleitung des Datenverkehrs an Ihre Anwendung verwenden möchten, müssen Sie das Ingress-Manifest ändern, um den Datenverkehr an den HTTP-Zusatzdienst weiterzuleiten.

Schauen wir uns ein Beispiel an.

Kombination des KEDA HTTP Add-On mit dem Ingress

Sie können den nginx-ingress Controller mit Helm installieren:

bash
$ helm upgrade --install ingress-nginx ingress-nginx \
 --repo https://kubernetes.github.io/ingress-nginx \
 --namespace ingress-nginx --create-namespace

Schreiben wir ein Ingress-Manifest, um den Verkehr zu podinfo zu leiten:

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
 name: podinfo
spec:
 ingressClassName: nginx
 rules:
 - host: example.com
   http:
     paths:
     - path: /
       pathType: Prefix
       backend:
         service:
           name: keda-add-ons-http-interceptor-proxy # <- this
           port:
             number: 8080

Sie können die IP des Load Balancers mit abrufen:

bash
LB_IP=$(kubectl get services -l "app.kubernetes.io/component=controller" -o jsonpath="{.items[0].status.loadBalancer.ingress
[0].ip}" -n ingress-nginx)

Mit können Sie schließlich eine Anfrage an die App stellen:

bash
curl $LB_IP -H "Host: example.com"

Es hat geklappt!

Wenn Sie lange genug warten, werden Sie feststellen, dass der Einsatz schließlich auf Null zurückgeht.

Was bedeutet das im Vergleich zu Serverless auf Kubernetes?

Es gibt mehrere wesentliche Unterschiede zwischen diesem Setup und einem serverlosen Framework auf Kubernetes wie OpenFaaS:

  1. Mit KEDA ist es nicht notwendig, eine neue Architektur zu erstellen oder ein SDK für die Bereitstellung der Anwendung zu verwenden.
  2. Serverlose Frameworks kümmern sich um die Weiterleitung und Bereitstellung von Anfragen. Sie schreiben nur die Logik.
  3. Bei KEDA sind die Bereitstellungen normale Container. Bei einem serverlosen Framework ist das nicht immer der Fall.

Möchten Sie diese Skalierung in Aktion sehen? Melden Sie sich für unsere Webinarreihe zur Skalierung von Kubernetes an.

Kommentare (5)

  1. Author Photo

    Very nice tutorial. In the case without the nginx ingress, can you explain how to access from the outside, instead of the localhost? I tried to use a NodePort service, but the port gets closed when the Interceptor is installed. The Interceptor proxy is a ClusterIP service. How can we access it from the outside? Is there any sort of kubectl port forwarding instruction?

    • Maddie Presland

      Hi Rui! I forwarded your question to Daniele and here is his response:

      It should work with NodePort, but you have to set the right header (i.e. Host: example.com ) when you make the request. There is no way for the interceptor to decide where the traffic should go without that.

  2. Author Photo

    Muito bom o conteudo!!!

  3. Author Photo

    Where does NodeBalancer show up in this configuration? Does LKE take over that job?

    • tlambert

      Hi Lee – The NodeBalancer is created during the installation of the nginx-ingress controller. For a more detailed explanation of this process you can check out our guide titled Deploying NGINX Ingress on Linode Kubernetes Engine.

      Once the NodeBalancer is provisioned it is controlled via LKE. We don’t recommend configuring the settings of your LKE NodeBalancers through the Cloud Manager.

Kommentar abgeben

Ihre E-Mail Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit *gekennzeichnet