Alla ricerca del dimensionamento corretto: come capire Requests e Limits del mio POD Kubernetes

25/07/2023

Una delle insidie più nascoste quando si lavora in ambito Kubernetes riguarda il corretto dimensionamento, in termini di utilizzo di CPU e memoria, dei POD applicativi.

Molto spesso tale tematica viene sottovalutata e si tende a dare poca importanza all’assegnazione delle risorse ai container.

In questo breve articolo cercheremo di dare delle nozioni utili alla comprensione del problema e dei suggerimenti su come operare e come accorgersi tempestivamente se stiamo andando nella direzione sbagliata.

Requests e Limits: cosa sono?

In Kubernetes, i “Limits” sono definiti come la quantità massima di una risorsa che può essere utilizzata da un container. Questo significa che il contenitore non può mai consumare più della quantità di memoria o CPU indicata.

D’altra parte, le “Requests” sono la quantità minima garantita di una risorsa riservata per un container.

Un esempio pratico

Prendiamo ad esempio il seguente deployment:

Possiamo dedurne quanto segue:

  1. L’effettiva richiesta di risorse del POD è di 400 MiB di memoria e 600 millicores di CPU. C’è bisogno di un nodo con abbastanza spazio allocabile libero per schedularlo.
  2. Le quote di CPU per il container Redis saranno di 512, mentre per il container Busybox saranno di 102. Kubernetes assegna sempre 1024 quote a ogni core, quindi Redis: 1024 * 0,5 core ≅ 512 e Busybox: 1024 * 0,1 core ≅
  3. Redis sarà terminato in caso di esaurimento della memoria se cerca di allocare più di 600 MB di RAM, causando molto probabilmente il fallimento del POD.
  4. Redis subirà un rallentamento della CPU se cerca di utilizzare più di 100 ms di CPU ogni 100 ms (dato che abbiamo 4 core, il tempo disponibile sarebbe di 400 ms ogni 100 ms), causando degradazione delle prestazioni.
  5. Busybox sarà terminato in caso di esaurimento della memoria se cerca di allocare più di 200 MB di RAM, risultando in un POD fallito.
  6. Busybox subirà un rallentamento della CPU se cerca di utilizzare più di 30 ms di CPU ogni 100 ms, causando degradazione delle prestazioni.

Precisazioni sullo scheduling dei POD

Kubernetes definisce le requests come una quantità minima garantita di una risorsa.

Quando un POD viene programmato, il kube-scheduler verifica le requests di Kubernetes per assegnarlo a un particolare Nodo che possa soddisfare almeno quella quantità per tutti i container presenti nel POD. Se l’importo richiesto è superiore alla risorsa disponibile, il POD non verrà mandato in esecuzione e rimarrà in stato di “Pending” (in attesa).

Kubernetes definisce i limits come la quantità massima di una risorsa che può essere utilizzata da un container, ciò significa che non può mai consumare più della quantità di memoria o CPU indicata come limite.

Tuttavia, occorre fare distinzione nel comportamento tra CPU e memoria.

La CPU è una risorsa comprimibile, il che significa che può essere estesa per soddisfare tutta la domanda. Nel caso in cui i processi richiedano troppa CPU, alcuni di essi verranno rallentati (throttled).

A differenza della CPU, la memoria non può essere condivisa o estesa per soddisfare tutte le richieste in modo dinamico. Se la memoria disponibile sul nodo del cluster Kubernetes è insufficiente per soddisfare tutte le richieste dei processi in esecuzione, alcuni di essi verranno terminati. Il processo terminato a causa di mancanza di memoria verrà segnalato come “OOM killed“, dove “OOM” sta per “Out of Memory”.

Performance

Il corretto utilizzo e dimensionamento di requests e limits non solo è importante per la salute del cluster Kubernetes, ma influisce tantissimo anche sul concetto di performance.

Kubernetes classifica i POD che vengono eseguiti e assegna a ciascuno una specifica classe di livello di servizio (QoS – Quality of Service). Kubernetes utilizza questa classificazione per influenzare come vengono gestiti i diversi POD. La classificazione avviene in base alle richieste di risorse dei container, insieme a come queste richieste sono correlate ai limiti di risorse.

Esistono le seguenti classi QoS, in ordine decrescente di priorità:

  • Guaranteed
    • I valori di requests e limits coincidono. Massima priorità a container che sono categorizzati in questa classe. Difficilmente andranno incontro a processi di eviction se non in caso di forte problematiche sui nodi
  • Burstable
    • I valori di request e limits sono assegnati ma non sono identici. Possono andare in sofferenza in case di pressioni sul nodo ma non possono essere terminati se ci sono ancora container in classe BestEffort in esecuzione
  • BestEffort
    • Non sono stati specificati valori né per requests né per limits. È la peggior condizione di performance possibile. Tali POD possono incorrere in eviction al minimo problema di pressione del nodo, per riassegnare le risorse alle classi a priorità maggiore

Molto spesso si vedono POD senza valori di soglia specificati, quindi in classe BestEffort, con la speranza che utilizzino tutte le risorse disponibili del nodo e che quindi vadano “più forte”. In realtà in ambiente produttivi a medio/alta densità questa si rivela una falsa speranza, perché saranno POD instabili che potranno essere “sacrificati” in qualsiasi momento.

Come scegliere Requests e Limits

Non esiste un vero e proprio algoritmo matematico agnostico per la scelta di valori corretti. Tuttavia, ci si può basare sull’esperienza, alcune best practice e strumenti che possono aiutare nell’osservazione dei consumi.

Riguardo quest’ultimo punto, è bene sottolineare come l’utilizzo all’interno della propria architettura infrastrutturale di un adeguato strumento di monitoraggio e osservabilità semplifichi enormemente la scelta corretta di tali parametri.

Solo tramite la costante osservazione delle metriche di consumo di CPU e memoria e il trend degli andamenti nel tempo (andando a storicizzare per esempio picchi di utilizzo) si può essere in grado di avere idee certe e anche andare a scoprire preventivamente e tempestivamente eventuali errori di configurazione di tali soglie.

Strumenti evoluti come Sysdig vanno proprio in questa direzione, abilitando il corretto rightsizing dell’infrastruttura e fornendo uno strumento fondamentale per il troubleshooting sia in ottica di funzionamento operativo che di performance analysis.

Link utili:

Credits: https://sysdig.com/blog/kubernetes-limits-requests/