HTTP-Anfrage-basierte automatische Skalierung auf K8S mit Prometheus und Keda auf CODE-DE

Der Kubernetes Pod-Auto-Scaler (HPA) verwendet standardmäßig CPU- und RAM-Metriken als Auslöser für die Erhöhung oder Verringerung der Anzahl von Pods. Dies ist zwar oft ausreichend, es kann jedoch Anwendungsfälle geben, in denen eine Skalierung anhand benutzerdefinierter Metriken bevorzugt wird.

KEDA ist ein Tool zur automatischen Skalierung auf der Grundlage von Ereignissen/Metriken, die von gängigen Quellen/Technologien wie Prometheus, Kafka, Postgres und vielen anderen bereitgestellt werden.

In diesem Artikel werden wir eine Beispielanwendung auf CODE-DE FRA1-1 Cloud bereitstellen. Wir sammeln HTTP-Anfragen von NGINX Ingress auf unserem Kubernetes-Cluster und wenden mithilfe von Keda mit Prometheus-Skalierer eine benutzerdefinierte HTTP-Anfrage-basierte Skalierung an.

Bemerkung

Wir werden NGINX web server verwenden, um die Anwendung zu demonstrieren, und NGINX ingress, um sie bereitzustellen und Metriken zu sammeln. Beachten Sie, dass NGINX web server und NGINX ingress zwei verschiedene Softwarekomponenten sind, die zwei unterschiedlichen Zwecken dienen.

Was wir behandeln werden

  • NGINX ingress auf dem Magnum-Cluster installieren

  • Prometheus installieren

  • Keda installieren

  • Bereitstellung einer Beispielanwendung

  • Bereitstellen unserer App ingress

  • Zugriff auf das Prometheus-Dashboard

  • KEDA ScaledObject bereitstellen

  • Test mit Locust

Voraussetzungen

No. 1 Konto

Sie benötigen ein Hosting-Konto mit Zugriff auf die Horizon-Schnittstelle: https://cloud.fra1-1.cloudferro.com/auth/login/?next=/.

Nr. 2 Erstellen eines neuen Kubernetes-Clusters ohne vorinstalliertes Magnum NGINX über die Horizon Oberfläche

Der standardmäßige NGINX-Ingress, der von Magnum über die Horizon GUI bereitgestellt wird, implementiert noch keinen Prometheus-Metrik-Export. Anstatt zu versuchen, den Magnum-Ingress für diesen Anwendungsfall zu konfigurieren, werden wir lieber einen neuen NGINX-Ingress installieren. Um Konflikte zu vermeiden, befolgen Sie am besten die folgenden Anweisungen auf einem Kubernetes-Cluster ohne Magnum NGINX, das von Horizon GUI vorinstalliert ist.

Nr. 3 kubectl zeigt auf den Kubernetes-Cluster

Der folgende Artikel enthält Optionen für die Erstellung eines neuen Clusters und die Aktivierung des Befehls kubectl:

Zugriff auf Kubernetes-Cluster nach der Bereitstellung mit Kubectl auf CODE-DE OpenStack Magnum.

Wie bereits erwähnt, erstellen Sie den Cluster ohne die NGINX-Ingress-Option zu installieren.

Nr. 4 Kenntnisse über den Einsatz von Helm-Diagrammen

Dieser Artikel führt Sie in die Helm-Diagramme für Kubernetes ein:

Einsatz von Helm Charts auf Magnum Kubernetes-Clustern auf der CODE-DE FRA1-1 Cloud

NGINX ingress auf Magnum-Cluster installieren

Bitte geben Sie die folgenden Befehle ein, um das Helm-Repository ingress-nginx herunterzuladen und dann das Diagramm zu installieren. Beachten Sie, dass wir einen benutzerdefinierten Namespace ingress-nginx verwenden und die Optionen zur Aktivierung von Prometheus-Metriken einstellen.

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

kubectl create namespace ingress-nginx

helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx \
--set controller.metrics.enabled=true \
--set-string controller.podAnnotations."prometheus\.io/scrape"="true" \
--set-string controller.podAnnotations."prometheus\.io/port"="10254"

Führen Sie nun den folgenden Befehl aus, um die externe IP-Adresse des Ingress-Controllers abzurufen, die von den in den weiteren Schritten dieses Artikels erstellten Ingress-Ressourcen verwendet werden soll.

$ kubectl get services -n ingress-nginx
NAME                      TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)                      AGE
ingress-nginx-controller  LoadBalancer   10.254.118.18    64.225.135.67   80:31573/TCP,443:30786/TCP   26h

Wir erhalten 64.225.135.67. Verwenden Sie anstelle dieses Wertes den EXTERNAL-IP-Wert, den Sie nach Ausführung des obigen Befehls in Ihrem Terminal erhalten.

Prometheus installieren

Um Prometheus zu installieren, führen Sie bitte den folgenden Befehl auf Ihrem Cluster aus:

