Di recente abbiamo passato il nostro ambiente di produzione a Kubernetes. Vorrei applicare i limiti della CPU sui contenitori. Sto ricevendo metriche CPU contrastanti che non si adattano insieme. Ecco la mia configurazione:
- Agenti DataDog in esecuzione come a
Daemonset
- Applicazioni esistenti in esecuzione senza limiti CPU
- I contenitori in questione sono applicazioni Ruby multi-thread
- Due parametri:
kubernetes.cpu.usage.{avg,max}
edocker.cpu.usage
c4.xlarge
nodi cluster (4 vCPU o 4000m in termini di Kubernetes)
kubernetes.cpu.usage.max
riporta ~ 600 m per i contenitori in questione. docker.cpu.usage
riporta ~ 60%. Ne consegue che un limite della CPU di 1000 m sarebbe una capacità più che sufficiente durante il normale funzionamento.
Ho impostato il limite a 1000m. Quindi docker.container.throttles
aumenta in modo significativo kubernetes.cpu.usage.max
e docker.cpu.usage
resta invariato. Durante questo periodo, il sistema è caduto in ginocchio. Questo non ha senso per me.
Ho studiato le statistiche di Docker. Sembra che docker stats
(e l'API sottostante) normalizzino il carico in base ai core della CPU. Quindi, nel mio caso, docker.cpu.usage
del 60% arriva (4000m * 0,60) a 2400m in termini di Kubernetes. Tuttavia, ciò non è correlato ai numeri di Kubernetes. Ho fatto un altro esperimento per verificare la mia ipotesi che i numeri di Kubernetes siano errati. Ho impostato il limite a 2600 m (per un po 'di spazio in più). Ciò non ha comportato alcun throttles. Tuttavia Kubernetes ha osservato che l'utilizzo della CPU non è cambiato. Questo mi lascia confuso.
Quindi le mie domande sono:
- Ti sembra un bug in Kubernetes (o qualcosa nello stack?)
- La mia comprensione è corretta?
La mia domanda di follow-up riguarda come determinare correttamente la CPU per le applicazioni Ruby. Un contenitore utilizza Puma. Questo è un server web multi-thread con una quantità configurabile di thread. Le richieste HTTP sono gestite da uno dei thread. La seconda applicazione è un server dell'usato che utilizza il server thread. Ogni connessione TCP in entrata è gestita dal proprio thread. Il thread termina alla chiusura della connessione. Ruby come GIL (Global Interpreter Lock), quindi solo un thread può eseguire il codice Ruby alla volta. Ciò consente a più thread di eseguire IO e cose del genere.
Penso che l'approccio migliore sia limitare il numero di thread in esecuzione in ciascuna applicazione e approssimare i limiti della CPU Kubernetes in base al numero di thread. I processi non stanno biforcando, quindi è più difficile prevedere l'utilizzo totale della CPU.
La domanda qui è: come prevedere correttamente l'utilizzo della CPU e i limiti per queste applicazioni?