Autoscaling horizontal des pods (HPA)

Ce document explique comment activer l'autoscaling horizontal des pods (HPA) pour Google Cloud Managed Service pour Prometheus. Vous pouvez activer le HPA en effectuant l'une des opérations suivantes :

Vous devez choisir l'une ou l'autre de ces approches. Vous ne pouvez pas utiliser les deux, car leurs définitions de ressources se chevauchent, comme décrit dans la section Dépannage.

Utiliser l'adaptateur de métriques personnalisées Stackdriver

L'adaptateur de métriques personnalisées Stackdriver permet d'interroger des métriques du service géré pour Prometheus à partir de la version 0.13.1 de l'adaptateur.

Pour définir un exemple de configuration HPA à l'aide de l'adaptateur de métriques personnalisées Stackdriver, procédez comme suit :

  1. Configurez la collecte gérée pour votre cluster.
  2. Installez l'adaptateur de métriques personnalisées Stackdriver dans votre cluster.

    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml
    
  3. Déployez un exemple d'exportateur de métriques Prometheus et une ressource HPA :

    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/examples/prometheus-to-sd/custom-metrics-prometheus-sd.yaml
    

    Cette commande déploie une application d'exportation qui émet la métrique foo et une ressource HPA. Le HPA effectue le scaling de cette application jusqu'à cinq instances répliquées pour atteindre la valeur cible de la métrique foo.

  4. Si vous utilisez Workload Identity Federation for GKE, vous devez également attribuer le rôle de lecteur Monitoring au compte de service sous lequel l'adaptateur s'exécute. Ignorez cette étape si Workload Identity Federation for GKE n'est pas activée sur votre cluster Kubernetes.

    export PROJECT_NUMBER=$(gcloud projects describe PROJECT_ID --format 'get(projectNumber)')
    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/custom-metrics/sa/custom-metrics-stackdriver-adapter
    
  5. Définissez une ressource PodMonitoring en plaçant la configuration suivante dans un fichier nommé podmonitoring.yaml.

    apiVersion: monitoring.googleapis.com/v1
    kind: PodMonitoring
    metadata:
      name: prom-example
    spec:
      selector:
        matchLabels:
          run: custom-metric-prometheus-sd
      endpoints:
      - port: 8080
        interval: 30s
    
  6. Déployez la nouvelle ressource PodMonitoring :

    kubectl -n default apply -f podmonitoring.yaml
    

    En quelques minutes, le service géré pour Prometheus traite les métriques extraites de l'exportateur et les stocke dans Cloud Monitoring à l'aide d'un nom long. Les métriques Prometheus sont stockées avec les conventions suivantes :

    • Le préfixe prometheus.googleapis.com.
    • Ce suffixe est généralement gauge, counter, summary ou histogram, bien que les métriques non spécifiées puissent comporter le suffixe unknown ou unknown:counter. Pour vérifier le suffixe, recherchez la métrique dans Cloud Monitoring à l'aide de l'explorateur de métriques.
  7. Mettez à jour le HPA déployé pour interroger la métrique à partir de Cloud Monitoring. La métrique foo est ingérée en tant que prometheus.googleapis.com/foo/gauge. Pour que la métrique puisse être interrogée par la ressource HorizontalPodAutoscaler déployée, vous devez utiliser le nom complet dans le HPA déployé, mais vous devez le modifier en remplaçant toutes les barres obliques (/) par la barre verticale (|) : prometheus.googleapis.com|foo|gauge. Pour en savoir plus, consultez la section Métriques disponibles depuis Stackdriver du dépôt de l'adaptateur de métriques personnalisées Stackdriver.

    1. Mettez à jour le HPA déployé en exécutant la commande suivante :

      kubectl edit hpa custom-metric-prometheus-sd
      
    2. Remplacez la valeur foo du champ pods.metric.name par prometheus.googleapis.com|foo|gauge. La section spec doit ressembler à l'exemple qui suit :

      spec:
         maxReplicas: 5
         metrics:
         - pods:
             metric:
               name: prometheus.googleapis.com|foo|gauge
             target:
               averageValue: "20"
               type: AverageValue
           type: Pods
         minReplicas: 1
      

    Dans cet exemple, la configuration HPA cherche à ce que la valeur moyenne de la métrique prometheus.googleapis.com/foo/gauge soit de 20. Comme le déploiement définit que la valeur de la métrique est 40, le contrôleur HPA augmente le nombre de pods jusqu'à la valeur du champ maxReplicas (5) pour essayer de réduire la valeur moyenne de la métrique sur tous les pods à 20.

    La requête HPA s'étend à l'espace de noms et au cluster dans lesquels la ressource HPA est installée. Par conséquent, les métriques identiques dans d'autres clusters et espaces de noms n'affectent pas votre autoscaling.

  8. Pour surveiller le scaling à la hausse de la charge de travail, exécutez la commande suivante :

    kubectl get hpa custom-metric-prometheus-sd --watch
    

    La valeur du champ REPLICAS passe de 1 à 5.

    NAME                          REFERENCE                                TARGETS        MINPODS   MAXPODS   REPLICAS   AGE
    custom-metric-prometheus-sd   Deployment/custom-metric-prometheus-sd   40/20          1         5         5          *
    
  9. Pour effectuer le scaling à la baisse du déploiement, mettez à jour la valeur de la métrique cible afin qu'elle soit supérieure à la valeur de la métrique exportée. Dans cet exemple, le déploiement définit la valeur de la métrique prometheus.googleapis.com/foo/gauge sur 40. Si vous définissez la valeur cible sur un nombre supérieur à 40, le déploiement subit un scaling à la baisse.

    Par exemple, utilisez kubectl edit pour remplacer la valeur 20 du champ pods.target.averageValue dans la configuration du HPA par 100.

    kubectl edit hpa custom-metric-prometheus-sd
    

    Modifiez la section "spec" pour qu'elle corresponde aux éléments suivants :

    spec:
      maxReplicas: 5
      metrics:
      - pods:
          metric:
            name: prometheus.googleapis.com|foo|gauge
          target:
            averageValue: "100"
            type: AverageValue
      type: Pods
      minReplicas: 1
    
  10. Pour surveiller le scaling à la baisse de la charge de travail, exécutez la commande suivante :

    kubectl get hpa custom-metric-prometheus-sd --watch
    

    La valeur du champ REPLICAS passe de 5 à 1. De par sa conception, ce scaling est plus lent que le scaling à la hausse du nombre de pods :

    NAME                          REFERENCE                                TARGETS        MINPODS   MAXPODS   REPLICAS   AGE
    custom-metric-prometheus-sd   Deployment/custom-metric-prometheus-sd   40/100          1         5         1          *
    
  11. Pour nettoyer l'exemple déployé, exécutez les commandes suivantes :

    kubectl delete -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml
    kubectl delete -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/examples/prometheus-to-sd/custom-metrics-prometheus-sd.yaml
    kubectl delete podmonitoring/prom-example
    