kubectl apply --kustomize github.com/kubernetes/ingress-nginx/deploy/prometheus/

Beachten Sie, dass dies eine Prometheus-Installation ist, die für NGINX Ingress angepasst wurde und standardmäßig in den Namespace ingress-nginx installiert wird, so dass kein Namespace-Flag angegeben oder erstellt werden muss.

Keda installieren

Mit den folgenden Schritten erstellen Sie einen separaten Namespace für Keda-Artefakte, laden das Repo herunter und installieren die Keda-Core-Karte:

kubectl create namespace keda

helm repo add kedacore https://kedacore.github.io/charts
helm repo update

helm install keda kedacore/keda --version 2.3.0 --namespace keda

Eine Beispielanwendung bereitstellen

Nachdem die obigen Schritte abgeschlossen sind, können wir eine einfache Anwendung bereitstellen. Es handelt sich um einen NGINX-Webserver, der eine einfache „Willkommen bei nginx!“-Seite bereitstellt. Beachten Sie, dass wir ein Deployment erstellen und dieses Deployment dann als Dienst vom Typ ClusterIP bereitstellen. Erstellen Sie eine Datei app-deployment.yaml in Ihrem bevorzugten Editor:

app-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    app: nginx
  type: ClusterIP
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

Wenden Sie es dann mit dem unten stehenden Befehl an:

kubectl apply -f app-deployment.yaml -n ingress-nginx

Wir stellen diese Anwendung im Namespace ingress-nginx bereit, in dem auch die Ingress-Installation und Prometheus gehostet werden. Für Produktionsszenarien möchten Sie möglicherweise eine bessere Isolierung von Anwendung und Infrastruktur, was jedoch den Rahmen dieses Artikels sprengen würde.

Bereitstellen unserer App ingress

Unsere Anwendung läuft bereits und ist in unserem Cluster verfügbar, aber wir wollen sie auch öffentlich zugänglich machen. Zu diesem Zweck werden wir NGINX ingress verwenden, das auch als Proxy für die Registrierung der Anfragemetriken dienen wird. Erstellen Sie eine Datei app-ingress.yaml mit dem folgenden Inhalt:

app-ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: "64.225.135.67.nip.io"
    http:
      paths:
      - backend:
          service:
            name: nginx
            port:
              number: 80
        path: /app
        pathType: Prefix

Dann anwenden mit: .. code:

kubectl apply -f app-ingress.yaml -n ingress-nginx

Nach einiger Zeit können Sie eine öffentliche IP-Adresse erhalten, unter der die App verfügbar ist:

$ kubectl get ingress -n ingress-nginx
NAME           CLASS   HOSTS                  ADDRESS         PORTS   AGE
app-ingress    nginx   64.225.135.67.nip.io   64.225.135.67   80      18h

Nachdem Sie die IP-Adresse mit dem Präfix eingegeben haben (ersetzen Sie diese durch Ihre eigene freie IP mit dem Suffix /app), wird die App angezeigt. Wir verwenden den Dienst nip.io, der als DNS-Resolver fungiert, so dass für die Zwecke der Demo keine DNS-Einträge eingerichtet werden müssen.

../_images/welcome_nginx.png

Zugang zum Prometheus-Dashboard

Um auf das Prometheus-Dashboard zuzugreifen, können wir den laufenden Prometheus-Server auf unseren localhost port-weiterleiten. Dies könnte für die Fehlersuche nützlich sein. Wir haben den prometheus-server als NodePort Dienst laufen, der wie unten beschrieben überprüft werden kann:

$ kubectl get services -n ingress-nginx
NAME                                 TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)                      AGE
ingress-nginx-controller             LoadBalancer   10.254.3.172     64.225.135.67   80:30881/TCP,443:30942/TCP   26h
ingress-nginx-controller-admission   ClusterIP      10.254.51.201    <none>          443/TCP                      26h
ingress-nginx-controller-metrics     ClusterIP      10.254.15.196    <none>          10254/TCP                    26h
nginx                                ClusterIP      10.254.160.207   <none>          80/TCP                       25h
prometheus-server                    NodePort       10.254.24.85     <none>          9090:32051/TCP               26h

Mit dem folgenden Befehl wird ein Port-Forward zum localhost eingerichtet:

kubectl port-forward deployment/prometheus-server 9090:9090 -n ingress-nginx

Geben Sie dann localhost:9090 in Ihren Browser ein, und Sie sehen das Prometheus-Dashboard. In dieser Ansicht können wir verschiedene von nginx-ingress bereitgestellte Metriken sehen. Dies kann überprüft werden, indem man „nginx-ingress“ in die Suchleiste eingibt, woraufhin verschiedene Metriken angezeigt werden.

../_images/prometheus-dashboard_9090.png

Einsatz von KEDA ScaledObject

