Scalabilità automatica pod orizzontale (HPA)

Questo documento descrive come abilitare lo scalabilità automatica orizzontale dei pod (HPA) per Google Cloud Managed Service per Prometheus. Puoi attivare HPA in uno dei seguenti modi:

Non puoi utilizzare Stackdriver Adapter e Prometheus Adapter insieme nello stesso cluster perché le loro definizioni di risorse si sovrappongono, come descritto in Risoluzione dei problemi. Ti consigliamo di scegliere una sola soluzione per HPA.

Utilizzare KEDA

KEDA (Kubernetes Event-driven Autoscaling) è il gestore della scalabilità automatica rilasciato più di recente che utilizza le metriche Prometheus e sta diventando una soluzione preferita all'interno della community Prometheus.

Per iniziare, consulta la documentazione di KEDA per l'integrazione con Google Cloud Managed Service per Prometheus.

Utilizzare l'adattatore Stackdriver delle metriche personalizzate

L'adattatore Stackdriver per le metriche personalizzate supporta le query sulle metriche di Managed Service for Prometheus a partire dalla versione v0.13.1 dell'adattatore.

Per configurare una configurazione HPA di esempio utilizzando l'adattatore Stackdriver per le metriche personalizzate:

  1. Configura la raccolta gestita nel cluster.
  2. Installa l'adattatore Stackdriver delle metriche personalizzate nel tuo cluster.

    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml
    
  3. Esegui il deployment di un esportatore di metriche Prometheus di esempio e di una risorsa 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
    

    Questo comando esegue il deployment di un'applicazione di esportazione che emette la metrica foo e una risorsa HPA. L'HPA esegue lo scale up di questa applicazione fino a 5 repliche per raggiungere il valore target per la metrica foo.

  4. Se utilizzi la federazione delle identità per i carichi di lavoro per GKE, devi anche concedere il ruolo Visualizzatore Monitoring alaccount di serviziot con cui viene eseguito l'adattatore. Salta questo passaggio se non hai abilitato la federazione delle identità per i carichi di lavoro per GKE nel tuo 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. Definisci una risorsa PodMonitoring inserendo la seguente configurazione in un file denominato 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. Esegui il deployment della nuova risorsa PodMonitoring:

    kubectl -n default apply -f podmonitoring.yaml
    

    Nel giro di un paio di minuti, Managed Service per Prometheus elabora le metriche recuperate dall'esportatore e le archivia in Cloud Monitoring utilizzando un nome in formato lungo. Le metriche Prometheus vengono archiviate con le seguenti convenzioni:

    • Il prefisso prometheus.googleapis.com.
    • Questo suffisso è in genere uno tra gauge, counter, summary o histogram, anche se le metriche non tipizzate potrebbero avere il suffisso unknown o unknown:counter. Per verificare il suffisso, cerca la metrica in Cloud Monitoring utilizzando Metrics Explorer.
  7. Aggiorna l'HPA di cui è stato eseguito il deployment per eseguire query sulla metrica da Cloud Monitoring. La metrica foo viene importata come prometheus.googleapis.com/foo/gauge. Per rendere la metrica interrogabile dalla risorsa HorizontalPodAutoscaler di cui è stato eseguito il deployment, utilizzi il nome in formato lungo nell'HPA di cui è stato eseguito il deployment, ma devi modificarlo sostituendo tutte le barre (/) con il carattere pipe (|): prometheus.googleapis.com|foo|gauge. Per ulteriori informazioni, consulta la sezione Metriche disponibili da Stackdriver del repository dell'adattatore Stackdriver per le metriche personalizzate.

    1. Aggiorna l'HPA di cui è stato eseguito il deployment eseguendo il seguente comando:

      kubectl edit hpa custom-metric-prometheus-sd
      
    2. Modifica il valore del campo pods.metric.name da foo a prometheus.googleapis.com|foo|gauge. La sezione spec dovrebbe avere il seguente aspetto:

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

    In questo esempio, la configurazione HPA cerca il valore medio della metrica prometheus.googleapis.com/foo/gauge pari a 20. Poiché il deployment imposta il valore della metrica su 40, il controller HPA aumenta il numero di pod fino al valore del campo maxReplicas (5) per cercare di ridurre il valore medio della metrica in tutti i pod a 20.

    La query HPA è limitata allo spazio dei nomi e al cluster in cui è installata la risorsa HPA, pertanto metriche identiche in altri cluster e spazi dei nomi non influiscono sullo scalabilità automatica.

  8. Per osservare lo scale up del carico di lavoro, esegui questo comando:

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

    Il valore del campo REPLICAS cambia da 1 a 5.

    NAME                          REFERENCE                                TARGETS        MINPODS   MAXPODS   REPLICAS   AGE
    custom-metric-prometheus-sd   Deployment/custom-metric-prometheus-sd   40/20          1         5         5          *
    
  9. Per fare lo scale down del deployment, aggiorna il valore della metrica target in modo che sia superiore al valore della metrica esportata. In questo esempio, il deployment imposta il valore della metrica prometheus.googleapis.com/foo/gauge su 40. Se imposti il valore target su un numero superiore a 40, il deployment verrà fare lo scale down.

    Ad esempio, utilizza kubectl edit per modificare il valore del campo pods.target.averageValue nella configurazione HPA da 20 a 100.

    kubectl edit hpa custom-metric-prometheus-sd
    

    Modifica la sezione delle specifiche in modo che corrisponda a quanto segue:

    spec:
      maxReplicas: 5
      metrics:
      - pods:
          metric:
            name: prometheus.googleapis.com|foo|gauge
          target:
            averageValue: "100"
            type: AverageValue
      type: Pods
      minReplicas: 1
    
  10. Per osservare la fare lo scale down del carico di lavoro, esegui questo comando:

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

    Il valore del campo REPLICAS cambia da 5 a 1. Per progettazione, questo avviene più lentamente rispetto allo scale up del numero di pod:

    NAME                          REFERENCE                                TARGETS        MINPODS   MAXPODS   REPLICAS   AGE
    custom-metric-prometheus-sd   Deployment/custom-metric-prometheus-sd   40/100          1         5         1          *
    
  11. Per pulire l'esempio di deployment, esegui questi comandi:

    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
    

