Mit KEDA auf null skalieren

In dieser Anleitung wird gezeigt, wie Sie Ihre GKE-Arbeitslasten mit KEDA auf null Pods skalieren. Durch das Skalieren der Bereitstellungen auf null Pods werden in Zeiten der Inaktivität (z. B. an Wochenenden und außerhalb der Bürozeiten) oder für intermittierende Arbeitslasten wie periodische Jobs Ressourcen gespart.

KEDA installieren

KEDA ist eine Komponente, die das horizontale Pod-Autoscaling von Kubernetes ergänzt. Mit KEDA können Sie ein Deployment auf null Pods und von null Pods auf einen Pod skalieren. Ein Deployment ist ein Kubernetes-API-Objekt, mit dem Sie mehrere Replikate von Pods ausführen können, die auf die Knoten in einem Cluster verteilt sind. Der standardmäßige Algorithmus für horizontales Pod-Autoscaling wird angewendet, nachdem GKE mindestens einen Pod erstellt hat.

Nachdem GKE das Deployment auf null Pods skaliert hat, kann das Autoscaling nicht auf Pod-Messwerte wie die CPU-Auslastung zurückgreifen, da keine Pods ausgeführt werden. Daher können mit KEDA Messwerte, die von außerhalb des Clusters stammen, über eine Implementierung der Kubernetes External Metrics API abgerufen werden. Mit dieser API können Sie das automatische Skalieren basierend auf Messwerten wie der Anzahl der ausstehenden Nachrichten in einem Pub/Sub-Abo durchführen. Eine Liste aller unterstützten Messwertquellen finden Sie in der KEDA-Dokumentation.

Installieren Sie KEDA auf Ihrem Cluster mit Helm oder mit kubectl.

Helm

Führen Sie die folgenden Befehle aus, um das KEDA-Helm-Repository hinzuzufügen, das KEDA-Helm-Diagramm zu installieren und dem KEDA-Dienstkonto Lesezugriff auf Cloud Monitoring zu gewähren:

helm repo add kedacore https://kedacore.github.io/charts
helm repo update
helm install keda kedacore/keda --create-namespace --namespace keda

gcloud projects add-iam-policy-binding projects/${PROJECT_ID} \
     --role roles/monitoring.viewer \
     --member=principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/keda/sa/keda-operator

Mit diesem Befehl werden auch Autorisierungsregeln eingerichtet, für die der Cluster mit der Identitätsföderation von Arbeitslasten für GKE eingerichtet sein muss.

kubectl

Führen Sie die folgenden Befehle aus, um KEDA mit kubectl apply zu installieren und dem KEDA-Dienstkonto Lesezugriff auf Cloud Monitoring zu gewähren:

kubectl apply --server-side  -f https://github.com/kedacore/keda/releases/download/v2.15.1/keda-2.15.1.yaml

gcloud projects add-iam-policy-binding projects/${PROJECT_ID} \
     --role roles/monitoring.viewer \
     --member=principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/keda/sa/keda-operator

Mit diesem Befehl werden auch Autorisierungsregeln eingerichtet, für die der Cluster mit der Identitätsföderation von Arbeitslasten für GKE eingerichtet sein muss.

Prüfen Sie, ob alle KEDA-Ressourcen im Namespace keda angezeigt werden:

kubectl get all -n keda

Weitere Informationen zu KEDA-Design und -Ressourcen finden Sie in der KEDA-Dokumentation.

Pub/Sub-Arbeitslast auf null skalieren

In diesem Abschnitt wird ein Arbeitslast beschrieben, die Nachrichten aus einem Pub/Sub-Abo verarbeitet, jede Nachricht verarbeitet und den Abschluss bestätigt. Die Arbeitslast wird dynamisch skaliert: Wenn die Anzahl der nicht bestätigten Nachrichten zunimmt, werden durch das Autoscaling weitere Pods instanziiert, um eine zeitnahe Verarbeitung zu gewährleisten.

Durch das Skalieren auf null wird dafür gesorgt, dass keine Pods instanziiert werden, wenn seit einiger Zeit keine Nachrichten empfangen wurden. Dadurch werden Ressourcen gespart, da keine Pods über längere Zeit im Leerlauf bleiben.

Pub/Sub-Arbeitslast bereitstellen

