Guida Pratica alla Regolazione dell'Horizontal Pod Autoscaler (HPA) di Kubernetes

Regola l'HPA di Kubernetes con richieste di risorse, metriche, comportamento di scaling, finestre di stabilizzazione e comandi di validazione.

Guida Pratica alla Regolazione dell'Horizontal Pod Autoscaler (HPA) di Kubernetes

L'Horizontal Pod Autoscaler (HPA) di Kubernetes può mantenere la tua app reattiva durante i picchi di traffico, ma solo se le metriche e i limiti riflettono il comportamento dell'app. Un HPA mal regolato potrebbe scalare troppo tardi, ridurre troppo rapidamente o non scalare mai perché mancano le richieste di risorse.

Questa guida mostra come regolare l'HPA di Kubernetes con CPU, memoria, metriche personalizzate, metriche esterne e controlli del comportamento di scaling.

Comprendere l'Horizontal Pod Autoscaler (HPA)

L'HPA scala automaticamente il numero di pod nella tua applicazione verso l'alto o verso il basso per soddisfare la domanda corrente. Monitora continuamente metriche specificate e le confronta con i valori target. Se la metrica osservata supera il target, HPA avvia un evento di scale-up; se scende al di sotto, attiva uno scale-down. Questo aggiustamento dinamico garantisce che la tua applicazione abbia risorse sufficienti per funzionare in modo ottimale senza sovra-provisioning.

HPA può scalare in base a:

  • Metriche delle Risorse: Principalmente l'utilizzo di CPU e memoria (disponibili tramite l'API metrics.k8s.io, solitamente servita dal Kubernetes Metrics Server).
  • Metriche Personalizzate: Metriche specifiche dell'applicazione esposte tramite l'API custom.metrics.k8s.io (ad esempio, richieste al secondo, profondità della coda, connessioni attive). Queste richiedono tipicamente un adattatore come prometheus-adapter.
  • Metriche Esterne: Metriche provenienti da fonti esterne al cluster esposte tramite l'API external.metrics.k8s.io (ad esempio, dimensione della coda Google Cloud Pub/Sub, lunghezza della coda AWS SQS). Queste richiedono anche un server API di metriche personalizzate in grado di recuperare metriche esterne.

Prerequisiti per una Regolazione Efficace dell'HPA

Prima di immergersi nelle configurazioni HPA, assicurati che questi elementi fondamentali siano in atto:

1. Definire Richieste e Limiti di Risorsa Accurati

Questo è forse il prerequisito più cruciale. L'HPA si basa fortemente su richieste di CPU e memoria correttamente definite per calcolare le percentuali di utilizzo. Se un pod non ha richieste di CPU definite, HPA non può calcolare il suo utilizzo di CPU, rendendo impossibile lo scaling basato su CPU.

  • Richieste: Definisci le risorse minime garantite per i tuoi container. HPA utilizza questi valori per determinare l'utilizzo target per pod.
  • Limiti: Definisci le risorse massime che un container può consumare. I limiti impediscono a un singolo pod di consumare risorse eccessive e di influenzare altri pod sullo stesso nodo.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-container
        image: my-image:latest
        resources:
          requests:
            cpu: "200m"  # 20% di un core CPU
            memory: "256Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"

2. Installare Kubernetes Metrics Server

Affinché HPA possa utilizzare le metriche di utilizzo di CPU e memoria, il Kubernetes Metrics Server deve essere installato nel tuo cluster. Raccoglie le metriche delle risorse dai Kubelet e le espone tramite l'API metrics.k8s.io.

3. Osservabilità dell'Applicazione

Per metriche personalizzate o esterne, la tua applicazione deve esporre metriche rilevanti (ad esempio, tramite un endpoint Prometheus) e avrai bisogno di un modo per raccogliere ed esporre queste metriche all'API Kubernetes, tipicamente utilizzando un adattatore Prometheus o un server API di metriche personalizzate.

Configurare HPA: Parametri Principali

Diamo un'occhiata alla struttura di base di un manifest HPA:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: my-app-hpa
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-app
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

Parametri chiave:

  • scaleTargetRef: Definisce la risorsa target (ad esempio, Deployment) che HPA scalerà. Specifica il suo apiVersion, kind e name.
  • minReplicas: Il numero minimo di pod a cui HPA si ridurrà. È buona pratica impostarlo ad almeno 1 o 2 per l'alta disponibilità, anche sotto carico zero.
  • maxReplicas: Il numero massimo di pod a cui HPA si espanderà. Funge da salvaguardia contro lo scaling incontrollato e limita i costi.
  • metrics: Un array che definisce le metriche che HPA deve monitorare.
    • type: Può essere Resource, Pods, Object o External.
    • resource.name: Per il tipo Resource, specifica cpu o memory.
    • target.type: Per il tipo Resource, Utilization (percentuale della risorsa richiesta) o AverageValue (valore assoluto).
    • averageUtilization: Per il tipo Utilization, la percentuale target. HPA calcola il numero desiderato di pod in base a utilizzo_corrente / utilizzo_target * conteggio_pod_corrente.