Pour en savoir plus, consultez l'exemple Prometheus dans le dépôt de l'adaptateur de métriques personnalisées Stackdriver, ou consultez la section Procéder au scaling d'une application.

Utiliser l'adaptateur Prometheus

Les configurations prometheus-adapter existantes permettent d'effectuer l'autoscaling en apportant seulement quelques modifications. La configuration de prometheus-adapter avec Managed Service pour Prometheus présente deux restrictions supplémentaires par rapport au scaling à l'aide de Prometheus en amont :

Les données pouvant prendre un peu plus de temps pour être disponibles dans Managed Service pour Prometheus par rapport à une règle Prometheus en amont, la configuration d'une logique d'autoscaling trop excessive peut entraîner un comportement indésirable. Bien qu'il n'y ait aucune garantie en ce qui concerne la fraîcheur des données, celles-ci sont généralement disponibles pour les requêtes trois à sept secondes après leur envoi à Managed Service pour Prometheus, à l'exception de la latence du réseau.

Toutes les requêtes émises par prometheus-adapter ont un champ d'application global. Cela signifie que si des applications situées dans deux espaces de noms différents émettent des métriques portant le même nom, le scaling d'une configuration HPA utilisant ces métriques va se baser sur les données des deux applications. Nous vous recommandons de toujours utiliser des filtres namespace ou cluster dans votre requête PromQL pour éviter tout scaling exploitant des données incorrectes.