Stellen Sie eine Beispielarbeitslast bereit, die Nachrichten verarbeitet, die in einem Pub/Sub-Thema in die Warteschlange gestellt werden. Um eine realistische Arbeitslast zu simulieren, wartet dieses Beispielprogramm drei Sekunden, bevor es eine Nachricht bestätigt. Die Workload ist so konfiguriert, dass sie unter dem Dienstkonto keda-pubsub-sa ausgeführt wird.

Führen Sie die folgenden Befehle aus, um das Pub/Sub-Thema und das Abo zu erstellen, die Berechtigung zu konfigurieren und die Bereitstellung zu erstellen, mit der die Arbeitslast im Namespace keda-pubsub gestartet wird.

gcloud pubsub topics create keda-echo
gcloud pubsub subscriptions create keda-echo-read --topic=keda-echo
gcloud projects add-iam-policy-binding projects/${PROJECT_ID}  \
    --role=roles/pubsub.subscriber \
  --member=principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/keda-pubsub/sa/keda-pubsub-sa

kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/kubernetes-engine-samples/refs/heads/main/cost-optimization/gke-keda/cloud-pubsub/deployment/keda-pubsub-with-workload-identity.yaml

Skalierung auf null konfigurieren

Wenn Sie Ihre Pub/Sub-Arbeitslast so konfigurieren möchten, dass sie auf null skaliert wird, verwenden Sie KEDA, um eine ScaledObject-Ressource zu definieren, mit der angegeben wird, wie die Bereitstellung skaliert werden soll. KEDA erstellt und verwaltet dann automatisch das zugrunde liegende HorizontalPodAutoscaler-Objekt (HPA).

  1. Erstellen Sie die ScaledObject-Ressource, um das erwartete Autoscaling-Verhalten zu beschreiben:

    curl https://raw.githubusercontent.com/GoogleCloudPlatform/kubernetes-engine-samples/refs/heads/main/cost-optimization/gke-keda/cloud-pubsub/deployment/keda-pubsub-scaledobject.yaml | envsubst | kubectl apply -f -
    

    Dadurch wird das folgende Objekt erstellt:

    apiVersion: keda.sh/v1alpha1
    kind: ScaledObject
    metadata:
      name: keda-pubsub
      namespace: keda-pubsub
    spec:
      maxReplicaCount: 5
      scaleTargetRef:
        name: keda-pubsub
      triggers:
        - type: gcp-pubsub
          authenticationRef:
            name: keda-auth
          metadata:
            subscriptionName: "projects/${PROJECT_ID}/subscriptions/keda-echo-read"
    
  2. Sehen Sie sich das HorizontalPodAutoscaler-Objekt (HPA) an, das KEDA basierend auf dem ScaledObject-Objekt erstellt:

    kubectl get hpa keda-hpa-keda-pubsub -n keda-pubsub -o yaml
    

    Weitere Informationen zum Autoscaling finden Sie in der Kubernetes-Dokumentation.

  3. Warten Sie, bis KEDA bestätigt, dass das Pub/Sub-Abo leer ist, und die Bereitstellung auf null Replikate skaliert.

    Arbeitslast-Autoscaler prüfen:

    kubectl describe hpa keda-hpa-keda-pubsub -n keda-pubsub
    

    Beachten Sie, dass die Bedingung ScalingActive in der Befehlsantwort falsch ist. Die zugehörige Meldung zeigt, dass das horizontale Pod-Autoscaling erkennt, dass KEDA das Deployment auf null skaliert hat. An diesem Punkt wird der Betrieb eingestellt, bis das Deployment wieder auf einen Pod skaliert wird.

    Name:                                                  keda-hpa-keda-pubsub
    Namespace:                                             keda-pubsub
    Metrics:                                               ( current / target )
      "s0-gcp-ps-projects-[...]]" (target average value):  0 / 10
    Min replicas:                                          1
    Max replicas:                                          5
    Deployment pods:                                       5 current / 5 desired
    Conditions:
      Type            Status  Reason               Message
      ----            ------  ------               -------
      AbleToScale     True    ScaleDownStabilized  recent recommendations were higher than current one [...]
      ScalingActive   False   ScalingDisabled      scaling is disabled since the replica count of the target is zero
      ScalingLimited  True    TooManyReplicas      the desired replica count is more than the maximum replica count
    

