Auto-Scaling von Kubernetes-Anwendungen mit Prometheus und KEDA

Auto-Scaling von Kubernetes-Anwendungen mit Prometheus und KEDABallonmann von Cimuanos

Skalierbarkeit ist eine entscheidende Anforderung für Cloud-Anwendungen. Mit Kubernetes ist es so einfach, eine Anwendung zu skalieren, wie die Anzahl der Repliken für das entsprechende Deployment zu erhöhen oder ReplicaSet — aber das ist ein manueller Prozess.

Kubernetes ermöglicht das automatische Skalieren von Anwendungen (d.h. Pods in einem Deployment oder ReplicaSet) deklarativ mithilfe der Spezifikation des Horizontal Pod Autoscaler. Standardmäßig ist das Kriterium für das automatische Skalieren eine Metrik zur Nutzung der CPU (Ressourcenschlüssel), aber es können benutzerdefinierte Metriken und Metriken von externen Quellen integriert werden.

Team Kubernetes aaS von Mail.ru übersetzte einen Artikel darüber, wie externe Metriken zum automatischen Skalieren einer Kubernetes-Anwendung verwendet werden können. Um zu zeigen, wie alles funktioniert, verwendet der Autor Metriken zu HTTP-Anfragen, die von Prometheus erfasst werden.

Anstelle des horizontalen automatischen Skalierens von Pods wird das Kubernetes Event Driven Autoscaling (KEDA) verwendet — ein Open-Source-Kubernetes-Operator. Er integriert sich von Anfang an mit dem Horizontal Pod Autoscaler, um ein nahtloses automatisches Skalieren (einschließlich Hoch- und Herunterskalierung) für ereignisgesteuerte Workloads zu ermöglichen. Der Code ist verfügbar unter GitHub.

Kurze Übersicht über die Funktionsweise des Systems

Auto-Scaling von Kubernetes-Anwendungen mit Prometheus und KEDA

Das Diagramm zeigt eine kurze Beschreibung, wie alles funktioniert:

  1. Die Anwendung liefert Metriken über die Anzahl der HTTP-Zugriffe im Prometheus-Format.
  2. Prometheus ist konfiguriert, um diese Metriken zu sammeln.
  3. Der Prometheus-Skalierer in KEDA ist so konfiguriert, dass er die Anwendung basierend auf der Anzahl der HTTP-Zugriffe automatisch skaliert.

Jetzt werde ich jedes Element im Detail erläutern.

KEDA und Prometheus

Prometheus ist ein Open-Source-Toolkit zur Überwachung und Benachrichtigung von Systemen, Teil Cloud Native Computing Foundation. Er sammelt Metriken aus verschiedenen Quellen und speichert sie als Zeitreihendaten. Zur Visualisierung der Daten können Grafana oder andere Visualisierungstools verwendet werden, die mit der Kubernetes-API arbeiten.

KEDA unterstützt das Konzept des Skalierers - er fungiert als Brücke zwischen KEDA und dem externen System. Die Implementierung des Skalierers ist spezifisch für jedes Zielsystem und extrahiert Daten daraus. Anschließend verwendet KEDA diese Daten zur Verwaltung der automatischen Skalierung.

Skalierer unterstützen mehrere Datenquellen, wie z.B. Kafka, Redis, Prometheus. Das bedeutet, dass KEDA für das automatische Skalieren von Kubernetes-Deployments verwendet werden kann, wobei die Prometheus-Metriken als Kriterien dienen.

Testanwendung

