Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

27 aprile alla conferenza Sciopero 2019, nell'ambito della sezione “DevOps”, è stato presentato il report “Autoscaling e gestione delle risorse in Kubernetes”. Descrive come utilizzare K8 per garantire un'elevata disponibilità delle applicazioni e garantire le massime prestazioni.

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

Per tradizione, siamo lieti di presentare video del resoconto (44 minuti, molto più informativo dell'articolo) e il riassunto principale in forma testuale. Andare!

Analizziamo parola per parola l'argomento della relazione e cominciamo dalla fine.

kubernetes

Supponiamo di avere contenitori Docker sul nostro host. Per quello? Per garantire ripetibilità e isolamento, che a loro volta consentono una distribuzione semplice e corretta, CI/CD. Abbiamo molti di questi veicoli con container.

Cosa offre Kubernetes in questo caso?

  1. Smettiamo di pensare a queste macchine e iniziamo a lavorare con il “cloud” gruppo di contenitori o baccelli (gruppi di contenitori).
  2. Inoltre, non pensiamo nemmeno ai singoli pod, ma ne gestiamo di piùоgruppi più grandi. Come primitive di alto livello consentiteci di dire che esiste un modello per l'esecuzione di un determinato carico di lavoro ed ecco il numero di istanze richiesto per eseguirlo. Se successivamente modifichiamo il modello, tutte le istanze cambieranno.
  3. Con API dichiarativa Invece di eseguire una sequenza di comandi specifici, descriviamo la “struttura del mondo” (in YAML), creata da Kubernetes. E ancora: quando cambia la descrizione, cambierà anche la sua effettiva visualizzazione.

Правление ресурсами

CPU

Eseguiamo nginx, php-fpm e mysql sul server. Questi servizi avranno effettivamente ancora più processi in esecuzione, ognuno dei quali richiede risorse di elaborazione:

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)
(i numeri sulla slide sono “pappagalli”, il bisogno astratto di potenza di calcolo di ogni processo)

Per facilitare il lavoro, è logico combinare i processi in gruppi (ad esempio, tutti i processi nginx in un gruppo “nginx”). Un modo semplice e ovvio per farlo è mettere ciascun gruppo in un contenitore:

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

Per continuare, è necessario ricordare cos'è un contenitore (in Linux). La loro comparsa è stata resa possibile grazie a tre caratteristiche chiave del kernel, implementate molto tempo fa: funzionalità, spazi dei nomi и cgroup. E l'ulteriore sviluppo è stato facilitato da altre tecnologie (comprese comode "shell" come Docker):

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

Nel contesto del rapporto, siamo interessati solo a cgroup, perché i gruppi di controllo sono la parte della funzionalità dei contenitori (Docker, ecc.) che implementa la gestione delle risorse. I processi combinati in gruppi, come volevamo, sono gruppi di controllo.

Torniamo ai requisiti della CPU per questi processi e ora per i gruppi di processi:

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)
(Ripeto che tutti i numeri sono espressione astratta del bisogno di risorse)