Hochskalierung auslösen

So stimulieren Sie das Deployment, um es zu skalieren:

  1. Nachrichten in die Warteschlange des Pub/Sub-Themas einreihen:

    for num in {1..20}
    do
      gcloud pubsub topics publish keda-echo --project=${PROJECT_ID} --message="Test"
    done
    
  2. Prüfen Sie, ob die Bereitstellung hochskaliert wird:

    kubectl get deployments -n keda-pubsub
    

    Beachten Sie in der Ausgabe, dass in der Spalte „Bereit“ ein Replikat angezeigt wird:

    NAME          READY   UP-TO-DATE   AVAILABLE   AGE
    keda-pubsub   1/1     1            1           2d
    

KEDA skaliert die Bereitstellung hoch, nachdem festgestellt wurde, dass die Warteschlange nicht leer ist.

LLM-Arbeitslast auf null skalieren

In diesem Abschnitt wird eine LLM-Arbeitslast (Large Language Model) beschrieben, mit der ein Ollama-Server mit angehängter GPU bereitgestellt wird. Mit Ollama können beliebte LLMs wie Gemma und Llama 2 ausgeführt werden. Die Funktionen werden hauptsächlich über HTTP bereitgestellt.

KEDA-HTTP-Add-on installieren

Wenn ein HTTP-Dienst in inaktiven Phasen auf null Pods skaliert wird, führt dies zu Anfragenfehlern, da kein Backend vorhanden ist, das die Anfragen verarbeiten kann.

In diesem Abschnitt wird beschrieben, wie Sie dieses Problem mit dem KEDA-HTTP-Add-on beheben. KEDA-HTTP startet einen HTTP-Proxy, der Nutzeranfragen empfängt und an die Dienste weiterleitet, die für die Skalierung auf null konfiguriert sind. Wenn der Dienst keinen Pod hat, löst der Proxy eine Aufskalierung des Dienstes aus und puffert die Anfrage, bis der Dienst auf mindestens einen Pod skaliert wurde.

Installieren Sie das KEDA-HTTP-Add-on mit Helm. Weitere Informationen finden Sie in der KEDA-HTTP-Dokumentation.

helm repo add ollama-helm https://otwld.github.io/ollama-helm/
helm repo update

# Set the proxy timeout to 120s, giving Ollama time to start.
helm install http-add-on kedacore/keda-add-ons-http  \
  --create-namespace --namespace keda \
  --set interceptor.responseHeaderTimeout=120s

Ollama-LLM-Arbeitslast bereitstellen

So stellen Sie eine Ollama-LLM-Arbeitslast bereit:

  1. Erstellen Sie einen Knotenpool mit g2-standard-4-Knoten mit angehängten GPUs und konfigurieren Sie das Cluster-Autoscaling so, dass zwischen null und zwei Knoten bereitgestellt werden:

    gcloud container node-pools create gpu --machine-type=g2-standard-4 \
        --location=${LOCATION} --cluster=scale-to-zero \
        --min-nodes 0 --max-nodes 2 --num-nodes=1 --enable-autoscaling
    
  2. Fügen Sie das offizielle Ollama-Helm-Diagramm-Repository hinzu und aktualisieren Sie das Repository Ihres lokalen Helm-Clients:

    helm repo add ollama-helm https://otwld.github.io/ollama-helm/
    helm repo update
    
  3. Stellen Sie den Ollama-Server mit dem Helm-Diagramm bereit:

    helm install ollama ollama-helm/ollama --create-namespace --namespace ollama \
      -f https://raw.githubusercontent.com/GoogleCloudPlatform/kubernetes-engine-samples/refs/heads/main/cost-optimization/gke-keda/ollama/helm-values-ollama.yaml
    

    In der helm-values-ollama.yaml-Konfiguration werden die zu ladenden LLM-Modelle, die GPU-Anforderungen und der TCP-Port für den Ollama-Server angegeben.

Skalierung auf null konfigurieren