Die Test-Golang-Anwendung bietet HTTP-Zugriff und erfüllt zwei wichtige Funktionen:

  1. Verwendet die Client-Bibliothek Prometheus Go zur Instrumentierung der Anwendung und zur Bereitstellung der Metrik http_requests, die einen Zugriffszähler enthält. Der Endpunkt, an dem die Prometheus-Metriken verfügbar sind, befindet sich unter der URI /metrics.
    var httpRequestsCounter = promauto.NewCounter(prometheus.CounterOpts{
           Name: "http_requests",
           Help: "Anzahl der HTTP-Anfragen",
       })
    
  2. Als Antwort auf die Anfrage GET erhöht die Anwendung den Wert des Schlüssels (access_count) in Redis. Dies ist eine einfache Möglichkeit, die Arbeit als Teil des HTTP-Handlers auszuführen und die Prometheus-Metriken zu überprüfen. Der Wert der Metrik sollte gleich dem Wert sein access_count in Redis.
    func main() {
           http.Handle("/metrics", promhttp.Handler())
           http.HandleFunc("/test", func(w http.ResponseWriter, r 
    *http.Request) {
               defer httpRequestsCounter.Inc()
               count, err := client.Incr(redisCounterName).Result()
               if err != nil {
                   fmt.Println("Kann den Redis-Zähler nicht erhöhen", err)
                   os.Exit(1)
               }
               resp := "Zugriff am " + time.Now().String() + "nZugriffsanzahl " + strconv.Itoa(int(count))
               w.Write([]byte(resp))
           })
           http.ListenAndServe(":8080", nil)
       }
    

Die Anwendung wird in Kubernetes über Deploymentbereitgestellt. Es wird auch ein Dienst erstellt, ClusterIP, der dem Prometheus-Server ermöglicht, die Anwendungsmetriken zu erhalten.

Hier Bereitstellungsmanifest für die Anwendung.

Prometheus-Server

Das Bereitstellungsmanifest für Prometheus besteht aus:

  • ConfigMap — zur Übermittlung der Prometheus-Konfiguration;
  • Deployment — für die Bereitstellung von Prometheus im Kubernetes-Cluster;
  • ClusterIP — Dienst für den Zugang zur Prometheus-UI;
  • Clusterrolle, ClusterRoleBinding und ServiceAccount — für die Auto-Discovery der Dienste in Kubernetes.

Hier Manifest zum Starten von Prometheus.

KEDA Prometheus ScaledObject

Der Skalierer fungiert als Brücke zwischen KEDA und dem externen System, aus dem Metriken abgerufen werden müssen. ScaledObject — eine anpassbare Ressource, die bereitgestellt werden muss, um das Deployment mit der Ereignisquelle zu synchronisieren, in diesem Fall mit Prometheus.

ScaledObject enthält Informationen zur Skalierung des Deployments, Metadaten zur Ereignisquelle (z.B. Verbindungsgeheimnisse, Warteschlangenname), Abfrageintervall, Erholungszeitraum und andere Daten. Es führt zu der entsprechenden Autoskalierungsressource (Definition HPA) für das Skalieren des Deployments.

Wenn das Objekt ScaledObject wird gelöscht, das entsprechende HPA wird zurückgesetzt.

Hier ist die Definition ScaledObject für unser Beispiel, es wird ein Scaler verwendet Prometheus:

apiVersion: keda.k8s.io/v1alpha1
kind: ScaledObject
metadata:
 name: prometheus-scaledobject
 namespace: default
 labels:
   deploymentName: go-prom-app
spec:
 scaleTargetRef:
   deploymentName: go-prom-app
 pollingInterval: 15
 cooldownPeriod:  30
 minReplicaCount: 1
 maxReplicaCount: 10
 triggers:
 - type: prometheus
   metadata:
     serverAddress: 
http://prometheus-service.default.svc.cluster.local:9090
     metricName: access_frequency
     threshold: '3'
     query: sum(rate(http_requests[2m]))