Allo stesso tempo, la CPU stessa dispone di una certa risorsa limitata (nell'esempio questo è 1000), di cui tutti possono mancare (la somma dei bisogni di tutti i gruppi è 150+850+460=1460). Cosa accadrà in questo caso?

Il kernel inizia a distribuire le risorse e lo fa “equamente”, dando la stessa quantità di risorse a ciascun gruppo. Ma nel primo caso ce ne sono più del necessario (333>150), quindi l'eccesso (333-150=183) rimane in riserva, anch'esso equamente distribuito tra altri due contenitori:

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

Di conseguenza: il primo container aveva abbastanza risorse, il secondo non aveva abbastanza risorse, il terzo non aveva abbastanza risorse. Questo è il risultato delle azioni pianificatore "onesto" in Linux - CFS. Il suo funzionamento può essere regolato utilizzando l'assegnazione peso ciascuno dei contenitori. Ad esempio, in questo modo:

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

Consideriamo il caso di mancanza di risorse nel secondo contenitore (php-fpm). Tutte le risorse del contenitore sono distribuite equamente tra i processi. Di conseguenza, il processo principale funziona bene, ma tutti i lavoratori rallentano, ricevendo meno della metà di ciò di cui hanno bisogno:

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

Ecco come funziona lo scheduler CFS. Chiameremo ulteriormente i pesi che assegniamo ai contenitori richieste. Perché è così - vedi oltre.

Diamo un'occhiata all'intera situazione dall'altra parte. Come sapete, tutte le strade portano a Roma e, nel caso di un computer, alla CPU. Una CPU, molte attività: serve un semaforo. Il modo più semplice per gestire le risorse è il “semaforo”: assegnano a un processo un tempo di accesso fisso alla CPU, poi a quello successivo, ecc.

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

Questo approccio è chiamato quote rigide (limitazione dura). Ricordiamolo semplicemente come limiti. Tuttavia, se si distribuiscono i limiti a tutti i contenitori, sorge un problema: mysql stava guidando lungo la strada e ad un certo punto il suo bisogno di CPU è terminato, ma tutti gli altri processi sono costretti ad aspettare finché la CPU oziare.

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

Torniamo al kernel Linux e alla sua interazione con la CPU: il quadro generale è il seguente:

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

cgroup ha due impostazioni: essenzialmente si tratta di due semplici "twist" che ti consentono di determinare:

  1. il peso del contenitore (richieste) è parti;
  2. percentuale del tempo totale della CPU per lavorare sulle attività del contenitore (limiti) è quota.

Come misurare la CPU?

Ci sono diversi modi:

  1. che cosa pappagalli, nessuno lo sa: devi negoziare ogni volta.
  2. interesse più chiaro, ma relativo: il 50% di un server con 4 core e con 20 core sono cose completamente diverse.
  3. Puoi usare quelli già menzionati peso, che Linux conosce, ma sono anche relativi.
  4. L'opzione più adeguata è misurare le risorse di calcolo in secondi. Quelli. in secondi di tempo del processore rispetto ai secondi di tempo reale: 1 secondo di tempo del processore è stato dato per 1 secondo reale: questo è un intero core della CPU.

Per rendere ancora più facile parlare, iniziarono a misurare direttamente noccioli, intendendo con loro lo stesso tempo di CPU rispetto a quello reale. Poiché Linux comprende i pesi, ma non tanto il tempo CPU/core, era necessario un meccanismo per tradurre dall'uno all'altro.

Consideriamo un semplice esempio con un server con 3 core CPU, dove a tre pod verranno assegnati pesi (500, 1000 e 1500) che possono essere facilmente convertiti nelle parti corrispondenti dei core loro assegnati (0,5, 1 e 1,5).

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

Se prendi un secondo server, dove ci saranno il doppio dei core (6), e posizioni lì gli stessi pod, la distribuzione dei core può essere facilmente calcolata semplicemente moltiplicando per 2 (1, 2 e 3, rispettivamente). Ma un momento importante si verifica quando su questo server appare un quarto pod, il cui peso, per comodità, sarà 3000. Toglie parte delle risorse della CPU (metà dei core) e per i restanti pod vengono ricalcolati (dimezzati):

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

Kubernetes e risorse della CPU

In Kubernetes, le risorse della CPU vengono solitamente misurate milliadrax, cioè. Come peso base vengono presi 0,001 nuclei. (La stessa cosa nella terminologia Linux/cgroups è chiamata condivisione CPU, sebbene, più precisamente, 1000 millicore = 1024 condivisioni CPU.) K8s garantisce di non posizionare sul server più pod di quante siano le risorse della CPU per la somma dei pesi di tutti i pod.

Come avviene questo? Quando aggiungi un server a un cluster Kubernetes, viene segnalato il numero di core CPU disponibili. E quando si crea un nuovo pod, lo scheduler Kubernetes sa di quanti core avrà bisogno questo pod. Pertanto, il pod verrà assegnato a un server in cui sono presenti core sufficienti.

Cosa succederà se no è specificata la richiesta (ovvero il pod non ha un numero definito di core di cui ha bisogno)? Scopriamo come Kubernetes generalmente conta le risorse.

Per un pod puoi specificare sia le richieste (schedulatore CFS) che i limiti (ricordi il semaforo?):

  • Se sono specificati uguali, al pod viene assegnata una classe QoS garantito. Questo numero di core sempre a sua disposizione è garantito.
  • Se la richiesta è inferiore al limite: classe QoS scoppiabile. Quelli. Ci aspettiamo che un pod, ad esempio, utilizzi sempre 1 core, ma questo valore non è una limitazione per esso: a volte pod può usarne di più (quando il server ha risorse libere per questo).
  • C'è anche una classe QoS miglior sforzo — include proprio quei pod per i quali non è specificata la richiesta. Le risorse vengono date loro per ultime.

Память

Con la memoria la situazione è simile, ma leggermente diversa: la natura di queste risorse è diversa. In generale, l’analogia è la seguente:

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

Vediamo come vengono implementate le richieste in memoria. Lascia che i pod vivano sul server, modificando il consumo di memoria, finché uno di essi non diventa così grande da esaurire la memoria. In questo caso, appare il killer OOM e uccide il processo più grande:

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

Questo non sempre ci soddisfa, quindi è possibile regolare quali processi sono importanti per noi e non dovrebbero essere uccisi. Per fare ciò, utilizzare il parametro oom_punteggio_agg.

Torniamo alle classi QoS della CPU e tracciamo un'analogia con i valori oom_score_adj che determinano le priorità di consumo di memoria per i pod:

  • Il valore oom_score_adj più basso per un pod - -998 - significa che tale pod dovrebbe essere ucciso per ultimo, questo garantito.
  • Il più alto - 1000 - è miglior sforzo, tali baccelli vengono uccisi per primi.
  • Per calcolare i valori rimanenti (scoppiabile) esiste una formula, la cui essenza si riduce al fatto che più risorse ha richiesto un pod, meno è probabile che venga ucciso.

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

La seconda "torsione" - limite_in_byte - per limiti. Con esso tutto è più semplice: assegniamo semplicemente la quantità massima di memoria emessa, e qui (a differenza della CPU) non si tratta di come misurarla (memoria).

In totale

Viene fornito ogni pod in Kubernetes requests и limits - entrambi i parametri per CPU e memoria:

  1. in base alle richieste funziona lo scheduler Kubernetes, che distribuisce i pod tra i server;
  2. in base a tutti i parametri viene determinata la classe QoS del pod;
  3. I pesi relativi vengono calcolati in base alle richieste della CPU;
  4. lo scheduler CFS è configurato in base alle richieste della CPU;
  5. OOM killer è configurato in base alle richieste di memoria;
  6. viene configurato un “semaforo” in base ai limiti della CPU;
  7. In base ai limiti di memoria, viene configurato un limite per il cgroup.

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

In generale, questa immagine risponde a tutte le domande su come avviene la parte principale della gestione delle risorse in Kubernetes.

Scalabilità automatica

Autoscaler cluster K8s

Immaginiamo che l'intero cluster sia già occupato e sia necessario creare un nuovo pod. Anche se il pod non può essere visualizzato, il suo stato rimane bloccato Attesa Pagamento. Affinché appaia, possiamo connettere un nuovo server al cluster o... installare cluster-autoscaler, che lo farà per noi: ordinare una macchina virtuale dal fornitore del cloud (utilizzando una richiesta API) e collegarla al cluster , dopodiché verrà aggiunto il pod .

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

Si tratta della scalabilità automatica del cluster Kubernetes, che funziona alla grande (secondo la nostra esperienza). Tuttavia, come altrove, anche qui ci sono alcune sfumature...

Finché aumentavamo le dimensioni del cluster, tutto andava bene, ma cosa succede quando il cluster cominciò a liberarsi? Il problema è che la migrazione dei pod (per liberare host) è tecnicamente molto difficile e costosa in termini di risorse. Kubernetes utilizza un approccio completamente diverso.

Considera un cluster di 3 server con distribuzione. Ha 6 pod: ora ce ne sono 2 per ogni server. Per qualche motivo volevamo spegnere uno dei server. Per fare ciò utilizzeremo il comando kubectl drain, Quale:

  • proibirà l'invio di nuovi pod a questo server;
  • eliminerà i pod esistenti sul server.

Poiché Kubernetes è responsabile del mantenimento del numero di pod (6), semplicemente ricreerà li su altri nodi, ma non su quello disabilitato, poiché è già contrassegnato come non disponibile per ospitare nuovi pod. Questa è una meccanica fondamentale per Kubernetes.

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

Tuttavia, anche qui c'è una sfumatura. In una situazione simile, per StatefulSet (invece di Deployment), le azioni saranno diverse. Ora abbiamo già un'applicazione stateful, ad esempio tre pod con MongoDB, uno dei quali presenta qualche tipo di problema (i dati sono danneggiati o un altro errore che impedisce il corretto avvio del pod). E decidiamo ancora una volta di disabilitare un server. Cosa accadrà?

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

MongoDB potuto morire perché ha bisogno del quorum: per un cluster di tre installazioni, almeno due devono funzionare. Tuttavia, questo non sta succedendo - grazie a PodDisruptionBudget. Questo parametro determina il numero minimo richiesto di pod funzionanti. Sapere che uno dei pod MongoDB non funziona più e vedere che PodDisruptionBudget è impostato per MongoDB minAvailable: 2, Kubernetes non ti consentirà di eliminare un pod.

In conclusione: affinché lo spostamento (e di fatto la ricreazione) dei pod funzioni correttamente al rilascio del cluster, è necessario configurare PodDisruptionBudget.

Ridimensionamento orizzontale

Consideriamo un'altra situazione. Esiste un'applicazione in esecuzione come distribuzione in Kubernetes. Il traffico degli utenti arriva ai suoi pod (ad esempio, ce ne sono tre) e in essi misuriamo un determinato indicatore (ad esempio, il carico della CPU). Quando il carico aumenta, lo registriamo secondo un programma e aumentiamo il numero di pod per distribuire le richieste.

Oggi in Kubernetes questo non deve essere fatto manualmente: viene configurato un aumento/diminuzione automatico del numero di pod a seconda dei valori degli indicatori di carico misurati.

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

Le domande principali qui sono: cosa misurare esattamente и come interpretare valori ottenuti (per prendere una decisione sulla modifica del numero di pod). Puoi misurare molto:

Autoscaling e gestione delle risorse in Kubernetes (revisione e report video)

Come farlo tecnicamente: raccogliere metriche, ecc. — Ne ho parlato in dettaglio nel rapporto Monitoraggio e Kubernetes. E il consiglio principale per scegliere i parametri ottimali è sperimentare!

C'è Metodo USO (Saturazione ed errori di utilizzo), il cui significato è il seguente. Su quali basi ha senso scalare, ad esempio, php-fpm? In base al fatto che i lavoratori stanno finendo, questo è utilizzo. E se i lavoratori sono finiti e non si accettano nuovi collegamenti, questo è già saturazione. Entrambi questi parametri devono essere misurati e, a seconda dei valori, deve essere effettuata la messa in scala.

Invece di una conclusione

Il rapporto ha un seguito: sul ridimensionamento verticale e su come selezionare le giuste risorse. Ne parlerò nei prossimi video su il nostro YouTube - iscriviti per non perderti nulla!

Video e diapositive

Video dallo spettacolo (44 minuti):

Presentazione del rapporto:

PS

Altri resoconti su Kubernetes sul nostro blog:

Fonte: habr.com

Aggiungi un commento