ProHoster > Blog > administratë > Kubernetes: pse është kaq e rëndësishme të vendosni menaxhimin e burimeve të sistemit?
Kubernetes: pse është kaq e rëndësishme të vendosni menaxhimin e burimeve të sistemit?
Si rregull, ekziston gjithmonë nevoja për të siguruar një grup të dedikuar burimesh për një aplikacion për funksionimin e tij korrekt dhe të qëndrueshëm. Por, çka nëse disa aplikacione funksionojnë me të njëjtën fuqi? Si t'i siguroni secilit prej tyre burimet minimale të nevojshme? Si mund ta kufizoni konsumin e burimeve? Si të shpërndani saktë ngarkesën midis nyjeve? Si të siguroheni që mekanizmi i shkallëzimit horizontal funksionon nëse rritet ngarkesa e aplikimit?
Ju duhet të filloni me llojet kryesore të burimeve që ekzistojnë në sistem - kjo, natyrisht, është koha e procesorit dhe RAM. Në manifestimet k8s, këto lloje burimesh maten në njësitë e mëposhtme:
CPU - në bërthama
RAM - në bajt
Për më tepër, për çdo burim është e mundur të vendosen dy lloje kërkesash - Kërkesat и Afatet. Kërkesat - përshkruan kërkesat minimale për burimet e lira të një nyje për të drejtuar një kontejner (dhe pod në tërësi), ndërsa limitet vendosin një kufi të fortë për burimet në dispozicion të kontejnerit.
Është e rëndësishme të kuptohet se manifesti nuk duhet të përcaktojë në mënyrë eksplicite të dy llojet, por sjellja do të jetë si më poshtë:
Nëse vetëm kufijtë e një burimi janë specifikuar në mënyrë eksplicite, atëherë kërkesat për këtë burim marrin automatikisht një vlerë të barabartë me kufijtë (mund ta verifikoni këtë duke thirrur entitetet e përshkruara). Ato. në fakt, kontejneri do të kufizohet në të njëjtën sasi burimesh që kërkon për të funksionuar.
Nëse vetëm kërkesat janë të specifikuara në mënyrë eksplicite për një burim, atëherë nuk vendosen kufizime të sipërme për këtë burim - d.m.th. kontejneri kufizohet vetëm nga burimet e vetë nyjës.
Është gjithashtu e mundur të konfiguroni menaxhimin e burimeve jo vetëm në nivelin e një kontejneri specifik, por edhe në nivelin e hapësirës së emrave duke përdorur entitetet e mëposhtme:
Gama e Kufirit — përshkruan politikën e kufizimit në nivelin e kontejnerëve/podeve në ns dhe është e nevojshme për të përshkruar kufijtë e paracaktuar në kontejner/pod, si dhe për të parandaluar krijimin e kontejnerëve/podeve dukshëm me yndyrë (ose anasjelltas), për të kufizuar numrin e tyre dhe përcaktoni ndryshimin e mundshëm në vlerat në kufij dhe kërkesa
Kuotat e burimeve — përshkruani politikën e kufizimit në përgjithësi për të gjithë kontejnerët në ns dhe përdoret, si rregull, për të kufizuar burimet midis mjediseve (e dobishme kur mjediset nuk janë të përcaktuara rreptësisht në nivelin e nyjeve)
Më poshtë janë shembuj të manifestimeve që vendosin kufijtë e burimeve:
Ato. në këtë rast, për të drejtuar një kontejner me nginx, do t'ju duhet të paktën 1G RAM falas dhe 0.2 CPU në nyje, ndërsa më së shumti kontejneri mund të konsumojë 0.2 CPU dhe të gjithë RAM-in e disponueshëm në nyje.
Ato. shuma e të gjithë kontejnerëve të kërkesave në ns të paracaktuar nuk mund të kalojë 300 m për CPU dhe 1G për OP, dhe shuma e të gjithë kufirit është 700 m për CPU dhe 2G për OP.
Ato. në hapësirën e emrave të paracaktuar për të gjithë kontejnerët, kërkesa do të vendoset në 100 m për CPU dhe 1G për OP, kufiri - 1 CPU dhe 2G. Në të njëjtën kohë, vendoset një kufi edhe në vlerat e mundshme në kërkesë/kufi për CPU (50m < x < 2) dhe RAM (500M < x < 4G).
Ato. për çdo pod në ns të paracaktuar do të ketë një kufi prej 4 vCPU dhe 1G.
Tani do të doja t'ju tregoja se çfarë avantazhesh mund të na japë vendosja e këtyre kufizimeve.
Mekanizmi i balancimit të ngarkesës midis nyjeve
Siç e dini, komponenti k8s është përgjegjës për shpërndarjen e pods midis nyjeve, si p.sh scheduler, i cili funksionon sipas një algoritmi specifik. Ky algoritëm kalon në dy faza kur zgjedh nyjen optimale për të nisur:
filtrim
Rangimi
Ato. sipas politikës së përshkruar, fillimisht zgjidhen nyjet mbi të cilat është e mundur të lëshohet një pod bazuar në një grup kallëzues (duke përfshirë kontrollin nëse nyja ka burime të mjaftueshme për të ekzekutuar pod - PodFitsResources), dhe më pas për secilën prej këtyre nyjeve, sipas prioritetet jepen pikë (përfshirë, sa më shumë burime të lira të ketë një nyje, aq më shumë pikë i caktohen - LeastResourceAllocation/LeastRequestedPriority/BalancedResourceAllocation) dhe pod hapet në nyjen me më shumë pikë (nëse disa nyje e plotësojnë këtë kusht në të njëjtën kohë, atëherë zgjidhet një rastësisht).
Në të njëjtën kohë, duhet të kuptoni se planifikuesi, kur vlerëson burimet e disponueshme të një nyje, udhëhiqet nga të dhënat që ruhen në etcd - d.m.th. për sasinë e burimit të kërkuar/kufizues të çdo pod që funksionon në këtë nyje, por jo për konsumin aktual të burimit. Ky informacion mund të merret nga dalja e komandës kubectl describe node $NODE, për shembull:
Këtu shohim të gjitha podet që funksionojnë në një nyje specifike, si dhe burimet që kërkon çdo pod. Dhe ja se si duken regjistrat e programuesit kur hapet pod cronjob-cron-events-1573793820-xt6q9 (ky informacion do të shfaqet në regjistrin e planifikuesit kur të vendosni nivelin e 10-të të regjistrimit në argumentet e komandës së nisjes -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
Këtu shohim që fillimisht planifikuesi filtron dhe gjeneron një listë me 3 nyje në të cilat mund të lëshohet (nxs-k8s-s8, nxs-k8s-s9, nxs-k8s-s10). Më pas ai llogarit rezultatet bazuar në disa parametra (përfshirë BalancedResourceAllocation, LeastResourceAllocation) për secilën prej këtyre nyjeve në mënyrë që të përcaktojë nyjen më të përshtatshme. Në fund të fundit, pod është planifikuar në nyjen me numrin më të madh të pikëve (këtu dy nyje njëherësh kanë të njëjtin numër pikash 100037, kështu që zgjidhet një e rastësishme - nxs-k8s-s10).
Prodhim: nëse një nyje ekzekuton pods për të cilat nuk janë vendosur kufizime, atëherë për k8s (nga pikëpamja e konsumit të burimeve) kjo do të jetë ekuivalente sikur të mos kishte fare pods të tillë në këtë nyje. Prandaj, nëse, me kusht, keni një pod me një proces grykës (për shembull, wowza) dhe nuk janë vendosur kufizime për të, atëherë mund të lindë një situatë kur ky pod në të vërtetë hëngri të gjitha burimet e nyjës, por për k8s kjo nyje konsiderohet e shkarkuar dhe do t'i jepet i njëjti numër pikësh kur renditet (pikërisht në pikët që vlerësojnë burimet e disponueshme) si një nyje që nuk ka nyje pune, gjë që në fund mund të çojë në shpërndarje të pabarabartë të ngarkesës midis nyjeve.
Dëbimi i Podit
Siç e dini, çdo pod i është caktuar një nga 3 klasat QoS:
e garantuar — caktohet kur për çdo kontejner në pod specifikohet një kërkesë dhe kufi për memorien dhe CPU, dhe këto vlera duhet të përputhen
i shpërthyeshëm — të paktën një kontejner në pod ka një kërkesë dhe një kufi, me kërkesë < limit
perpjekja me e mire — kur asnjë enë e vetme në pod nuk ka burime të kufizuara
Në të njëjtën kohë, kur një nyje përjeton mungesë burimesh (disk, memorie), kubelet fillon të rendit dhe të nxjerrë podet sipas një algoritmi specifik që merr parasysh përparësinë e pod dhe klasës së tij QoS. Për shembull, nëse po flasim për RAM, atëherë bazuar në klasën QoS, pikët jepen sipas parimit të mëposhtëm:
Garantuar: -998
Përpjekja më e mirë: 1000
I plasur: min (maksimumi (2, 1000 - (1000 * memorieRequestBytes) / makineMemoryCapacityBytes), 999)
Ato. me të njëjtin prioritet, kubelet fillimisht do të nxjerrë podet me klasën më të mirë QoS nga nyja.
Prodhim: nëse doni të zvogëloni gjasat që podi i dëshiruar të dëbohet nga nyja në rast të mungesës së burimeve në të, atëherë së bashku me përparësinë, duhet të kujdeseni edhe për vendosjen e kërkesës/kufizimit për të.
Mekanizmi për shkallëzimin automatik horizontal të podave të aplikacionit (HPA)
Kur detyra është të rritet dhe të zvogëlohet automatikisht numri i pod-ve në varësi të përdorimit të burimeve (sistemi - CPU/RAM ose përdorues - rps), një entitet i tillë k8s si HPA (Horizontal Pod Autoscaler). Algoritmi i të cilit është si më poshtë:
Përcaktohen leximet aktuale të burimit të vëzhguar (Vlera Metrike aktuale)
Përcaktohen vlerat e dëshiruara për burimin (dëshiruarMetricValue), të cilat për burimet e sistemit vendosen duke përdorur kërkesën
Përcaktohet numri aktual i kopjeve (replikat aktuale)
Formula e mëposhtme llogarit numrin e dëshiruar të kopjeve (Replikat e dëshiruara)
Replikat e dëshiruara = [Replikat aktuale * (Vlera Metrike aktuale / Vlera Metrike e dëshiruar)]
Në këtë rast, shkallëzimi nuk do të ndodhë kur koeficienti (currentMetricValue / dëshiruarMetricValue) është afër 1 (në këtë rast, ne mund ta vendosim vetë gabimin e lejuar; si parazgjedhje është 0.1).
Le të shohim se si funksionon hpa duke përdorur shembullin e aplikacionit të testit të aplikacionit (të përshkruar si Deployment), ku është e nevojshme të ndryshohet numri i kopjeve në varësi të konsumit të CPU:
Ato. ne shohim që pod aplikacioni fillimisht lëshohet në dy raste, secila prej të cilave përmban dy kontejnerë nginx dhe nginx-eksportues, për secilën prej të cilave një specifikim Kërkesat për CPU.
Ato. Ne krijuam një hpa që do të monitorojë testin e aplikacionit të vendosjes dhe do të rregullojë numrin e podeve me aplikacionin bazuar në treguesin e CPU (presim që pod duhet të konsumojë 30% të CPU-së që kërkon), me numrin e kopjeve në diapazoni 2-10.
Tani, le të shohim mekanizmin e funksionimit të hpa nëse aplikojmë një ngarkesë në një nga vatrat:
# kubectl top pod
NAME CPU(cores) MEMORY(bytes)
app-test-78559f8f44-pgs58 101m 243Mi
app-test-78559f8f44-cj4jz 4m 240Mi
Në total kemi këto:
Vlera e dëshiruar (dëshiruarMetricValue) - sipas cilësimeve të hpa, kemi 30%
Vlera aktuale (currentMetricValue) - për llogaritjen, kontrolluesi-menaxher llogarit vlerën mesatare të konsumit të burimeve në %, d.m.th. me kusht bën sa më poshtë:
Merr vlera absolute të metrikës së pod nga serveri metrikë, d.m.th. 101m dhe 4m
Merr vlerën absolute për konsumin e dëshiruar të burimit (për këtë, kërkesat e të gjithë kontejnerëve janë përmbledhur) 60m + 30m = 90m
Llogarit përqindjen mesatare të konsumit të CPU-së në raport me podin e kërkesës, d.m.th. 53 m / 90 m * 100% = 59%
Tani kemi gjithçka që na nevojitet për të përcaktuar nëse duhet të ndryshojmë numrin e kopjeve; për ta bërë këtë, ne llogarisim koeficientin:
ratio = 59% / 30% = 1.96
Ato. numri i kopjeve duhet të rritet me ~ 2 herë dhe të arrijë në [2 * 1.96] = 4.
Përfundim: Siç mund ta shihni, në mënyrë që ky mekanizëm të funksionojë, një kusht i domosdoshëm është prania e kërkesave për të gjithë kontejnerët në podin e vëzhguar.
Mekanizmi për shkallëzimin automatik horizontal të nyjeve (Cluster Autoscaler)
Për të neutralizuar ndikimin negativ në sistem gjatë rritjeve të ngarkesës, nuk mjafton të kesh një hpa të konfiguruar. Për shembull, sipas cilësimeve në menaxherin e kontrolluesit hpa, ai vendos që numri i kopjeve duhet të rritet me 2 herë, por nyjet nuk kanë burime falas për të ekzekutuar një numër të tillë pods (d.m.th. nyja nuk mund të sigurojë burimet e kërkuara në podin e kërkesave) dhe këto pods kalojnë në gjendjen në pritje.
Në këtë rast, nëse ofruesi ka një IaaS/PaaS përkatës (për shembull, GKE/GCE, AKS, EKS, etj.), Një mjet si Shkallëzuesi automatik i nyjeve. Kjo ju lejon të vendosni numrin maksimal dhe minimal të nyjeve në grup dhe të rregulloni automatikisht numrin aktual të nyjeve (duke thirrur API-në e ofruesit të resë kompjuterike për të porositur/hequr një nyje) kur ka mungesë burimesh në grup dhe në pods nuk mund të planifikohet (janë në gjendje në pritje).
Përfundim: Për të qenë në gjendje të shkallëzoni automatikisht nyjet, është e nevojshme të vendosni kërkesa në kontejnerët e pod, në mënyrë që k8-të të mund të vlerësojnë saktë ngarkesën në nyje dhe në përputhje me rrethanat të raportojnë se nuk ka burime në grup për të nisur podin e ardhshëm.
Përfundim
Duhet të theksohet se vendosja e kufijve të burimeve të kontejnerit nuk është një kërkesë që aplikacioni të funksionojë me sukses, por është akoma më mirë ta bëni këtë për arsyet e mëposhtme:
Për funksionim më të saktë të planifikuesit në drejtim të balancimit të ngarkesës midis nyjeve k8s
Për të reduktuar gjasat e ndodhjes së një ngjarjeje të "dëbimit të pod".
Që të funksionojë shkallëzimi automatik horizontal i podave të aplikacionit (HPA).
Për shkallëzimin automatik horizontal të nyjeve (Cluster Autoscaling) për ofruesit e cloud
Lexoni gjithashtu artikuj të tjerë në blogun tonë: