Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Autoscaling Kubernetes con metriche custom: ci siamo quasi

By Christopher McGrathNov 10, 20235 min read

Questa pagina è disponibile anche in English, Deutsch, Español, Français, 日本語 e Português.

Le metriche custom tendono a essere più accurate e utili dell'autoscaling basato su CPU e RAM, ma lo scaling fondato su metriche custom ed esterne resta una frontiera ancora poco esplorata e migliorabile.

Kubernetes è una piattaforma in continua evoluzione. Per questo, ogni tanto, mi capita di rimettere mano a funzionalità che non utilizzavo da qualche anno. Di recente l'ho fatto con gli Horizontal Pod Autoscaler (HPA) e ho scoperto caratteristiche interessanti e limiti utili da conoscere, ma poco documentati o tutt'altro che evidenti.

Una "insidia" da segnalare è che apiVersion: autoscaling/v2 lascia intendere che gli HPA siano ormai un'API matura. In realtà, lo scaling basato su metriche custom ed esterne è ancora una frontiera selvaggia, su cui c'è parecchio da migliorare. Un peccato, perché le metriche custom sono in genere più accurate e utili dell'autoscaling basato su CPU e RAM.

Vediamo alcuni casi d'uso in cui le metriche custom migliorano la scalabilità e gli strumenti per metterli in pratica.

Casi d'uso

  • Una volta configurate le metriche custom e presentate in un formato compatibile con gli HPA, questi possono effettuare lo scaling sulla base di più metriche. La documentazione di Kubernetes ne riporta un esempio parziale: un HPA è configurato per scalare in base all'utilizzo della CPU, ai pacchetti al secondo e alle richieste al secondo. L'idea è che ogni metrica possa suggerire un numero diverso di repliche desiderate, ad esempio 3, 5 e 8. L'HPA può quindi scalare al valore più alto suggerito.

  • Le richieste al secondo in ingresso e la durata/latenza delle richieste sono metriche solide su cui scalare i servizi web.

    • Traefik, Linkerd e Istio sono comunemente impiegati per ingress, gateway e service mesh. Ognuno dispone di proxy Layer 7 in grado di esporre numerose metriche custom estremamente utili per ottimizzare l'autoscaling.
  • Le architetture con code o storage bucket, in cui vengono caricati gli oggetti da elaborare, possono scalare automaticamente i servizi che li processano in base al numero di elementi rilevati.

  • Le repliche minime variabili aiutano a bilanciare la capacità di gestire picchi di traffico con il contenimento dei costi. Se ha mai gestito un'app con repliche lente ad avviarsi o soggetta a picchi di traffico importanti, si sarà certamente trovato nella necessità di alzare il numero minimo di repliche per garantire la qualità del servizio.

    • Un esempio: se una replica regge 100 req/sec, può essere configurata per scalare automaticamente a 50 req/sec, evitando errori o latenze che si manifesterebbero oltre le 100 req/sec. Un minimo di 10 repliche assorbirebbe i picchi di traffico molto meglio di un minimo di due.
    • L'unico problema di questa tecnica è l'aumento dei costi, ma è ragionevole supporre che un'app possa avere picchi di traffico semi-prevedibili. Magari un minimo di due repliche è sufficiente al di fuori dell'orario di lavoro, mentre nelle ore in cui i picchi sono frequenti serve un minimo di 10, e un minimo di cinque negli altri momenti.
    • KEDA ha recentemente integrato un'opzione per inserire più metriche in una formula personalizzabile dall'utente, così da creare metriche composite combinando altre metriche in formule matematiche. In questo modo, conteggio desiderato = metrica di autoscaling + conteggio desiderato basato su cron permette di ottenere l'effetto di un numero minimo di repliche variabile.
  • Piattaforme serverless e functions-as-a-service ospitate su Kubernetes, come ad esempio:

    • keda.sh
    • knative.dev
    • openfaas.com

Limitazioni e conseguenze

Sulla carta tutto questo è interessante, e gli strumenti per realizzarlo non mancano. Qual è dunque la limitazione che impedisce agli HPA di fare davvero il salto di qualità?

La limitazione qui descritta ha conseguenze rilevanti sulla UX (user experience): https://github.com/kubernetes-sigs/custom-metrics-apiserver/issues/70

In sintesi: "Può esistere un solo custom metrics server". Se installa il diffusissimo kube-prometheus-stack con le impostazioni di default, otterrà Prometheus Adapter. E non potrà usare il keda-operator-metrics-apiserver di KEDA, il Knative Pod Autoscaler di Knative, l'autoscaler di OpenFaaS Pro, quello di Datadog o altri ancora. Tutti, infatti, funzionano ospitando un custom metric server. Credo sia anche per questo che KEDA conta così tanti scaler da sembrare il manifesto del feature creep: oltre 60 scaler, compresi quelli per Prometheus e Datadog. Una scelta che sembra eccessiva, finché non si capisce che in parte serve proprio ad aggirare questa limitazione.

Perché allora questa limitazione peggiora la UX? Partiamo da un esempio di cosa significhi avere una buona UX.

Lo stack Kube Prometheus e Helm sono diffusi per un motivo. Offrono un'ottima UX, e parte della loro ricetta segreta è il principio della "convenzione sulla configurazione". Forniscono valori di default sensati e una configurazione predefinita in cui centinaia o migliaia di oggetti YAML sono già pre-collegati secondo convenzioni, ottenendo una UX turnkey in cui moltissimo funziona subito, out of the box.

Il presupposto per arrivare a quella UX quasi magica è poter disporre di un namespace dedicato che non entri in conflitto con altri elementi: solo così è possibile stabilire convenzioni al suo interno e pre-collegare i componenti senza dover ricorrere a configurazioni artigianali.

Sono stati realizzati diversi proof-of-concept (PoC) per affrontare questo problema comune ed è stata persino redatta una proposta di miglioramento di Kubernetes per risolverlo, poi finita nel nulla. La mia speranza è che questo articolo accenda i riflettori sul problema e contribuisca a riportare l'attenzione sulle API di scaling basate su metriche custom.