Regolare HPA per Reattività e Stabilità

Oltre alla configurazione di base, HPA offre opzioni di regolazione avanzate, specialmente con autoscaling/v2 (o v2beta2 in versioni precedenti), per gestire il comportamento di scaling in modo più granulare.

1. Target di CPU e Memoria (averageUtilization / averageValue)

Impostare il giusto utilizzo target è cruciale. Un target più basso significa scaling anticipato (più reattivo, potenzialmente più costoso), mentre un target più alto significa scaling ritardato (meno reattivo, potenzialmente più economico ma rischiando un degrado delle prestazioni).

  • Come Determinare i Target Ottimali: I test di carico e la profilazione sono i tuoi migliori amici. Aumenta gradualmente il carico sulla tua applicazione monitorando l'uso delle risorse e le metriche di prestazione (latenza, tassi di errore). Identifica l'utilizzo di CPU/memoria al quale la tua applicazione inizia a degradare le prestazioni. Imposta il tuo target HPA al di sotto di questa soglia, tipicamente nell'intervallo 60-80% per la CPU.
  • Equilibrio: Punta a un target che lasci sufficiente margine per picchi imprevisti ma non sia così basso da essere costantemente sovra-provisionato.

2. Comportamento di Scaling (campo behavior)

Introdotto in HPA autoscaling/v2, il campo behavior fornisce un controllo granulare sugli eventi di scale-up e scale-down, prevenendo il "thrashing" (cicli rapidi di scale-up e scale-down).

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: my-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-app
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 60 # Aspetta 60 secondi prima di scalare di nuovo verso l'alto
      policies:
      - type: Pods
        value: 4
        periodSeconds: 15 # Aggiungi massimo 4 pod ogni 15 secondi
      - type: Percent
        value: 100
        periodSeconds: 15 # Oppure raddoppia i pod correnti ogni 15 secondi (qualunque sia meno restrittivo)
    scaleDown:
      stabilizationWindowSeconds: 300 # Aspetta 5 minuti prima di scalare verso il basso
      policies:
      - type: Percent
        value: 50
        periodSeconds: 60 # Rimuovi massimo il 50% dei pod ogni 60 secondi
      selectPolicy: Max # Scegli la politica che permette il maggior cambiamento di scale-down consentito

Configurazione scaleUp:

  • stabilizationWindowSeconds: Questo smussa le raccomandazioni di scaling su una finestra temporale recente. Lo scale-up di solito utilizza una finestra breve in modo che l'app possa reagire rapidamente.
  • policies: Definisce come vengono aggiunti i pod durante un evento di scale-up. Puoi definire più politiche, e HPA utilizzerà quella che permette il numero più alto di pod (scale-up più aggressivo).
    • type: Pods: Scala verso l'alto di un numero fisso di pod. value specifica il numero di pod da aggiungere. periodSeconds definisce la finestra temporale su cui si applica questa politica.
    • type: Percent: Scala verso l'alto di una percentuale del conteggio attuale dei pod. value è la percentuale.

Configurazione scaleDown:

  • stabilizationWindowSeconds: Più critico per scaleDown, specifica per quanto tempo HPA deve osservare metriche al di sotto del target prima di considerare lo scale-down. Una finestra più lunga (ad esempio, 300-600 secondi) previene lo scale-down prematuro durante pause temporanee, evitando "cold starts" e cali di prestazioni. Questa è un'impostazione cruciale per ambienti stabili.

  • policies: Simile a scaleUp, definisce come vengono rimossi i pod. HPA utilizza la politica che risulta nel numero più basso di pod (scale-down più aggressivo) se selectPolicy è Min, o la politica che risulta nel numero più alto di pod se selectPolicy è Max.

    • type: Pods: Rimuove un numero fisso di pod.
    • type: Percent: Rimuove una percentuale dei pod correnti.
  • selectPolicy: Determina quale politica applicare quando sono definite più politiche di scaleDown. Max è l'impostazione predefinita e seleziona la politica che permette il maggior cambiamento di scala. Usa Min quando desideri uno scale-down più conservativo.

  • Avvertenza: Fai attenzione con politiche di scaleDown aggressive o stabilizationWindowSeconds brevi per scaleDown. Se la tua applicazione ha tempi di inizializzazione lunghi o gestisce connessioni stateful, uno scale-down rapido può portare a interruzioni del servizio o aumento della latenza per gli utenti.

Metriche e Strategie Avanzate per HPA

Sebbene CPU e memoria siano comuni, molte applicazioni scalano meglio su metriche personalizzate o esterne che riflettono il loro carico di lavoro effettivo.

1. Metriche Personalizzate

Usa metriche personalizzate quando CPU/memoria non è un indicatore diretto del carico o del collo di bottiglia delle prestazioni della tua applicazione. Esempi: richieste HTTP al secondo (QPS), connessioni attive, lunghezza della coda dei messaggi, arretrato del batch job.