Damit Ihre Ollama-Arbeitslast auf null skaliert werden kann, verwendet KEDA-HTTP ein HTTPScaledObject.

  1. Erstellen Sie die HTTPScaledObject-Ressource, um das erwartete Autoscaling-Verhalten zu beschreiben:

    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/kubernetes-engine-samples/refs/heads/main/cost-optimization/gke-keda/ollama/keda-ollama-httpscaledobject.yaml
    

    Dadurch wird das HTTPScaledObject-Objekt erstellt, das die folgenden Felder definiert:

    • scaleTargetRef: Gibt den Dienst an, an den KEDA-HTTP die Anfragen weiterleiten soll. In diesem Beispiel werden alle Anfragen mit dem Host ollama.ollama an den Ollama-Server weitergeleitet.
    • scaledownPeriod: gibt in Sekunden an, wie schnell die Skalierung verringert werden soll, wenn keine Anfragen eingehen.
    • replicas: Gibt die Mindest- und Höchstanzahl der Pods an, die für die Ollama-Bereitstellung beibehalten werden sollen.
    • scalingMetric: Gibt die Messwerte an, die für das Autoscaling verwendet werden, z. B. die Anforderungsrate in diesem Beispiel. Weitere Messwertoptionen finden Sie in der KEDA-HTTP-Dokumentation.
    kind: HTTPScaledObject
    apiVersion: http.keda.sh/v1alpha1
    metadata:
        namespace: ollama
        name: ollama
    spec:
        hosts:
        - ollama.ollama
        scaleTargetRef:
            name: ollama
            kind: Deployment
            apiVersion: apps/v1
            service: ollama
            port: 11434
        replicas:
            min: 0
            max: 2
        scaledownPeriod: 3600
        scalingMetric:
            requestRate:
                targetValue: 20
    
  2. Führen Sie den folgenden Befehl aus, um zu prüfen, ob KEDA-HTTP die im vorherigen Schritt erstellte HTTPScaledObject erfolgreich verarbeitet hat:

    kubectl get hpa,scaledobject -n ollama
    

    Die Ausgabe zeigt die Ressourcen HorizontalPodAutoscaler (von KEDA erstellt) und ScaledObject (von KEDA-HTTP erstellt):

    NAME                                                  REFERENCE           TARGETS       MINPODS   MAXPODS   REPLICAS   AGE
    horizontalpodautoscaler.autoscaling/keda-hpa-ollama   Deployment/ollama   0/100 (avg)   1         2         1          2d
    
    NAME                          SCALETARGETKIND      SCALETARGETNAME   MIN   MAX   TRIGGERS        AUTHENTICATION   READY   ACTIVE   FALLBACK   PAUSED    AGE
    scaledobject.keda.sh/ollama   apps/v1.Deployment   ollama            0     2     external-push                    True    False    False      Unknown   2d
    
  3. Prüfen Sie, ob die Bereitstellung auf null Pods skaliert wird.

    Warten Sie den im Feld scaledownPeriod festgelegten Zeitraum ab und führen Sie den Befehl aus:

    kubectl get deployments -n ollama
    

    Die Ausgabe zeigt, dass KEDA das Ollama-Deployment skaliert hat und keine Pods ausgeführt werden:

    NAME     READY   UP-TO-DATE   AVAILABLE   AGE
    ollama   0/0     0            0           2d
    

Hochskalierung auslösen

Um die Bereitstellung zum Hochskalieren zu veranlassen, rufen Sie den Ollama-Dienst über den Proxy auf, der vom KEDA-HTTP-Add-on eingerichtet wurde. Dadurch erhöht sich der Wert des Messwerts Anfragerate und es wird ein erster Pod erstellt.

Verwenden Sie die kubectl-Portweiterleitungsfunktionen, um auf den Proxy zuzugreifen, da der Proxy nicht extern verfügbar gemacht wird.

kubectl port-forward svc/keda-add-ons-http-interceptor-proxy -n keda 8080:8080 &

# Set the 'Host' HTTP header so that the proxy routes requests to the Ollama server.
curl -H "Host: ollama.ollama" \
  http://localhost:8080/api/generate \
  -d '{ "model": "gemma:7b", "prompt": "Hello!" }'

Mit dem Befehl curl wird der Prompt „Hallo!“ an ein Gemma-Modell gesendet. Sehen Sie sich die Antwort-Tokens an, die in der Antwort zurückgegeben werden. Die Spezifikation der API finden Sie im Ollama-Leitfaden.