Per ulteriori informazioni, consulta l'esempio di Prometheus nel repository dell'adattatore Stackdriver per le metriche personalizzate o vedi Scalare un'applicazione.

Utilizzare l'adattatore Prometheus

Le configurazioni esistenti di prometheus-adapter possono essere utilizzate per la scalabilità automatica con poche modifiche. La configurazione di prometheus-adapter per lo scaling utilizzando Managed Service per Prometheus presenta due limitazioni aggiuntive rispetto allo scaling utilizzando Prometheus upstream:

  • Le query devono essere instradate tramite il proxy della UI frontend di Prometheus, proprio come quando esegui query su Managed Service per Prometheus utilizzando l'API o la UI di Prometheus. Per prometheus-adapter, devi modificare il prometheus-adapter Deployment per cambiare il valore prometheus-url come segue:

    --prometheus-url=http://frontend.NAMESPACE_NAME.svc:9090/
    

    dove NAMESPACE_NAME è lo spazio dei nomi in cui viene eseguito il deployment del frontend.

  • Non puoi utilizzare un matcher di espressioni regolari su un nome di metrica nel campo .seriesQuery della configurazione delle regole. Devi invece specificare completamente i nomi delle metriche.

Poiché i dati potrebbero richiedere un po' di tempo in più per essere disponibili in Managed Service per Prometheus rispetto a Prometheus upstream, la configurazione di una logica di scalabilità automatica eccessivamente rapida potrebbe causare un comportamento indesiderato. Sebbene non vi sia alcuna garanzia sull'aggiornamento dei dati, in genere i dati sono disponibili per le query 3-7 secondi dopo l'invio a Managed Service per Prometheus, escludendo qualsiasi latenza di rete.

Tutte le query emesse da prometheus-adapter hanno ambito globale. Ciò significa che se hai applicazioni in due spazi dei nomi che emettono metriche con lo stesso nome, una configurazione HPA che utilizza questa metrica viene scalata utilizzando i dati di entrambe le applicazioni. Ti consigliamo di utilizzare sempre i filtri namespace o cluster in PromQL per evitare lo scaling utilizzando dati errati.