Pour définir un exemple de configuration HPA à l'aide de prometheus-adapter et d'une collecte gérée, procédez comme suit :

  1. Configurez la collecte gérée pour votre cluster.
  2. Déployez le proxy d'interface Prometheus dans votre cluster. Si vous utilisez Workload Identity Federation for GKE, vous devez également configurer et autoriser un compte de service.
  3. Déployez les fichiers manifestes dans le répertoire examples/hpa/ du dépôt prometheus-engine :
    • example-app.yaml : exemple de déploiement et de service qui émet des métriques.
    • pod-monitoring.yaml : ressource qui configure le scraping des exemples de métriques.
    • hpa.yaml : ressource HPA qui configure le scaling de votre charge de travail.
  4. Assurez-vous que prometheus-adapter est installé dans votre cluster. Pour ce faire, déployez l'exemple de fichier manifeste d'installation sur votre cluster. Ce fichier manifeste est configuré pour :

    • Interroger un proxy d'interface déployé dans l'espace de noms default.
    • Utiliser PromQL pour calculer et renvoyer la métrique http_requests_per_second de l'exemple de déploiement.
  5. Exécutez les commandes suivantes, chacune dans une session de terminal distincte :

    1. Générez une charge HTTP sur le service prometheus-example-app :
      kubectl run -i --tty load-generator --rm --image=busybox:1.28 --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://prometheus-example-app; done"
    2. Observez l'autoscaler horizontal de pods :
      kubectl get hpa prometheus-example-app --watch
    3. Observez le scaling à la hausse de la charge de travail :
      kubectl get po -lapp.kubernetes.io/name=prometheus-example-app --watch
  6. Arrêtez la génération de la charge HTTP à l'aide de Ctrl+C et observez le scaling à la baisse de la charge de travail.

Dépannage

L'adaptateur de métriques personnalisées Stackdriver utilise des définitions de ressources portant les mêmes noms que celles de l'adaptateur Prometheus, prometheus-adapter. Ce chevauchement de noms signifie que l'exécution de plusieurs adaptateurs dans le même cluster va entraîner des erreurs.

L'installation de l'adaptateur Prometheus dans un cluster contenant précédemment l'adaptateur de métriques personnalisées Stackdriver installé peut générer des erreurs du type FailedGetObjectMetric en raison de conflits de noms. Pour résoudre ce problème, vous devrez peut-être supprimer les services API v1beta1.external.metrics.k8s.io, v1beta1.custom.metrics.k8s.io et v1beta2.custom.metrics.k8s.io précédemment enregistrés par l'adaptateur de métriques personnalisées.