Beachten Sie die folgenden Punkte:

  1. Es verweist auf Deployment mit dem Namen go-prom-app.
  2. Der Typ des Triggers ist Prometheus. Die Adresse des Prometheus-Servers wird zusammen mit dem Metriknamen, dem Schwellenwert und der PromQL-Abfrage, die verwendet wird. Die PromQL-Abfrage ist sum(rate(http_requests[2m])).
  3. Laut pollingInterval, KEDA fragt das Ziel alle fünfzehn Sekunden bei Prometheus ab. Es wird mindestens ein Pod unterstützt (minReplicaCount), und die maximale Anzahl der Pods liegt bei maxReplicaCount (in diesem Beispiel zehn).

Es kann auf minReplicaCount null gesetzt werden. In diesem Fall aktiviert KEDA das Deployment von null auf eins und stellt dann HPA für die weitere Automatisierung bereit. Es ist auch möglich, in umgekehrter Reihenfolge zu skalieren, also von eins auf null. In unserem Beispiel haben wir null nicht gewählt, da es sich um einen HTTP-Dienst handelt und nicht um ein Abfragesystem.

Die Magie des automatischen Skalierens

Der Schwellenwert wird als Auslöser zum Skalieren des Deployments verwendet. In unserem Beispiel gibt die PromQL-Abfrage sum(rate(http_requests[2m])) einen aggregierten Wert der Rate von HTTP-Anfragen (Anzahl der Anfragen pro Sekunde) zurück, die in den letzten zwei Minuten gemessen wurde.

Da der Schwellenwert drei beträgt, wird es einen Pod geben, solange der Wert sum(rate(http_requests[2m])) weniger als drei ist. Wenn der Wert jedoch steigt, wird jedes Mal ein zusätzlicher Pod hinzugefügt, wenn sum(rate(http_requests[2m])) er um drei ansteigt. Zum Beispiel, wenn der Wert von 12 auf 14 steigt, beträgt die Anzahl der Pods vier.

Lassen Sie uns jetzt versuchen, es einzurichten!

Vorbereitende Konfiguration

Alles, was Sie brauchen, ist ein Kubernetes-Cluster und ein eingerichtetes Tool kubectl. In diesem Beispiel wird ein Cluster verwendet minikube, aber Sie können jeden anderen verwenden. Für den Clusteraufbau gibt es Anleitung.

Installieren Sie die neueste Version auf Mac:

curl -Lo minikube 
https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 
&& chmod +x minikube
sudo mkdir -p /usr/local/bin/
sudo install minikube /usr/local/bin/

Installieren Sie kubectl, um Zugriff auf den Kubernetes-Cluster zu erhalten.

Neueste Version auf Mac installieren:

curl -LO 
"https://storage.googleapis.com/kubernetes-release/release/$(curl -s
https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl"
chmod +x ./kubectl
sudo mv ./kubectl /usr/local/bin/kubectl
kubectl version

KEDA-Installation

Sie können KEDA auf mehrere Arten bereitstellen, die im Dokumentationaufgelistet sind. Ich verwende ein monolithisches YAML:

kubectl apply -f
https://raw.githubusercontent.com/kedacore/keda/master/deploy/KedaScaleController.yaml

KEDA und ihre Komponenten werden im Namensraum kedainstalliert. Der Befehl zur Überprüfung:

kubectl get pods -n keda

Warten Sie, bis der KEDA-Operator-Pod startet — in den Running Stateübergeht. Und fahren Sie dann fort.

Installation von Redis mit Helm

Wenn Sie Helm nicht installiert haben, verwenden Sie dieses Handbuch.Befehl zur Installation auf Mac:

brew install kubernetes-helm
helm init --history-max 200

helm init initialisiert die lokale Befehlszeilenoberfläche und installiert auch Tiller im Kubernetes-Cluster.

kubectl get pods -n kube-system | grep tiller

Warten Sie, bis der Tiller-Pod in den Zustand Running übergeht.

Hinweis des Übersetzers: Der Autor verwendet Helm@2, das die Installation der Serverkomponente Tiller erfordert. Aktuell ist Helm@3, für den kein Serverteil benötigt wird.

