Scaling à zéro instance avec KEDA

Ce tutoriel explique comment réduire le nombre de pods de vos charges de travail GKE à zéro à l'aide de KEDA. La mise à l'échelle des déploiements à zéro pod permet d'économiser des ressources pendant les périodes d'inactivité (comme les week-ends et les heures creuses) ou pour les charges de travail intermittentes telles que les jobs périodiques.

Objectifs

Ce tutoriel décrit les cas d'utilisation suivants :

Coûts

Dans ce document, vous utilisez les composants facturables de Google Cloudsuivants :

Vous pouvez obtenir une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût.

Les nouveaux utilisateurs de Google Cloud peuvent bénéficier d'un essai sans frais.

Une fois que vous avez terminé les tâches décrites dans ce document, supprimez les ressources que vous avez créées pour éviter que des frais vous soient facturés. Pour en savoir plus, consultez la section Effectuer un nettoyage.

Avant de commencer

Dans ce tutoriel, vous utilisez Cloud Shell pour exécuter des commandes. Cloud Shell est un environnement shell permettant de gérer les ressources hébergées sur Google Cloud. Il est doté des outils de ligne de commande préinstallés suivants : Google Cloud CLI, kubectl, Helm et Terraform. Si vous n'utilisez pas Cloud Shell, vous devez installer la Google Cloud CLI et Helm.

  1. Pour exécuter les commandes sur cette page, configurez gcloud CLI dans l'un des environnements de développement suivants :

    Cloud Shell

    Pour utiliser un terminal en ligne avec la gcloud CLI déjà configurée, activez Cloud Shell :

    En bas de la page, une session Cloud Shell démarre et affiche une invite de ligne de commande. L'initialisation de la session peut prendre quelques secondes.

    Shell local

    Pour utiliser un environnement de développement local, procédez comme suit :

    1. Installez gcloud CLI.
    2. Initialisez gcloud CLI.
    3. Installez Helm, un outil de gestion des packages Kubernetes.
  2. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  3. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  4. Verify that billing is enabled for your Google Cloud project.

  5. Enable the Resource Manager, Compute Engine, GKE, Pub/Sub APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  6. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  7. Verify that billing is enabled for your Google Cloud project.

  8. Enable the Resource Manager, Compute Engine, GKE, Pub/Sub APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  9. Configurer votre environnement

    Pour configurer votre environnement avec Cloud Shell, procédez comme suit :

    1. Définissez les variables d'environnement :

      export PROJECT_ID=PROJECT_ID
      export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format 'get(projectNumber)')
      export LOCATION=LOCATION
      

      Remplacez PROJECT_ID par votre ID de projet et LOCATION par les régions ou zones dans lesquelles votre cluster GKE doit être créé. Google Cloud

      Si vous ne suivez pas l'intégralité du tutoriel en une seule session ou si vos variables d'environnement sont supprimées pour une raison quelconque, assurez-vous d'exécuter à nouveau cette commande pour les définir à nouveau.

    2. Créez un cluster GKE Standard avec l'autoscaling de cluster et la fédération d'identité de charge de travail pour GKE activés :

      gcloud container clusters create scale-to-zero \
          --project=${PROJECT_ID} --location=${LOCATION} \
          --machine-type=n1-standard-2 \
          --enable-autoscaling --min-nodes=1 --max-nodes=5 \
          --workload-pool=${PROJECT_ID}.svc.id.goog
      

    Installer KEDA

    KEDA est un composant qui complète l'autoscaler horizontal de pods Kubernetes. Avec KEDA, vous pouvez réduire le nombre de pods d'un déploiement à zéro, puis le faire passer de zéro à un. Un déploiement est un objet de l'API Kubernetes qui vous permet d'exécuter plusieurs instances dupliquées de pods répartis entre les nœuds d'un cluster. L'algorithme standard de l'autoscaler horizontal de pods s'applique une fois que GKE a créé au moins un pod.

    Une fois que GKE a mis le déploiement à l'échelle sur zéro pod, l'autoscaling ne peut pas s'appuyer sur les métriques de pod telles que l'utilisation du processeur, car aucun pod n'est en cours d'exécution. Par conséquent, KEDA permet d'extraire des métriques provenant de l'extérieur du cluster à l'aide d'une implémentation de l'API Kubernetes External Metrics. Vous pouvez utiliser cette API pour effectuer un autoscaling en fonction de métriques telles que le nombre de messages en attente sur un abonnement Pub/Sub. Consultez la documentation KEDA pour obtenir la liste de toutes les sources de métriques compatibles.

    Installez KEDA sur votre cluster avec Helm ou kubectl.

    Helm

    Exécutez les commandes suivantes pour ajouter le dépôt Helm KEDA, installer le graphique Helm KEDA et accorder au compte de service KEDA un accès en lecture à Cloud Monitoring :

    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
    

    Notez que cette commande configure également des règles d'autorisation qui exigent que le cluster soit configuré avec la fédération d'identité de charge de travail pour GKE.

    kubectl

    Exécutez les commandes suivantes pour installer KEDA à l'aide de kubectl apply et accorder au compte de service KEDA l'accès en lecture à Cloud Monitoring :

    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
    

    Notez que cette commande configure également des règles d'autorisation qui exigent que le cluster soit configuré avec la fédération d'identité de charge de travail pour GKE.

    Vérifiez que toutes les ressources KEDA apparaissent sous l'espace de noms keda :

    kubectl get all -n keda
    

    Pour en savoir plus sur la conception et les ressources de KEDA, consultez la documentation KEDA.

    Redimensionner votre charge de travail Pub/Sub à zéro

    Cette section décrit une charge de travail qui traite les messages d'un abonnement Pub/Sub, en gérant chaque message et en accusant réception de son traitement. La charge de travail évolue de manière dynamique : à mesure que le nombre de messages non confirmés augmente, l'autoscaling instancie davantage de pods pour garantir un traitement rapide.

    La mise à l'échelle à zéro garantit qu'aucun pod n'est instancié lorsqu'aucun message n'a été reçu depuis un certain temps. Cela permet d'économiser des ressources, car aucun pod ne reste inactif pendant de longues périodes.

    Déployer une charge de travail Pub/Sub

    Déployez un exemple de charge de travail qui traite les messages mis en file d'attente dans un sujet Pub/Sub. Pour simuler une charge de travail réaliste, cet exemple de programme attend trois secondes avant d'accuser réception d'un message. La charge de travail est configurée pour s'exécuter sous le compte de service keda-pubsub-sa.

    Exécutez les commandes suivantes pour créer le sujet et l'abonnement Pub/Sub, configurer leurs autorisations et créer le déploiement en démarrant la charge de travail sous l'espace de noms keda-pubsub.

    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
    

    Configurer le scaling à zéro instance

    Pour configurer votre charge de travail Pub/Sub afin qu'elle passe à zéro, utilisez KEDA pour définir une ressource ScaledObject afin de spécifier comment le déploiement doit être mis à l'échelle. KEDA créera et gérera ensuite automatiquement l'objet HorizontalPodAutoscaler (AHP) sous-jacent.

    1. Créez la ressource ScaledObject pour décrire le comportement d'autoscaling attendu :

      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 -
      

      L'objet suivant est alors créé :

      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. Inspectez l'objet HorizontalPodAutoscaler (AHP) que KEDA crée en fonction de l'objet ScaledObject :

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

      Pour en savoir plus sur l'autoscaling, consultez la documentation Kubernetes.

    3. Attendez que KEDA confirme que l'abonnement Pub/Sub est vide et que le déploiement est mis à l'échelle sur zéro réplique.

      Inspectez l'autoscaler de charge de travail :

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

      Notez que dans la réponse à la commande, la condition ScalingActive est définie sur "false". Le message associé indique que l'autoscaler horizontal de pods reconnaît que KEDA a mis le déploiement à zéro, auquel cas il cesse de fonctionner jusqu'à ce que le déploiement soit remis à un pod.

      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
      

    Déclencher le scaling à la hausse

    Pour stimuler le scaling à la hausse du déploiement :

    1. Mettez en file d'attente les messages sur le sujet Pub/Sub :

      for num in {1..20}
      do
        gcloud pubsub topics publish keda-echo --project=${PROJECT_ID} --message="Test"
      done
      
    2. Vérifiez que le déploiement fait un scaling à la hausse :

      kubectl get deployments -n keda-pubsub
      

      Dans le résultat, vérifiez que la colonne "Ready" (Prêt) affiche une instance répliquée :

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

    KEDA augmente le nombre de déploiements après avoir constaté que la file d'attente n'est pas vide.

    Mettre à zéro le scaling de votre charge de travail LLM

    Cette section décrit une charge de travail de grand modèle de langage (LLM) qui déploie un serveur Ollama avec un GPU associé. Ollama permet d'exécuter des LLM populaires tels que Gemma et Llama 2, et expose ses fonctionnalités principalement via HTTP.

    Installer le module complémentaire KEDA-HTTP

    Si vous réduisez un service HTTP à zéro pod pendant les périodes d'inactivité, les requêtes échouent, car il n'y a pas de backend pour les traiter.

    Cette section explique comment résoudre ce problème à l'aide du module complémentaire KEDA-HTTP. KEDA-HTTP démarre un proxy HTTP qui reçoit les requêtes des utilisateurs et les transmet aux services configurés pour la mise à l'échelle à zéro. Lorsque le service ne dispose d'aucun pod, le proxy déclenche le scaling à la hausse du service et met en mémoire tampon la requête jusqu'à ce que le service ait été mis à l'échelle sur au moins un pod.

    Installez le module complémentaire KEDA-HTTP à l'aide de Helm. Pour en savoir plus, consultez la documentation KEDA-HTTP.

    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
    

    Déployer une charge de travail LLM Ollama

    Pour déployer une charge de travail LLM Ollama :

    1. Créez un pool de nœuds contenant g2-standard-4 nœuds avec des GPU associés, puis configurez l'autoscaling du cluster pour fournir entre zéro et deux nœuds :

      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. Ajoutez le dépôt officiel de chart Helm Ollama et mettez à jour le dépôt de votre client Helm local :

      helm repo add ollama-helm https://otwld.github.io/ollama-helm/
      helm repo update
      
    3. Déployez le serveur Ollama à l'aide du chart Helm :

      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
      

      La configuration helm-values-ollama.yaml spécifie les modèles LLM à charger, les exigences en matière de GPU et le port TCP du serveur Ollama.

    Configurer le scaling à zéro instance

    Pour configurer votre charge de travail Ollama afin qu'elle puisse être mise à l'échelle à zéro, KEDA-HTTP utilise un HTTPScaledObject.

    1. Créez la ressource HTTPScaledObject pour décrire le comportement d'autoscaling attendu :

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

      Cela crée l'objet HTTPScaledObject qui définit les champs suivants :

      • scaleTargetRef : spécifie le service auquel KEDA-HTTP doit transférer les requêtes. Dans cet exemple, toutes les requêtes avec l'hôte ollama.ollama sont acheminées vers le serveur Ollama.
      • scaledownPeriod : spécifie (en secondes) la vitesse de réduction de la capacité lorsqu'aucune requête n'est reçue.
      • replicas : spécifie le nombre minimal et maximal de pods à maintenir pour le déploiement Ollama.
      • scalingMetric : spécifie les métriques utilisées pour l'autoscaling, comme le taux de requêtes dans cet exemple. Pour en savoir plus sur les options de métriques, consultez la documentation KEDA-HTTP.
      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. Exécutez la commande suivante pour vérifier que KEDA-HTTP a bien traité le HTTPScaledObject créé à l'étape précédente :

      kubectl get hpa,scaledobject -n ollama
      

      Le résultat affiche les ressources HorizontalPodAutoscaler (créées par KEDA) et ScaledObject (créées par KEDA-HTTP) :

      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. Vérifiez que le déploiement est réduit à zéro pod.

      Attendez la durée définie dans le champ scaledownPeriod et exécutez la commande :

      kubectl get deployments -n ollama
      

      Le résultat indique que KEDA a réduit le déploiement Ollama et qu'aucun pod n'est en cours d'exécution :

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

    Déclencher le scaling à la hausse

    Pour stimuler le scaling du déploiement, appelez le service Ollama à l'aide du proxy configuré par le module complémentaire KEDA-HTTP. Cela entraîne une augmentation de la valeur de la métrique taux de requêtes et déclenche la création d'un premier pod.

    Utilisez les fonctionnalités de transfert de port kubectl pour accéder au proxy, car celui-ci n'est pas exposé en externe.

    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!" }'
    

    La commande curl envoie la requête "Bonjour !" à un modèle Gemma. Observez les jetons de réponse qui reviennent dans la réponse. Pour connaître les spécifications de l'API, consultez le guide Ollama.

    Effectuer un nettoyage

    Pour éviter que les ressources utilisées lors de ce tutoriel soient facturées sur votre compte Google Cloud, supprimez le projet contenant les ressources, ou conservez le projet et supprimez les ressources individuelles.

    1. Nettoyez l'abonnement et le sujet Pub/Sub :

      gcloud pubsub subscriptions delete keda-echo-read
      gcloud pubsub topics delete keda-echo
      
    2. Supprimez le cluster GKE :

      gcloud container clusters delete scale-to-zero --location=${LOCATION}
      

    Étapes suivantes