Per configurare una configurazione HPA di esempio utilizzando prometheus-adapter e la raccolta gestita, segui questi passaggi:

  1. Configura la raccolta gestita nel cluster.
  2. Esegui il deployment del proxy dell'interfaccia utente frontend di Prometheus nel tuo cluster. Se utilizzi la federazione delle identità per i carichi di lavoro per GKE, devi anche configurare e autorizzare un service account.
  3. Esegui il deployment dei manifest nella directory examples/hpa/ all'interno del repository prometheus-engine:
    • example-app.yaml: un esempio di deployment e servizio che emette metriche.
    • pod-monitoring.yaml: una risorsa che configura lo scraping delle metriche di esempio.
    • hpa.yaml: La risorsa HPA che configura lo scaling per il tuo workload.
  4. Assicurati che prometheus-adapter sia installato nel cluster. Questa operazione può essere eseguita eseguendo il deployment del manifest di installazione di esempio nel cluster. Questo manifest è configurato per:

    • Esegui una query su un proxy frontend di cui è stato eseguito il deployment nello spazio dei nomi default.
    • Esegui PromQL per calcolare e restituire la metrica http_requests_per_second dall'esempio di deployment.
  5. Esegui questi comandi, ciascuno in una sessione del terminale separata:

    1. Genera carico HTTP sul servizio 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. Osserva il gestore della scalabilità automatica orizzontale dei pod:
      kubectl get hpa prometheus-example-app --watch
    3. Osserva lo scale up del workload:
      kubectl get po -lapp.kubernetes.io/name=prometheus-example-app --watch
  6. Interrompi la generazione del carico HTTP utilizzando Ctrl+C e osserva la riduzione del carico di lavoro.

Risoluzione dei problemi

L'adattatore Stackdriver per le metriche personalizzate utilizza definizioni di risorse con gli stessi nomi di quelle dell'adattatore Prometheus, prometheus-adapter. Questa sovrapposizione di nomi significa che l'esecuzione di più di un adattatore nello stesso cluster causa errori.

L'installazione di Prometheus Adapter in un cluster in cui era installato in precedenza l'adattatore Custom Metrics Stackdriver potrebbe generare errori come FailedGetObjectMetric a causa di nomi in conflitto. Per risolvere il problema, potresti dover eliminare le API v1beta1.external.metrics.k8s.io, v1beta1.custom.metrics.k8s.io e v1beta2.custom.metrics.k8s.io registrate in precedenza dall'adattatore delle metriche personalizzate.

Suggerimenti per la risoluzione dei problemi:

  • Alcune metriche di sistema di Cloud Monitoring, come le metriche Pub/Sub, vengono ritardate di 60 secondi o più. Poiché Prometheus Adapter esegue query utilizzando il timestamp corrente, l'esecuzione di query su queste metriche utilizzando Prometheus Adapter potrebbe restituire erroneamente nessun dato. Per eseguire query sulle metriche ritardate, utilizza il modificatore offset in PromQL per modificare l'offset temporale della query dell'importo necessario.

  • Per verificare che il proxy dell'interfaccia utente frontend funzioni come previsto e che non ci siano problemi con le autorizzazioni, esegui questo comando in un terminale:

    kubectl -n NAMESPACE_NAME port-forward svc/frontend 9090
    

    Poi, apri un altro terminale ed esegui il comando seguente:

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

    Quando il proxy dell'interfaccia utente frontend funziona correttamente, la risposta nel secondo terminale è simile alla seguente:

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

    Se ricevi un errore 403, il proxy dell'interfaccia utente frontend non è configurato correttamente. Per informazioni su come risolvere un errore 403, consulta la guida Configurare e autorizzare un service account.

  • Per verificare che l'apiserver delle metriche personalizzate sia disponibile, esegui questo comando:

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

    Quando apiserver è disponibile, la risposta è simile alla seguente:

    $ 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
    
  • Per verificare che HPA funzioni come previsto, esegui questo comando:

    $ 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
    

    Quando la risposta contiene un'istruzione come FailedGetPodsMetric, l'HPA non funziona. Di seguito è illustrata una risposta alla chiamata describe quando l'HPA non funziona:

    $ 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
    

    Quando l'HPA non funziona, assicurati di generare metriche con load-generator. Puoi controllare direttamente l'API Custom Metrics con il comando:

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

    Un output riuscito è simile al seguente:

    $ 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"
            ]
         }
      ]
      }
    

    Se non sono presenti metriche, non ci saranno dati in "resources" nell'output, ad esempio:

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