Keda ScaledObject ist eine benutzerdefinierte Ressource, die die Skalierung unserer Anwendung auf der Grundlage benutzerdefinierter Metriken ermöglicht. Im YAML-Manifest legen wir fest, was skaliert werden soll (das Nginx-Deployment), was die Bedingungen für die Skalierung sind und die Definition und Konfiguration des Triggers, in diesem Fall Prometheus. Bereiten Sie eine Datei scaled-object.yaml mit dem folgenden Inhalt vor:

scaled-object.yaml

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: prometheus-scaledobject
  namespace: ingress-nginx
  labels:
    deploymentName: nginx
spec:
  scaleTargetRef:
    kind: Deployment
    name: nginx # name of the deployment, must be in the same namespace as ScaledObject
  minReplicaCount: 1
  pollingInterval: 15
  triggers:
  - type: prometheus
    metadata:
      serverAddress: http://prometheus-server.ingress-nginx.svc.cluster.local:9090
      metricName: nginx_ingress_controller_requests
      threshold: '100'
      query: sum(rate(nginx_ingress_controller_requests[1m]))

Die genaue Definition des ScaledObjects ist in der Keda-Dokumentation nachzulesen, wir belassen hier viele Standardeinstellungen.

Wir verwenden die Metrik nginx-ingress-controller-requests für die Skalierung. Diese Metrik wird erst im Prometheus-Dashboard angezeigt, wenn die Anfragen beginnen, unseren App-Dienst zu erreichen. Wir setzen den Schwellenwert auf 100 und die Zeit auf 1 Minute, so dass die Skalierung ausgelöst wird, wenn mehr als 100 Anfragen pro Pod in einer Minute eingehen.

kubectl apply -f scaled-object.yaml -n ingress-nginx

Test mit Heuschrecke

Wir können nun testen, ob die Skalierung wie erwartet funktioniert. Dazu verwenden wir Locust, ein Tool für Lasttests. Um Locust schnell als LoadBalancer-Diensttyp einzusetzen, geben Sie die folgenden Befehle ein:

kubectl create deployment locust --image paultur/locustproject:latest
kubectl expose deployment locust --type LoadBalancer --port 80 --target-port 8089

Nach ein paar Minuten ist der LoadBalancer erstellt und Locust wird ausgesetzt:

$ kubectl get services
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
kubernetes   ClusterIP      10.254.0.1     <none>           443/TCP        28h
locust       LoadBalancer   10.254.88.89   64.225.132.243   80:31287/TCP   4m19s

Geben Sie das Locust UI im Browser über die EXTERNAL-IP ein. Es kann nur 64.225.132.243 oder 64.225.132.243.nip.io sein, einer dieser Werte wird sicher funktionieren. Klicken Sie dann auf „Start Swarming“, um Mock-Anfragen an den öffentlichen Endpunkt unserer App zu initiieren:

../_images/locust_test.png

Mit der Standardeinstellung und sogar einem einzigen Benutzer wird Locust sofort Hunderte von Anfragen ausschwärmen lassen. Das Tuning von Locust ist nicht Gegenstand dieses Artikels, aber wir können die Auswirkungen schnell sehen. Die zusätzlichen Pod-Replikate werden erzeugt:

$ kubectl get pods -n ingress-nginx
NAME                                        READY   STATUS              RESTARTS   AGE
ingress-nginx-controller-557bf68967-h9zf5   1/1     Running             0          27h
nginx-85b98978db-2kjx6                      1/1     Running             0          30s
nginx-85b98978db-2kxzz                      1/1     Running             0          61s
nginx-85b98978db-2t42c                      1/1     Running             0          31s
nginx-85b98978db-2xdzw                      0/1     ContainerCreating   0          16s
nginx-85b98978db-2zdjm                      1/1     Running             0          30s
nginx-85b98978db-4btfm                      1/1     Running             0          30s
nginx-85b98978db-4mmlz                      0/1     ContainerCreating   0          16s
nginx-85b98978db-4n5bk                      1/1     Running             0          46s
nginx-85b98978db-525mq                      1/1     Running             0          30s
nginx-85b98978db-5czdf                      1/1     Running             0          46s
nginx-85b98978db-5kkgq                      0/1     ContainerCreating   0          16s
nginx-85b98978db-5rt54                      1/1     Running             0          30s
nginx-85b98978db-5wmdk                      1/1     Running             0          46s
nginx-85b98978db-6tc6p                      1/1     Running             0          77s
nginx-85b98978db-6zcdw                      1/1     Running             0          61s
...

Abkühlung

Nachdem Sie in Locust auf „Stop“ geklickt haben, werden die Pods auf ein Replikat heruntergefahren, entsprechend dem Wert des Parameters coolDownPeriod, der im Keda ScaledObject definiert ist. Sein Standardwert ist 300 Sekunden. Wenn Sie ihn ändern möchten, verwenden Sie den Befehl

kubectl edit scaledobject prometheus-scaledobject -n ingress-nginx