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.
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.
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.
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:
- Es funktioniert nicht sofort - Sie müssen einen Metrics Server installieren, um die Metriken zu aggregieren und zu veröffentlichen.
- Er skaliert nicht auf null Replikate.
- 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:
- Ein Zahnsteinentferner
- Ein Metrik-Adapter
- Ein Controller
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.
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:
- Mit KEDA ist es nicht notwendig, eine neue Architektur zu erstellen oder ein SDK für die Bereitstellung der Anwendung zu verwenden.
- Serverlose Frameworks kümmern sich um die Weiterleitung und Bereitstellung von Anfragen. Sie schreiben nur die Logik.
- 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)
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?
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.Muito bom o conteudo!!!
Where does NodeBalancer show up in this configuration? Does LKE take over that job?
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.