Per utilizzare metriche personalizzate:

  1. La tua applicazione deve esporre queste metriche (ad esempio, tramite un esportatore Prometheus).
  2. Distribuisci un adattatore di metriche personalizzate (ad esempio, prometheus-adapter) che possa raccogliere queste metriche ed esporle tramite l'API custom.metrics.k8s.io.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: my-app-hpa-qps
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-app
  minReplicas: 2
  maxReplicas: 15
  metrics:
  - type: Pods # Oppure Object se la metrica è per l'intero deployment
    pods:
      metric:
        name: http_requests_per_second # Il nome della metrica esposta dalla tua applicazione/adattatore
      target:
        type: AverageValue
        averageValue: "10k" # Target 10.000 richieste al secondo per pod

2. Metriche Esterne

Le metriche esterne sono utili quando il carico di lavoro della tua applicazione è guidato da un sistema esterno non in esecuzione direttamente su Kubernetes. Esempi: profondità della coda AWS SQS, lag del topic Kafka, arretrato della sottoscrizione Pub/Sub.

Per utilizzare metriche esterne:

  1. Hai bisogno di un server API di metriche personalizzate che possa recuperare metriche dal tuo sistema esterno (ad esempio, un adattatore specifico per AWS CloudWatch o GCP Monitoring).
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: my-worker-hpa-sqs
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-worker
  minReplicas: 1
  maxReplicas: 20
  metrics:
  - type: External
    external:
      metric:
        name: aws_sqs_queue_messages_visible # Nome della metrica dalla tua fonte esterna
        selector:
          matchLabels:
            queue: my-queue-name
      target:
        type: AverageValue
        averageValue: "100" # Target 100 messaggi visibili nella coda per pod

3. Metriche Multiple

HPA può essere configurato per monitorare più metriche simultaneamente. Quando vengono specificate più metriche, HPA calcola il conteggio di repliche desiderato per ciascuna metrica indipendentemente e poi seleziona il più alto di questi conteggi di repliche desiderati. Questo garantisce che l'applicazione si adatti sufficientemente per tutte le dimensioni di carico osservate.

# ... (boilerplate HPA)
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Pods
    pods:
      metric:
        name: http_requests_per_second
      target:
        type: AverageValue
        averageValue: "10k"

Monitoraggio e Validazione

Una regolazione efficace dell'HPA è un processo iterativo che richiede monitoraggio e validazione continui:

  • Osserva gli Eventi HPA: Usa kubectl describe hpa <nome-hpa> per vedere lo stato, gli eventi e le decisioni di scaling di HPA. Questo fornisce preziose informazioni sul perché HPA ha scalato verso l'alto o verso il basso.
  • Monitora Metriche e Repliche: Usa il tuo stack di osservabilità (ad esempio, Prometheus, Grafana) per visualizzare l'uso delle risorse della tua applicazione (CPU, memoria), le metriche personalizzate/esterne e il numero effettivo di repliche dei pod nel tempo. Correlali con i cambiamenti nel carico in arrivo.
  • Test di Carico: Simula carichi previsti e di picco per validare la reattività di HPA e assicurarti che la tua applicazione funzioni come previsto sotto stress. Regola i parametri HPA in base a questi test.

Migliori Pratiche per la Regolazione dell'HPA

  • Inizia con Richieste/Limiti di Risorsa Ben Definiti: Sono la base di un HPA accurato basato sulle risorse. Senza di essi, HPA non può funzionare efficacemente per CPU/memoria.
  • Imposta minReplicas e maxReplicas Realistici: minReplicas fornisce una base per la disponibilità, mentre maxReplicas funge da rete di sicurezza contro costi incontrollati ed esaurimento delle risorse.
  • Regola Gradualmente l'Utilizzo Target: Inizia con un target CPU leggermente conservativo (ad esempio, 60-70%) e itera. Non puntare al 100% di utilizzo, poiché non lascia margine per picchi di latenza o elaborazione.
  • Sfrutta stabilizationWindowSeconds: Essenziale per prevenire oscillazioni rapide di scaling. Usa una finestra più lunga per scaleDown (ad esempio, 5-10 minuti) rispetto a scaleUp (ad esempio, 1-2 minuti) per garantire stabilità.
  • Dai Priorità alle Metriche Specifiche dell'Applicazione: Se CPU o memoria non sono direttamente correlati ai colli di bottiglia delle prestazioni della tua applicazione, usa metriche personalizzate o esterne per uno scaling più accurato ed efficiente.
  • Monitora, Testa, Itera: La regolazione dell'HPA non è un'installazione una tantum. Il comportamento dell'applicazione, i modelli di traffico e l'infrastruttura sottostante possono cambiare. Rivedi regolarmente le prestazioni di HPA e regola le impostazioni secondo necessità.
  • Comprendi le Caratteristiche di Scaling della Tua Applicazione: Scala linearmente con le richieste? Ha tempi di avvio lunghi? È stateful? Queste caratteristiche influenzano la tua strategia HPA.

Considerazioni Finali

Tratta la regolazione dell'HPA come un ciclo di feedback. Inizia con richieste di risorse accurate, imposta minReplicas e maxReplicas realistici, scegli una metrica che tracci la domanda reale e valida il comportamento di scale-up e scale-down con test di carico prima che il traffico di produzione dipenda da esso.