Nach der Installation von Helm reicht ein Befehl aus, um Redis zu starten:

helm install --name redis-server --set cluster.enabled=false --set 
usePassword=false stable/redis

Stellen Sie sicher, dass Redis erfolgreich gestartet wurde:

kubectl get pods/redis-server-master-0

Warten Sie, bis der Redis-Pod in den Zustand Laufend.

Anwendungsbereitstellung

Befehl zur Bereitstellung:

kubectl apply -f go-app.yaml

//output
deployment.apps/go-prom-app created
service/go-prom-app-service created

Überprüfen Sie, dass alles gestartet wurde:

kubectl get pods -l=app=go-prom-app

Warten Sie, bis Redis in den Zustand Laufend.

Bereitstellung des Prometheus-Servers

Das Manifest von Prometheus verwendet Kubernetes Service Discovery für Prometheus. Es ermöglicht das dynamische Entdecken von Anwendungs-Pods basierend auf dem Servicelabel.

kubernetes_sd_configs:
   - role: service
   relabel_configs:
   - source_labels: [__meta_kubernetes_service_label_run]
     regex: go-prom-app-service
     action: keep

Für die Bereitstellung:

kubectl apply -f prometheus.yaml

//output
clusterrole.rbac.authorization.k8s.io/prometheus created
serviceaccount/default configured
clusterrolebinding.rbac.authorization.k8s.io/prometheus created
configmap/prom-conf created
deployment.extensions/prometheus-deployment created
service/prometheus-service created

Überprüfen Sie, dass alles gestartet wurde:

kubectl get pods -l=app=prometheus-server

Warten Sie, bis der Prometheus-Pod in den Zustand Laufend.

Verwenden Sie kubectl port-forward zum Zugriff auf die Benutzeroberfläche von Prometheus (oder den API-Server) unter http://localhost:9090.

kubectl port-forward service/prometheus-service 9090

Bereitstellung der KEDA-Autoskalierungs-Konfiguration

Befehl zur Erstellung ScaledObject:

kubectl apply -f keda-prometheus-scaledobject.yaml

Überprüfen Sie die Protokolle des KEDA-Operators:

KEDA_POD_NAME=$(kubectl get pods -n keda 
-o=jsonpath='{.items[0].metadata.name}')
kubectl logs $KEDA_POD_NAME -n keda

Das Ergebnis sieht ungefähr so aus:

time="2019-10-15T09:38:28Z" level=info msg="Skalierungsobjekt beobachten:
default/prometheus-scaledobject"
time="2019-10-15T09:38:28Z" level=info msg="HPA mit 
Namespace default und Name keda-hpa-go-prom-app erstellt"

Überprüfen Sie die Anwendung Pods. Es sollte ein Exemplar laufen, da minReplicaCount es gleich 1 ist:

kubectl get pods -l=app=go-prom-app

Überprüfen Sie, ob der HPA-Ressource erfolgreich erstellt wurde:

kubectl get hpa

Sie sollten etwas sehen wie:

NAME                   REFERENCE                TARGETS     MINPODS   MAXPODS   REPLICAS   AGE
keda-hpa-go-prom-app   Deployment/go-prom-app   0/3 (avg)   1         10        1          45s

Überprüfung der Funktionsfähigkeit: Zugriff auf die Anwendung

Um auf den REST-Endpunkt unserer Anwendung zuzugreifen, führen Sie aus:

kubectl port-forward service/go-prom-app-service 8080

Jetzt können Sie auf die Go-Anwendung unter der Adresse zugreifen http://localhost:8080. Führen Sie dazu den Befehl aus:

curl http://localhost:8080/test

Das Ergebnis sieht ungefähr so aus:

Zugriff am 2019-10-21 11:29:10.560385986 +0000 UTC 
m=+406004.817901246
Zugriffsanzahl 1

Überprüfen Sie zu diesem Zeitpunkt auch Redis. Sie werden sehen, dass der Schlüssel access_count auf 1 erhöht wurde:

