ProHoster > Blog > Amministrazione > Kubernetes: perchè hè cusì impurtante di stallà a gestione di e risorse di u sistema?
Kubernetes: perchè hè cusì impurtante di stallà a gestione di e risorse di u sistema?
In regula, ci hè sempre bisognu di furnisce una riserva di risorse dedicata à una applicazione per u so funziunamentu currettu è stabile. Ma chì succede s'ellu parechje applicazioni funzionanu nantu à a stessa putenza? Cumu furnisce ognuna di elli cù e risorse minimu necessariu? Cumu pudete limità u cunsumu di risorse? Cumu distribuisce currettamente a carica trà i nodi? Cumu assicurà chì u mecanismu di scala horizontale funziona se a carica di l'applicazione aumenta?
Avete bisognu di principià cù quale tippi principali di risorse esistenu in u sistema - questu, sicuru, hè u tempu di processore è RAM. In i manifesti k8s sti tipi di risorse sò misurati in e seguenti unità:
CPU - in core
RAM - in bytes
Inoltre, per ogni risorsa hè pussibule stabilisce dui tipi di esigenze - dumande и limiti. Richieste - descrive i requisiti minimi per i risorsi gratuiti di un node per eseguisce un containeru (è pod in tuttu), mentre chì i limiti stabiliscenu un limitu duru nantu à e risorse dispunibuli per u containeru.
Hè impurtante di capisce chì u manifestu ùn deve esse definitu esplicitamente i dui tipi, ma u cumpurtamentu serà cusì:
Se solu i limiti di una risorsa sò esplicitamente specificati, allora e dumande per questa risorsa piglianu automaticamente un valore uguale à i limiti (pudete verificà questu chjamendu entità descritte). Quelli. in fattu, u cuntinuu serà limitatu à a listessa quantità di risorse chì hà bisognu à curriri.
Se solu e dumande sò esplicitamente specificate per una risorsa, allora ùn ci sò micca restrizioni superiori nantu à sta risorsa - i.e. u cuntinuu hè limitatu solu da e risorse di u node stessu.
Hè ancu pussibule di cunfigurà a gestione di risorse micca solu à u livellu di un containeru specificu, ma ancu à u livellu di u namespace usendu e seguenti entità:
Limit Range - descrive a pulitica di restrizzione à u livellu di cuntainer / pod in ns è hè necessariu per descriverà i limiti predeterminati nantu à u container / pod, è ancu impedisce a creazione di cuntenituri / pods ovviamente grassi (o vice versa), limità u so numeru è determinà a pussibuli differenza di i valori in limiti è richieste
Quote di risorse - descrive a pulitica di restrizzione in generale per tutti i cuntenituri in ns è hè aduprata, in regula, per delimità e risorse trà l'ambienti (utile quandu l'ambienti ùn sò micca strettamente delimitati à u livellu di u nodu)
I seguenti sò esempi di manifesti chì stabiliscenu limiti di risorse:
Quelli. in questu casu, per eseguisce un cuntinuu cù nginx, avete bisognu di almenu 1G di RAM libera è 0.2 CPU nantu à u node, mentri à u più u cuntinuu pò cunsumà 0.2 CPU è tutta a RAM dispunibule nantu à u node.
Quelli. a summa di tutti i cuntenituri di dumanda in u ns predeterminatu ùn pò esse più di 300m per u CPU è 1G per l'OP, è a summa di tutti i limiti hè 700m per u CPU è 2G per l'OP.
Quelli. in u namespace predeterminatu per tutti i cuntenituri, a dumanda serà stabilita à 100m per CPU è 1G per OP, limite - 1 CPU è 2G. À u listessu tempu, un limitu hè ancu stabilitu nantu à i valori pussibuli in dumanda / limite per CPU (50m < x < 2) è RAM (500M < x < 4G).
Quelli. per ogni pod in u ns predeterminatu ci sarà un limitu di 4 vCPU è 1G.
Avà vogliu dì à voi chì vantaghji ponu dà sti restrizioni.
Meccanisimu di equilibriu di carica trà i nodi
Comu sapete, u cumpunente k8s hè rispunsevule per a distribuzione di pods trà i nodi, cum'è pianificatore, chì travaglia secondu un algoritmu specificu. Questu algoritmu passa per duie tappe quandu selezziunate u node ottimale per lancià:
Filtrazione
A varieghja
Quelli. secondu a pulitica descritta, i nodi sò inizialmente selezziunati nantu à quale hè pussibule lancià un pod basatu nantu à un set predicati (cumprese a verificazione se u node hà abbastanza risorse per eseguisce u pod - PodFitsResources), è dopu per ognunu di sti nodi, secondu priurità i punti sò attribuiti (cumpresu, più risorse gratuiti un node hà, più punti hè attribuitu - LeastResourceAllocation/LeastRequestedPriority/BalancedResourceAllocation) è u pod hè lanciatu nantu à u node cù u più punti (se parechji nodi satisfacenu sta cundizione à una volta, allora hè sceltu un aleatoriu).
À u listessu tempu, avete bisognu di capiscenu chì u pianificatore, quandu valutà e risorse dispunibili di un node, hè guidatu da e dati chì sò guardati in etcd - i.e. per a quantità di a risorsa dumandata / limite di ogni pod in esecuzione nantu à questu node, ma micca per u cunsumu di risorse attuale. Sta infurmazione pò esse ottenuta da l'output di cumandamentu kubectl describe node $NODE, per esempiu:
Quì vedemu tutti i podi chì currenu nantu à un node specificu, è ancu e risorse chì ogni poda dumanda. È eccu ciò chì pareanu i logs di pianificazione quandu u pod cronjob-cron-events-1573793820-xt6q9 hè lanciatu (questa infurmazione appariscerà in u logu di pianificazione quandu stabilisce u 10u livellu di logging in l'argumenti di cumanda di startup -v = 10):
log
I1115 07:57:21.637791 1 scheduling_queue.go:908] About to try and schedule pod nxs-stage/cronjob-cron-events-1573793820-xt6q9
I1115 07:57:21.637804 1 scheduler.go:453] Attempting to schedule pod: nxs-stage/cronjob-cron-events-1573793820-xt6q9
I1115 07:57:21.638285 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s5 is allowed, Node is running only 16 out of 110 Pods.
I1115 07:57:21.638300 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s6 is allowed, Node is running only 20 out of 110 Pods.
I1115 07:57:21.638322 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s3 is allowed, Node is running only 20 out of 110 Pods.
I1115 07:57:21.638322 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s4 is allowed, Node is running only 17 out of 110 Pods.
I1115 07:57:21.638334 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s10 is allowed, Node is running only 16 out of 110 Pods.
I1115 07:57:21.638365 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s12 is allowed, Node is running only 9 out of 110 Pods.
I1115 07:57:21.638334 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s11 is allowed, Node is running only 11 out of 110 Pods.
I1115 07:57:21.638385 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s1 is allowed, Node is running only 19 out of 110 Pods.
I1115 07:57:21.638402 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s2 is allowed, Node is running only 21 out of 110 Pods.
I1115 07:57:21.638383 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s9 is allowed, Node is running only 16 out of 110 Pods.
I1115 07:57:21.638335 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s8 is allowed, Node is running only 18 out of 110 Pods.
I1115 07:57:21.638408 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s13 is allowed, Node is running only 8 out of 110 Pods.
I1115 07:57:21.638478 1 predicates.go:1369] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s10 is allowed, existing pods anti-affinity terms satisfied.
I1115 07:57:21.638505 1 predicates.go:1369] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s8 is allowed, existing pods anti-affinity terms satisfied.
I1115 07:57:21.638577 1 predicates.go:1369] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s9 is allowed, existing pods anti-affinity terms satisfied.
I1115 07:57:21.638583 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s7 is allowed, Node is running only 25 out of 110 Pods.
I1115 07:57:21.638932 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: BalancedResourceAllocation, capacity 39900 millicores 66620178432 memory bytes, total request 2343 millicores 9640186880 memory bytes, score 9
I1115 07:57:21.638946 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: LeastResourceAllocation, capacity 39900 millicores 66620178432 memory bytes, total request 2343 millicores 9640186880 memory bytes, score 8
I1115 07:57:21.638961 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: BalancedResourceAllocation, capacity 39900 millicores 66620170240 memory bytes, total request 4107 millicores 11307422720 memory bytes, score 9
I1115 07:57:21.638971 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: BalancedResourceAllocation, capacity 39900 millicores 66620178432 memory bytes, total request 5847 millicores 24333637120 memory bytes, score 7
I1115 07:57:21.638975 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: LeastResourceAllocation, capacity 39900 millicores 66620170240 memory bytes, total request 4107 millicores 11307422720 memory bytes, score 8
I1115 07:57:21.638990 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: LeastResourceAllocation, capacity 39900 millicores 66620178432 memory bytes, total request 5847 millicores 24333637120 memory bytes, score 7
I1115 07:57:21.639022 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10: TaintTolerationPriority, Score: (10)
I1115 07:57:21.639030 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8: TaintTolerationPriority, Score: (10)
I1115 07:57:21.639034 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9: TaintTolerationPriority, Score: (10)
I1115 07:57:21.639041 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10: NodeAffinityPriority, Score: (0)
I1115 07:57:21.639053 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8: NodeAffinityPriority, Score: (0)
I1115 07:57:21.639059 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9: NodeAffinityPriority, Score: (0)
I1115 07:57:21.639061 1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: InterPodAffinityPriority, Score: (0)
I1115 07:57:21.639063 1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: SelectorSpreadPriority, Score: (10)
I1115 07:57:21.639073 1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: InterPodAffinityPriority, Score: (0)
I1115 07:57:21.639077 1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: SelectorSpreadPriority, Score: (10)
I1115 07:57:21.639085 1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: InterPodAffinityPriority, Score: (0)
I1115 07:57:21.639088 1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: SelectorSpreadPriority, Score: (10)
I1115 07:57:21.639103 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10: SelectorSpreadPriority, Score: (10)
I1115 07:57:21.639109 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8: SelectorSpreadPriority, Score: (10)
I1115 07:57:21.639114 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9: SelectorSpreadPriority, Score: (10)
I1115 07:57:21.639127 1 generic_scheduler.go:781] Host nxs-k8s-s10 => Score 100037
I1115 07:57:21.639150 1 generic_scheduler.go:781] Host nxs-k8s-s8 => Score 100034
I1115 07:57:21.639154 1 generic_scheduler.go:781] Host nxs-k8s-s9 => Score 100037
I1115 07:57:21.639267 1 scheduler_binder.go:269] AssumePodVolumes for pod "nxs-stage/cronjob-cron-events-1573793820-xt6q9", node "nxs-k8s-s10"
I1115 07:57:21.639286 1 scheduler_binder.go:279] AssumePodVolumes for pod "nxs-stage/cronjob-cron-events-1573793820-xt6q9", node "nxs-k8s-s10": all PVCs bound and nothing to do
I1115 07:57:21.639333 1 factory.go:733] Attempting to bind cronjob-cron-events-1573793820-xt6q9 to nxs-k8s-s10
Quì vedemu chì inizialmente u pianificatore filtra è genera una lista di nodi 3 nantu à quale pò esse lanciatu (nxs-k8s-s8, nxs-k8s-s9, nxs-k8s-s10). Allora calcula i punteggi in basa di parechji paràmetri (inclusi BalancedResourceAllocation, LeastResourceAllocation) per ognunu di sti nodi per determinà u node più adattatu. In ultimamente, u pod hè pianificatu nantu à u node cù u più altu numaru di punti (qui dui nodi à una volta anu u listessu numeru di punti 100037, cusì un aleatoriu hè sceltu - nxs-k8s-s10).
cunchiusioni: se un node esegue pods per i quali ùn sò micca stabilite restrizioni, allora per k8s (da u puntu di vista di u cunsumu di risorse) questu serà equivalente à cum'è s'ellu ùn ci era micca tali pods nantu à stu node. Dunque, se avete, cundizionalmente, avete un pod cun un prucessu gluttonosu (per esempiu, wowza) è ùn ci sò micca restrizioni per questu, allora una situazione pò esse quandu questu pod in realtà manghja tutte e risorse di u node, ma per k8s stu node. hè cunsideratu scaricatu è serà attribuitu u listessu nùmeru di punti quandu u ranking (precisamente in punti chì valutanu e risorse dispunibili) cum'è un node chì ùn hà micca podi di travagliu, chì in ultimamente pò purtà à una distribuzione irregulare di a carica trà i nodi.
L'evacuazione di Pod
Comu sapete, ogni pod hè assignatu una di e 3 classi QoS:
guarantitu - hè attribuitu quandu per ogni cuntainer in u pod una dumanda è un limitu sò specificati per a memoria è u CPU, è questi valori devenu cuncordà
burstable - almenu un containeru in u podu hà una dumanda è un limitu, cù a dumanda < limitu
u megliu sforzu - quandu ùn un solu cuntainer in u pod hè risorsa limitata
À u stessu tempu, quandu un node sperimenta una mancanza di risorse (discu, memoria), kubelet cumencia à classificà è evict pods secondu un algoritmu specificu chì piglia in contu a priorità di u pod è a so classa QoS. Per esempiu, se parlemu di RAM, allora basatu nantu à a classe QoS, i punti sò attribuiti secondu u principiu seguente:
Quelli. cù a listessa priorità, u kubelet prima evict pods cù u megliu sforzu QoS class from the node.
cunchiusioni: se vulete riduce a probabilità chì u podu desideratu sia scacciatu da u node in casu di una mancanza di risorse nantu à questu, allora cù a priorità, avete ancu bisognu di cura di stabilisce a dumanda / limitu per questu.
Meccanismu per l'autoscaling horizontale di i pod d'applicazione (HPA)
Quandu u compitu hè di aumentà automaticamente è diminuite u numeru di pods secondu l'usu di risorse (sistema - CPU / RAM o utilizatore - rps), cum'è una entità k8s cum'è HPA (Autoscaler Pod Horizontal). L'algoritmu di quale hè u seguente:
E letture attuali di a risorsa osservata sò determinate (currentMetricValue)
I valori desiderati per a risorsa sò determinati (desiredMetricValue), chì per e risorse di u sistema sò stabiliti cù a dumanda
U numeru attuale di repliche hè determinatu (currentReplicas)
A formula seguente calcula u numeru desideratu di repliche (repliche desiderate)
desiderateReplicas = [ currentReplicas * ( currentMetricValue / wantMetricValue )]
In questu casu, a scala ùn accade micca quandu u coefficient (currentMetricValue / wantMetricValue) hè vicinu à 1 (in questu casu, pudemu stabilisce l'errore permissibile noi stessi; per automaticamente hè 0.1).
Fighjemu cumu funziona hpa usendu l'esempiu di l'applicazione app-test (descritta cum'è Deployment), induve hè necessariu cambià u numeru di repliche secondu u cunsumu di CPU:
Quelli. vedemu chì u pod di l'applicazione hè inizialmente lanciatu in dui casi, ognuna di e quali cuntene dui cuntenituri nginx è nginx-exporter, per ognuna di quale un specificatu dumande per CPU.
Quelli. Avemu creatu un hpa chì monitorerà l'app-test di implementazione è aghjustà u nùmeru di pods cù l'applicazione basatu annantu à l'indicatore di CPU (aspittemu chì u pod duveria cunsumà u 30% di a CPU chì dumanda), cù u numeru di rèpliche chì sò in. a gamma di 2-10.
Avà, fighjemu u mecanismu di l'operazione hpa se applichemu una carica à unu di i fochi:
# kubectl top pod
NAME CPU(cores) MEMORY(bytes)
app-test-78559f8f44-pgs58 101m 243Mi
app-test-78559f8f44-cj4jz 4m 240Mi
In totale avemu i seguenti:
U valore desideratu (desiredMetricValue) - secondu i paràmetri hpa, avemu 30%
Valore attuale (currentMetricValue) - per u calculu, u controller-manager calcula u valore mediu di u cunsumu di risorse in %, i.e. cundizionalmente face i seguenti:
Riceve valori assoluti di metrica pod da u servitore metricu, i.e. 101 m è 4 m
Calcula u valore assolutu mediu, i.e. (101m + 4m) / 2 = 53m
Ottene u valore assolutu per u cunsumu di risorse desiderate (per questu, e dumande di tutti i cuntenituri sò riassunte) 60m + 30m = 90m
Calcula u percentuale mediu di u cunsumu CPU relative à u pod di dumanda, i.e. 53 m / 90 m * 100% = 59%
Avà avemu tuttu ciò chì avemu bisognu di determinà s'ellu ci vole à cambià u numeru di repliche; per fà questu, calculemu u coefficient:
ratio = 59% / 30% = 1.96
Quelli. u numeru di repliche deve esse aumentatu da ~ 2 volte è quantità à [2 * 1.96] = 4.
Cunsigliu: Comu pudete vede, per u funziunamentu di stu mecanismu, una cundizione necessaria hè a presenza di richieste per tutti i cuntenituri in u pod osservatu.
Meccanismu per l'autoscaling horizontale di i nodi (Cluster Autoscaler)
Per neutralizà l'impattu negativu nantu à u sistema durante i surge di carica, avè un hpa cunfiguratu ùn hè micca abbastanza. Per esempiu, sicondu i paràmetri in u gestore di u controller hpa, decide chì u numeru di rèpliche deve esse aumentatu da 2 volte, ma i nodi ùn anu micca risorse gratuiti per eseguisce un tali numeru di pods (vale à dì u node ùn pò micca furnisce risorse richieste à u pod di richieste) è questi pods passanu à u statu Pending.
In questu casu, se u fornitore hà un IaaS / PaaS currispundente (per esempiu, GKE / GCE, AKS, EKS, etc.), un strumentu cum'è Node Autoscaler. Permette di stabilisce u numeru massimu è minimu di nodi in u cluster è aghjustà automaticamente u numeru attuale di nodi (chjamendu l'API di u fornitore di nuvola per urdinà / caccià un node) quandu ci hè una mancanza di risorse in u cluster è i pods. ùn pò micca esse pianificatu (sò in u statu Pending).
Cunsigliu: Per esse capace di autoscala i nodi, hè necessariu stabilisce e dumande in i contenitori di pod in modu chì k8s ponu valutà currettamente a carica nantu à i nodi è per quessa rapportu chì ùn ci sò risorse in u cluster per lancià u prossimu pod.
cunchiusioni
Si deve esse nutatu chì stabilisce limiti di risorse di u containeru ùn hè micca un requisitu per l'applicazione per eseguisce cù successu, ma hè sempre megliu per fà per i seguenti motivi:
Per un funziunamentu più precisu di u pianificatore in quantu à l'equilibriu di carica trà i nodi k8s
Per riduce a probabilità di un avvenimentu di "eviction pod".
Per l'autoscaling horizontale di l'applicazione pods (HPA) per travaglià
Per l'autoscaling horizontale di i nodi (Cluster Autoscaling) per i fornitori di nuvola
Leghjite ancu altri articuli nantu à u nostru blog: