ProHoster > Blog > Bestjoer > Kubernetes: wêrom is it sa wichtich om systeemboarnebehear te konfigurearjen?
Kubernetes: wêrom is it sa wichtich om systeemboarnebehear te konfigurearjen?
As regel is d'r altyd ferlet om in tawijd pool fan boarnen te leverjen oan in applikaasje foar har juste en stabile wurking. Mar wat as ferskate applikaasjes op deselde krêft rinne? Hoe elk fan harren te foarsjen mei de minimale nedige middels? Hoe kinne jo boarneferbrûk beheine? Hoe korrekt fersprieden de lading tusken knopen? Hoe kinne jo derfoar soargje dat it horizontaal skaalmeganisme wurket as de tapassingsbelesting ferheget?
Jo moatte begjinne mei hokker haadtypen fan boarnen besteane yn it systeem - dit is fansels prosessortiid en RAM. Yn k8s manifestearret dizze boarne typen wurde metten yn de folgjende ienheden:
CPU - yn kearnen
RAM - yn bytes
Boppedat is it foar elke boarne mooglik om twa soarten easken yn te stellen - fersiken и limiten. Fersiken - beskriuwt de minimale easken foar frije boarnen fan in knooppunt om in kontener (en pod as gehiel) út te fieren, wylst grinzen in hurde limyt ynstelle op 'e boarnen dy't beskikber binne foar de kontener.
It is wichtich om te begripen dat it manifest net beide soarten eksplisyt hoecht te definiearjen, mar it gedrach sil as folgjend wêze:
As allinnich de grinzen fan in boarne eksplisyt oantsjutte, dan fersiken foar dizze boarne automatysk nimme in wearde lyk oan grinzen (jo kinne ferifiearje dit troch in oprop beskriuwe entiteiten). Dy. yn feite, de kontener wurdt beheind ta itselde bedrach fan middels it fereasket om te rinnen.
As allinich fersiken eksplisyt oantsjutte binne foar in boarne, dan wurde gjin boppeste beheiningen ynsteld op dizze boarne - d.w.s. de kontener wurdt allinich beheind troch de middels fan it knooppunt sels.
It is ek mooglik om boarnebehear te konfigurearjen net allinich op it nivo fan in spesifike kontener, mar ek op it nammeromtenivo mei de folgjende entiteiten:
LimitRange - beskriuwt it beheiningbelied op it kontener/podnivo yn ns en is nedich om de standertgrinzen op 'e kontener/pod te beskriuwen, en ek foar te kommen dat it oanmeitsjen fan fansels dikke konteners/pods (of oarsom), har oantal beheine en bepale it mooglike ferskil yn 'e wearden yn grinzen en oanfragen
ResourceQuotas - beskriuw it beheiningbelied yn 't algemien foar alle konteners yn ns en wurdt, yn' e regel, brûkt om boarnen ûnder omjouwings te beheinen (nuttich as omjouwings net strikt ôfstimd binne op it knooppuntnivo)
De folgjende binne foarbylden fan manifesten dy't boarnegrinzen ynstelle:
Dy. yn dit gefal, foar in run in kontener mei nginx, do silst nedich op syn minst 1G frije RAM en 0.2 CPU op it knooppunt, wylst op syn meast de kontener kin konsumearje 0.2 CPU en alle beskikbere RAM op it knooppunt.
Dy. de som fan alle fersyk containers yn de standert ns kin net mear as 300m foar de CPU en 1G foar de OP, en de som fan alle limyt is 700m foar de CPU en 2G foar de OP.
Dy. yn de standert nammeromte foar alle konteners, fersyk wurdt ynsteld op 100m foar CPU en 1G foar OP, limyt - 1 CPU en 2G. Tagelyk wurdt ek in limyt ynsteld foar de mooglike wearden yn fersyk/limyt foar CPU (50m < x <2) en RAM (500M < x <4G).
Dy. foar eltse pod yn de standert ns sil der in limyt fan 4 vCPU en 1G.
No wol ik jo fertelle hokker foardielen it ynstellen fan dizze beheiningen ús kin jaan.
Load balancing meganisme tusken knopen
Lykas jo witte, is de k8s-komponint ferantwurdlik foar de ferdieling fan pods ûnder knooppunten, lykas scheduler, dy't wurket neffens in spesifyk algoritme. Dit algoritme giet troch twa stadia by it selektearjen fan it optimale knooppunt om te starten:
filtering
Ranging
Dy. neffens it beskreaune belied wurde nodes yn earste ynstânsje selektearre wêrop it mooglik is om in pod te starten op basis fan in set predikaten (ynklusyf kontrolearjen oft it knooppunt genôch boarnen hat om de pod út te fieren - PodFitsResources), en dan foar elk fan dizze knooppunten, neffens prioriteiten punten wurde takend (ynklusyf hoe mear frije boarnen in knooppunt hat, hoe mear punten it wurdt tawiisd - LeastResourceAllocation/LeastRequestedPriority/BalancedResourceAllocation) en de pod wurdt lansearre op it knooppunt mei de measte punten (as ferskate knooppunten tagelyk oan dizze betingst foldwaan, dan in willekeurich ien is selektearre).
Tagelyk moatte jo begripe dat de planner, by it beoardieljen fan de beskikbere boarnen fan in knooppunt, wurdt begelaat troch de gegevens dy't opslein binne yn etcd - d.w.s. foar it bedrach fan 'e frege / limyt boarne fan elke pod dy't rint op dizze knooppunt, mar net foar de eigentlike boarne konsumpsje. Dizze ynformaasje kin krigen wurde fan 'e kommando-útfier kubectl describe node $NODEbygelyks:
Hjir sjogge wy alle pods dy't rinne op in spesifyk knooppunt, lykas de boarnen dy't elke pod freget. En hjir is hoe't de planner-logs derút sjogge as de cronjob-cron-events-1573793820-xt6q9-pod wurdt lansearre (dizze ynformaasje sil ferskine yn it planner-log as jo it 10e lognivo ynstelle yn 'e opstartkommando-arguminten -v=10):
lochboek
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
Hjir sjogge wy dat yn earste ynstânsje de planner filtert en genereart in list fan 3 knopen wêrop it kin wurde lansearre (nxs-k8s-s8, nxs-k8s-s9, nxs-k8s-s10). Dan berekkenet it skoares basearre op ferskate parameters (ynklusyf BalancedResourceAllocation, LeastResourceAllocation) foar elk fan dizze knopen om de meast geskikte node te bepalen. Uteinlik wurdt de pod pland op it knooppunt mei it heechste oantal punten (hjir hawwe twa knooppunten tagelyk itselde oantal punten 100037, dus in willekeurige wurdt selektearre - nxs-k8s-s10).
konklúzje: as in knooppunt pods rint dêr't gjin beheinings foar ynsteld binne, dan sil dit foar k8s (út it eachpunt fan boarneferbrûk) lykweardich wêze as oft d'r gjin sokke pods op dizze node wiene. Dêrom, as jo, betingst, hawwe in pod mei in gluttonous proses (bygelyks, wowza) en gjin beheinings wurde ynsteld foar it, dan kin in situaasje ûntstean as dizze pod eins iet alle boarnen fan de node, mar foar k8s dizze node wurdt beskôge as ûntladen en it sil wurde takend itselde oantal punten doe't ranglist (krekt yn punten beoardielje beskikbere middels) as in knooppunt dat hat gjin wurkjende pods, dy't úteinlik kin liede ta uneven ferdieling fan de lading tusken knopen.
Pod syn útsetting
Lykas jo witte, wurdt elke pod ien fan 3 QoS-klassen tawiisd:
garandearre - wurdt tawiisd as foar elke kontener yn 'e pod in fersyk en limyt wurde opjûn foar ûnthâld en cpu, en dizze wearden moatte oerienkomme
burstable - op syn minst ien kontener yn 'e pod hat in fersyk en in limyt, mei fersyk < limyt
bêste ynspanning - as net ien kontener yn 'e pod boarne beheind is
Tagelyk, as in knooppunt ûnderfynt in tekoart oan middels (skiif, ûnthâld), begjint kubelet te rank en evict pods neffens in spesifyk algoritme dat rekken hâldt mei de prioriteit fan de pod en syn QoS klasse. Bygelyks, as wy it oer RAM hawwe, dan wurde op basis fan 'e QoS-klasse punten takend neffens it folgjende prinsipe:
Dy. mei deselde prioriteit, de kubelet sil earst evict pods mei de bêste ynspannings QoS klasse út it knooppunt.
konklúzje: as jo de kâns wolle ferminderje dat de winske pod út 'e knooppunt wurdt ferdreaun yn gefal fan in tekoart oan middels derop, dan moatte jo tegearre mei de prioriteit ek soargje foar it ynstellen fan it fersyk/limyt dêrfoar.
Mechanisme foar horizontale autoskalearring fan applikaasjepods (HPA)
As de taak is om it oantal pods automatysk te fergrutsjen en te ferminderjen ôfhinklik fan it gebrûk fan boarnen (systeem - CPU / RAM of brûker - rps), sa'n k8s-entiteit as hPa (Horizontale Pod Autoscaler). It algoritme dêrfan is as folget:
De hjoeddeistige lêzingen fan 'e waarnommen boarne wurde bepaald (currentMetricValue)
De winske wearden foar de boarne wurde bepaald (desiredMetricValue), dy't foar systeemboarnen wurde ynsteld mei fersyk
It hjoeddeiske oantal replika's wurdt bepaald (currentReplicas)
De folgjende formule berekkent it winske oantal replika's (winske Replika's)
gewensteReplicas = [ currentReplicas * ( currentMetricValue / wantedMetricValue )]
Yn dit gefal sil skaalfergrutting net foarkomme as de koeffizient (currentMetricValue / wantedMetricValue) tichtby 1 is (yn dit gefal kinne wy de tastiene flater sels ynstelle; standert is it 0.1).
Litte wy sjen nei hoe't hpa wurket mei it foarbyld fan 'e app-test-applikaasje (beskreaun as Deployment), wêr't it nedich is om it oantal replika's te feroarjen ôfhinklik fan CPU-konsumpsje:
Dy. wy sjogge dat de applikaasje pod yn earste ynstânsje wurdt lansearre yn twa eksimplaren, dy't elk twa nginx- en nginx-eksporterkontainers befetsje, wêrfan elk in spesifisearre fersiken foar CPU.
Dy. Wy hawwe in hpa makke dy't de Deployment app-test sil kontrolearje en it oantal pods oanpasse mei de applikaasje basearre op de cpu-yndikator (wy ferwachtsje dat de pod 30% fan 'e CPU moat konsumearje dy't it freget), mei it oantal replika's yn it berik fan 2-10.
Litte wy no sjen nei it meganisme fan hpa-operaasje as wy in lading tapasse op ien fan 'e hurden:
# kubectl top pod
NAME CPU(cores) MEMORY(bytes)
app-test-78559f8f44-pgs58 101m 243Mi
app-test-78559f8f44-cj4jz 4m 240Mi
Yn totaal hawwe wy it folgjende:
De winske wearde (desiredMetricValue) - neffens de hpa-ynstellingen hawwe wy 30%
Aktuele wearde (currentMetricValue) - foar berekkening berekkent controller-manager de gemiddelde wearde fan boarne konsumpsje yn%, d.w.s. betingst docht it folgjende:
Untfangt absolute wearden fan pod-metriken fan 'e metrike tsjinner, d.w.s. 101m en 4m
Kriget de absolute wearde foar it winske boarneferbrûk (dêrfoar wurde de oanfragen fan alle konteners gearfette) 60m + 30m = 90m
Berekkent it gemiddelde persintaazje fan CPU-konsumpsje relatyf oan it fersyk pod, d.w.s. 53m / 90m * 100% = 59%
No hawwe wy alles wat wy nedich binne om te bepalen oft wy it oantal replika's moatte feroarje; Om dit te dwaan, berekkenje wy de koeffizient:
ratio = 59% / 30% = 1.96
Dy. it oantal replika's moat ferhege wurde mei ~2 kear en bedraacht [2 * 1.96] = 4.
Fermelding: Sa't jo sjen kinne, om dit meganisme te wurkjen, is in needsaaklike betingst de oanwêzigens fan oanfragen foar alle konteners yn 'e waarnommen pod.
Mechanisme foar horizontale autoskalearring fan knopen (Cluster Autoscaler)
Om de negative ynfloed op it systeem te neutralisearjen tidens load surges, is it net genôch om in konfigureare hpa te hawwen. Bygelyks, neffens de ynstellings yn 'e hpa-controllerbehearder, beslút it dat it oantal replika's mei 2 kear ferhege wurde moat, mar de knooppunten hawwe gjin frije boarnen om sa'n oantal pods út te fieren (d.w.s. it knooppunt kin de knooppunt net leverje oanfrege boarnen foar de fersiken pod) en dizze pods wikselje oer nei de Pending state.
Yn dit gefal, as de provider in oerienkommende IaaS/PaaS hat (bygelyks GKE/GCE, AKS, EKS, ensfh.), In ark lykas Node Autoscaler. It lit jo it maksimale en minimale oantal knooppunten yn it kluster ynstelle en automatysk it aktuele oantal knooppunten oanpasse (troch de wolkprovider API te skiljen om in knooppunt te bestellen / te ferwiderjen) as d'r in tekoart is oan boarnen yn it kluster en de pods kin net pland wurde (binne yn 'e steat fan ôfwachting).
Fermelding: Om knooppunten autoscale te kinnen, is it nedich om fersiken yn 'e podkonteners yn te stellen sadat k8's de lading op' e knooppunten korrekt kinne beoardielje en dus rapportearje dat d'r gjin boarnen binne yn it kluster om de folgjende pod te starten.
konklúzje
It moat opmurken wurde dat it ynstellen fan kontenerboarnegrinzen gjin fereaske is foar de applikaasje om mei súkses te rinnen, mar it is noch altyd better om dit te dwaan om de folgjende redenen:
Foar krekter wurking fan de planner yn termen fan load balancing tusken k8s knopen
Om de kâns te ferminderjen dat in "pod-eviction" barren plakfynt
Foar horizontale autoskalearring fan applikaasjepods (HPA) om te wurkjen
Foar horizontale autoscaling fan knopen (Cluster Autoscaling) foar wolkproviders