kubectl exec -it redis-server-master-0 -- redis-cli get access_count
//output
"1"

Stellen Sie sicher, dass der Wert der Metrik http_requests derselbe ist:

curl http://localhost:8080/metrics | grep http_requests
//output
# HELP http_requests Anzahl der HTTP-Anfragen
# TYPE http_requests counter
http_requests 1

Lastenüberprüfung

Wir werden hey — ein Tool zur Lastgenerierung:

curl -o hey https://storage.googleapis.com/hey-release/hey_darwin_amd64 
&& chmod a+x hey

Sie können auch das Tool für Linux oder Windows.

Führen Sie es aus:

./hey http://localhost:8080/test

Standardmäßig sendet das Tool 200 Anfragen. Sie können dies über die Prometheus-Metriken und Redis überprüfen.

curl http://localhost:8080/metrics | grep http_requests
//output
# HELP http_requests Anzahl der HTTP-Anfragen
# TYPE http_requests counter
http_requests 201
kubectl exec -it redis-server-master-0 -- redis-cli get access_count
//output
201

Bestätigen Sie den Wert der tatsächlichen Metrik (zurückgegeben durch die PromQL-Abfrage):

curl -g 
'http://localhost:9090/api/v1/query?query=sum(rate(http_requests[2m]))'
//output
{"status":"success","data":{"resultType":"vector","result":[{"metric":{},"value":[1571734214.228,"1.686057971014493"]}]}}

In diesem Fall beträgt das tatsächliche Ergebnis 1,686057971014493 und wird im Feld angezeigt value. Das reicht nicht aus, um zu skalieren, da unser gesetzter Schwellenwert 3 beträgt.

Mehr Last!

Überwachen Sie in einem neuen Terminal die Anzahl der Anwendung Pods:

kubectl get pods -l=app=go-prom-app -w

Lassen Sie uns die Last mit folgendem Befehl erhöhen:

./hey -n 2000 http://localhost:8080/test

Nach einer gewissen Zeit werden Sie sehen, dass der HPA das Deployment skaliert und neue Pods startet. Überprüfen Sie den HPA, um dies zu bestätigen:

kubectl get hpa
NAME                   REFERENCE                TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
keda-hpa-go-prom-app   Deployment/go-prom-app   1830m/3 (avg)   1         10        6          4m22s

Wenn die Last unregelmäßig ist, wird das Deployment auf den Punkt verringert, an dem nur ein Pod läuft. Wenn Sie die tatsächliche Metrik (die von PromQL zurückgegeben wird) überprüfen möchten, verwenden Sie den Befehl:

curl -g 
'http://localhost:9090/api/v1/query?query=sum(rate(http_requests[2m]))'

Bereinigung

//Delete KEDA
kubectl delete namespace keda
//Delete the app, Prometheus server and KEDA scaled object
kubectl delete -f .
//Delete Redis
helm del --purge redis-server

Fazit

KEDA ermöglicht das automatische Skalieren Ihrer Kubernetes-Deployments (bis/ab null) basierend auf Daten von externen Metriken. Beispielsweise basierend auf Prometheus-Metriken, der Länge der Warteschlange in Redis, der Latenz des Verbrauchers in einem Kafka-Thema.

KEDA integriert sich mit einer externen Quelle und stellt deren Metriken über den Metrics Server für den Horizontal Pod Autoscaler bereit.

Viel Erfolg!

Was Sie sonst noch lesen sollten:

  1. Best Practices und Empfehlungen für den Betrieb von Containern und Kubernetes in Produktionsumgebungen.
  2. 90+ nützliche Tools für Kubernetes: Deployment, Management, Monitoring, Sicherheit und mehr.
  3. Unser Kanal Rund um Kubernetes auf Telegram.

Quelle: habr.com

60GB SSD 8Gb DDR4