Conseils de dépannage

  • Certaines métriques système Cloud Monitoring, telles que les métriques Pub/Sub, sont retardées de 60 secondes ou plus. Étant donné que l'adaptateur Prometheus exécute des requêtes à l'aide du code temporel actuel, l'interrogation de ces métriques à l'aide de l'adaptateur Prometheus peut ne pas générer de données à tort. Pour interroger des métriques retardées, utilisez le modificateur offset dans PromQL afin de remplacer l'horodatage de votre requête par celui requis.

  • Pour vérifier que le proxy d'interface utilisateur fonctionne comme prévu et qu'il n'y a aucun problème avec les autorisations, exécutez la commande suivante dans un terminal :

    kubectl -n NAMESPACE_NAME port-forward svc/frontend 9090
    

    Ensuite, ouvrez un autre terminal et exécutez la commande suivante :

    curl --silent 'localhost:9090/api/v1/series?match%5B%5D=up'
    

    Lorsque le proxy d'interface utilisateur fonctionne correctement, la réponse du second terminal est semblable à celle-ci :

    curl --silent 'localhost:9090/api/v1/series?match%5B%5D=up' | jq .
    {
      "status": "success",
      "data": [
         ...
      ]
    }
    

    Si vous recevez une erreur 403, le proxy d'interface utilisateur n'est pas correctement configuré. Pour plus d'informations sur la façon de résoudre une erreur 403, consultez le guide Configurer et autoriser un compte de service.

  • Pour vérifier que le serveur d'API de métriques personnalisées est disponible, exécutez la commande suivante :

    kubectl get apiservices.apiregistration.k8s.io v1beta1.custom.metrics.k8s.io
    

    Lorsque le serveur d'API est disponible, la réponse est semblable à ce qui suit :

    $ kubectl get apiservices.apiregistration.k8s.io v1beta1.custom.metrics.k8s.io
    NAME                            SERVICE                         AVAILABLE   AGE
    v1beta1.custom.metrics.k8s.io   monitoring/prometheus-adapter   True        33m
    
  • Pour vérifier que votre HPA fonctionne comme prévu, exécutez la commande suivante :

    $ kubectl describe hpa prometheus-example-app
    Name:                                  prometheus-example-app
    Namespace:                             default
    Labels:                                
    Annotations:                           
    Reference:                             Deployment/prometheus-example-app
    Metrics:                               ( current / target )
    "http_requests_per_second" on pods:  11500m / 10
    Min replicas:                          1
    Max replicas:                          10
    Deployment pods:                       2 current / 2 desired
    Conditions:
    Type            Status  Reason              Message
    ----            ------  ------              -------
    AbleToScale     True    ReadyForNewScale    recommended size matches current size
    ScalingActive   True    ValidMetricFound    the HPA was able to successfully calculate a replica count from pods metric http_requests_per_second
    ScalingLimited  False   DesiredWithinRange  the desired count is within the acceptable range
    Events:
    Type     Reason               Age                   From                       Message
    ----     ------               ----                  ----                       -------
    Normal   SuccessfulRescale    47s                   horizontal-pod-autoscaler  New size: 2; reason: pods metric http_requests_per_second above target
    

    Lorsque la réponse contient une instruction telle que FailedGetPodsMetric, le HPA échoue. L'exemple suivant illustre une réponse à l'appel describe en cas d'échec du HPA :

    $ kubectl describe hpa prometheus-example-app
    Name:                                  prometheus-example-app
    Namespace:                             default
    Reference:                             Deployment/prometheus-example-app
    Metrics:                               ( current / target )
      "http_requests_per_second" on pods:   / 10
    Min replicas:                          1
    Max replicas:                          10
    Deployment pods:                       1 current / 1 desired
    Conditions:
      Type            Status  Reason               Message
      ----            ------  ------               -------
      AbleToScale     True    ReadyForNewScale     recommended size matches current size
      ScalingActive   False   FailedGetPodsMetric  the HPA was unable to compute the replica count: unable to get metric http_requests_per_second: unable to fetch metrics from custom metrics API: the server could not find the metric http_requests_per_second for pods
      ScalingLimited  False   DesiredWithinRange   the desired count is within the acceptable range
    Events:
      Type     Reason               Age                   From                       Message
      ----     ------               ----                  ----                       -------
      Warning  FailedGetPodsMetric  104s (x11 over 16m)   horizontal-pod-autoscaler  unable to get metric http_requests_per_second: unable to fetch metrics from custom metrics API: the server could not find the metric http_requests_per_second for pods
    

    En cas d'échec du HPA, assurez-vous de générer des métriques avec load-generator. Vous pouvez vérifier l'API de métriques personnalisées directement à l'aide de la commande suivante :

    kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/" | jq .
    

    Si la commande aboutit, vous devriez obtenir le résultat suivant :

    $ kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/" | jq .
      {
      "kind": "APIResourceList",
      "apiVersion": "v1",
      "groupVersion": "custom.metrics.k8s.io/v1beta1",
      "resources": [
         {
            "name": "namespaces/http_requests_per_second",
            "singularName": "",
            "namespaced": false,
            "kind": "MetricValueList",
            "verbs": [
            "get"
            ]
         },
         {
            "name": "pods/http_requests_per_second",
            "singularName": "",
            "namespaced": true,
            "kind": "MetricValueList",
            "verbs": [
            "get"
            ]
         }
      ]
      }
    

    S'il n'y a pas de métriques, il n'y aura pas de données sous "resources" dans le résultat, par exemple :

    kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/" | jq .
    {
    "kind": "APIResourceList",
    "apiVersion": "v1",
    "groupVersion": "custom.metrics.k8s.io/v1beta1",
    "resources": []
    }