ProHoster > Блог > Administrado > Kubernetes: kial estas tiel grave agordi sisteman rimedadministradon?
Kubernetes: kial estas tiel grave agordi sisteman rimedadministradon?
Kiel regulo, ĉiam necesas provizi dediĉitan aron da rimedoj al aplikaĵo por ĝia ĝusta kaj stabila funkciado. Sed kio se pluraj aplikoj funkcias per la sama potenco? Kiel provizi al ĉiu el ili la minimumajn necesajn rimedojn? Kiel vi povas limigi konsumon de rimedoj? Kiel ĝuste distribui la ŝarĝon inter nodoj? Kiel certigi, ke la horizontala skala mekanismo funkcias se la aplika ŝarĝo pliiĝas?
Vi devas komenci per kiaj ĉefaj specoj de rimedoj ekzistas en la sistemo - ĉi tio, kompreneble, estas procesora tempo kaj RAM. En k8s-manifestoj ĉi tiuj rimedspecoj estas mezuritaj en la sekvaj unuoj:
CPU - en kernoj
RAM - en bajtoj
Krome, por ĉiu rimedo eblas agordi du specojn de postuloj - petoj и limoj. Petoj - priskribas la minimumajn postulojn por senpagaj resursoj de nodo por prizorgi ujon (kaj pod kiel tutaĵo), dum limoj fiksas malmolan limon al la rimedoj disponeblaj al la ujo.
Gravas kompreni, ke la manifesto ne devas eksplicite difini ambaŭ tipojn, sed la konduto estos jena:
Se nur la limoj de rimedo estas eksplicite specifitaj, tiam petoj por ĉi tiu rimedo aŭtomate prenas valoron egala al limoj (vi povas kontroli tion vokante priskribi entojn). Tiuj. fakte, la ujo estos limigita al la sama kvanto de rimedoj, kiujn ĝi postulas por funkcii.
Se nur petoj estas eksplicite specifitaj por rimedo, tiam neniuj supraj limigoj estas fiksitaj sur ĉi tiu rimedo - t.e. la ujo estas limigita nur de la rimedoj de la nodo mem.
Eblas ankaŭ agordi rimedadministradon ne nur je la nivelo de specifa ujo, sed ankaŭ ĉe la nomspaca nivelo uzante la jenajn entojn:
LimitRange — priskribas la limigan politikon ĉe la ujo/pod-nivelo en ns kaj necesas por priskribi la defaŭltajn limojn sur la ujo/pod, kaj ankaŭ malhelpi la kreadon de evidente grasaj ujoj/pod (aŭ inverse), limigi ilian nombron kaj determini la eblan diferencon en la valoroj en limoj kaj petoj
Rimedaj Kvotoj — priskribu la limigan politikon ĝenerale por ĉiuj ujoj en ns kaj estas uzata, kiel regulo, por limigi resursojn inter medioj (utila kiam medioj ne estas strikte limigitaj ĉe la noda nivelo)
La sekvantaroj estas ekzemploj de manifestoj, kiuj fiksas rimedlimojn:
Tiuj. en ĉi tiu kazo, por ruli ujon kun nginx, vi bezonos almenaŭ 1G da libera RAM kaj 0.2 CPU sur la nodo, dum maksimume la ujo povas konsumi 0.2 CPU kaj ĉiujn disponeblajn RAM sur la nodo.
Tiuj. la sumo de ĉiuj petaj ujoj en la defaŭlta ns ne povas superi 300m por la CPU kaj 1G por la OP, kaj la sumo de ĉiuj limoj estas 700m por la CPU kaj 2G por la OP.
Tiuj. en la defaŭlta nomspaco por ĉiuj ujoj, peto estos agordita al 100m por CPU kaj 1G por OP, limo - 1 CPU kaj 2G. Samtempe, limo ankaŭ estas fiksita al la eblaj valoroj en peto/limo por CPU (50m < x < 2) kaj RAM (500M < x < 4G).
Tiuj. por ĉiu pod en la defaŭlta ns estos limo de 4 vCPU kaj 1G.
Nun mi ŝatus diri al vi, kiajn avantaĝojn povas doni al ni agordi ĉi tiujn limigojn.
Ŝarĝbalanca mekanismo inter nodoj
Kiel vi scias, la k8s-komponento respondecas pri la distribuado de balgoj inter nodoj, kiel ekzemple planificador, kiu funkcias laŭ specifa algoritmo. Ĉi tiu algoritmo trairas du stadiojn kiam elektas la optimuman nodon por lanĉi:
Filtrado
Gaming
Tiuj. laŭ la priskribita politiko oni komence elektas nodojn, sur kiuj eblas lanĉi podon surbaze de aro predikatoj (inkluzive kontroli ĉu la nodo havas sufiĉajn rimedojn por ruli la pod - PodFitsResources), kaj poste por ĉiu el ĉi tiuj nodoj, laŭ prioritatoj punktoj estas aljuĝitaj (inkluzive, ju pli da liberaj rimedoj nodo havas, des pli da punktoj ĝi estas asignita - LeastResourceAllocation/LeastRequestedPriority/BalancedResourceAllocation) kaj la pod estas lanĉita sur la nodo kun la plej multaj poentoj (se pluraj nodoj kontentigas tiun ĉi kondiĉon samtempe, tiam hazarda estas elektita).
Samtempe, vi devas kompreni, ke la planisto, kiam oni taksas la disponeblajn rimedojn de nodo, estas gvidata de la datumoj stokitaj en etcd - t.e. por la kvanto de la petita/lima rimedo de ĉiu pod kuranta sur ĉi tiu nodo, sed ne por la reala rimeda konsumo. Ĉi tiu informo povas esti akirita de la komanda eligo kubectl describe node $NODEekzemple:
Ĉi tie ni vidas ĉiujn podojn kurantajn sur specifa nodo, same kiel la rimedojn, kiujn ĉiu podoj petas. Kaj jen kiel aspektas la protokoloj de la planilo kiam la podo cronjob-cron-events-1573793820-xt6q9 estas lanĉita (ĉi tiu informo aperos en la protokolo de la planilo kiam vi agordas la 10-an protokolan nivelon en la argumentoj de la startkomando -v=10):
ŝtipo
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
Ĉi tie ni vidas, ke komence la planilo filtras kaj generas liston de 3 nodoj, sur kiuj ĝi povas esti lanĉita (nxs-k8s-s8, nxs-k8s-s9, nxs-k8s-s10). Poste ĝi kalkulas poentarojn surbaze de pluraj parametroj (inkluzive de BalancedResourceAllocation, LeastResourceAllocation) por ĉiu el ĉi tiuj nodoj por determini la plej taŭgan nodon. Finfine, la podo estas planita sur la nodo kun la plej alta nombro da punktoj (ĉi tie du nodoj samtempe havas la saman nombron da punktoj 100037, do hazarda estas elektita - nxs-k8s-s10).
konkludo: se nodo rulas podojn por kiuj neniuj limigoj estas fiksitaj, tiam por k8s (el la vidpunkto de konsumo de rimedoj) tio ekvivalentos al kvazaŭ tiaj podoj en ĉi tiu nodo entute ne ekzistus. Sekve, se vi, kondiĉe, havas podon kun glutema procezo (ekzemple, wowza) kaj neniuj limigoj estas fiksitaj por ĝi, tiam situacio povas ekesti kiam ĉi tiu pod efektive manĝis ĉiujn rimedojn de la nodo, sed por k8s ĉi tiu nodo. estas konsiderata malŝarĝita kaj ĝi estos aljuĝita la saman nombron da poentoj kiam vi klasifikas (precize en punktoj taksantaj disponeblajn rimedojn) kiel nodo, kiu ne havas funkciajn podojn, kio finfine povas konduki al neegala distribuo de la ŝarĝo inter nodoj.
Eldomigo de Pod
Kiel vi scias, al ĉiu podo estas asignita unu el 3 QoS-klasoj:
garantiita — estas asignita kiam por ĉiu ujo en la pod peto kaj limo estas specifitaj por memoro kaj CPU, kaj ĉi tiuj valoroj devas kongrui
krevebla — almenaŭ unu ujo en la podo havas peton kaj limon, kun peto < limo
plej bona penado — kiam neniu ujo en la balgo estas rimedo limigita
Samtempe, kiam nodo spertas mankon de rimedoj (disko, memoro), kubelet komencas vicigi kaj forpeli podojn laŭ specifa algoritmo, kiu konsideras la prioritaton de la pod kaj ĝian QoS-klason. Ekzemple, se ni parolas pri RAM, tiam surbaze de la QoS-klaso, punktoj estas aljuĝitaj laŭ la sekva principo:
Tiuj. kun la sama prioritato, la kubelet unue elpelos podojn kun la plej bona peno QoS-klaso de la nodo.
konkludo: se vi volas redukti la verŝajnecon, ke la dezirata podo estu elpelita de la nodo okaze de manko de rimedoj sur ĝi, tiam kune kun la prioritato, vi ankaŭ devas zorgi pri agordo de la peto/limo por ĝi.
Mekanismo por horizontala aŭtoskalado de aplikaĵkapsuloj (HPA)
Kiam la tasko estas aŭtomate pliigi kaj malpliigi la nombron da podoj depende de la uzo de rimedoj (sistemo - CPU/RAM aŭ uzanto - rps), tia k8s ento kiel HPA (Horizontala Pod Autoscaler). La algoritmo de kiu estas kiel sekvas:
La aktualaj legaĵoj de la observita rimedo estas determinitaj (currentMetricValue)
La dezirataj valoroj por la rimedo estas determinitaj (desiredMetricValue), kiuj por sistemaj rimedoj estas fiksitaj per peto
La nuna nombro da kopioj estas determinita (nunaReplicas)
La sekva formulo kalkulas la deziratan nombron da kopioj (deziritajReplikoj)
deziratajReplikoj = [ nunajReplikoj * (nunaMetricValue / dezirataMetricaValoro)]
En ĉi tiu kazo, skalo ne okazos kiam la koeficiento (currentMetricValue / dezirataMetricValue) estas proksima al 1 (en ĉi tiu kazo, ni mem povas agordi la permeseblan eraron; defaŭlte ĝi estas 0.1).
Ni rigardu kiel hpa funkcias uzante la ekzemplon de la aplikaĵo-testa aplikaĵo (priskribita kiel Deplojo), kie necesas ŝanĝi la nombron da kopioj depende de la CPU-konsumo:
Tiuj. ni vidas, ke la aplikaĵo pod estas komence lanĉita en du okazoj, ĉiu el kiuj enhavas du nginx kaj nginx-exporter-ujojn, por ĉiu el kiuj specifita. petoj por CPU.
Tiuj. Ni kreis hpa, kiu kontrolos la Deployment-ap-teston kaj ĝustigos la nombron da podoj kun la aplikaĵo bazita sur la cpu-indikilo (ni atendas, ke la podo devas konsumi 30% de la CPU, kiun ĝi petas), kun la nombro da kopioj enestas. la gamo de 2-10.
Nun, ni rigardu la mekanismon de hpa operacio se ni aplikas ŝarĝon al unu el la fajrujoj:
# kubectl top pod
NAME CPU(cores) MEMORY(bytes)
app-test-78559f8f44-pgs58 101m 243Mi
app-test-78559f8f44-cj4jz 4m 240Mi
Entute ni havas la jenajn:
La dezirata valoro (desiredMetricValue) - laŭ la agordoj de hpa, ni havas 30%
Nuna valoro (currentMetricValue) - por kalkulo, regilo-administranto kalkulas la averaĝan valoron de konsumo de rimedoj en %, t.e. kondiĉe faras la jenon:
Ricevas absolutajn valorojn de pod-metrikoj de la metrika servilo, t.e. 101m kaj 4m
Akiras la absolutan valoron por la dezirata konsumo de rimedoj (por tio, la petoj de ĉiuj ujoj estas resumitaj) 60m + 30m = 90m
Kalkulas la mezan procenton de CPU-konsumo rilate al la petopodo, t.e. 53m / 90m * 100% = 59%
Nun ni havas ĉion, kion ni bezonas por determini ĉu ni devas ŝanĝi la nombron da kopioj; por fari tion, ni kalkulas la koeficienton:
ratio = 59% / 30% = 1.96
Tiuj. la nombro da kopioj devus esti pliigita je ~2 fojojn kaj sumiĝi al [2 * 1.96] = 4.
Konkludo: Kiel vi povas vidi, por ke ĉi tiu mekanismo funkciu, necesa kondiĉo estas la ĉeesto de petoj por ĉiuj ujoj en la observita pod.
Mekanismo por horizontala aŭtoskalado de nodoj (Cluster Autoscaler)
Por neŭtraligi la negativan efikon al la sistemo dum ŝargiĝoj, havi agordita hpa ne sufiĉas. Ekzemple, laŭ la agordoj en la administranto de hpa regilo, ĝi decidas, ke la nombro da kopioj devas esti pliigita je 2 fojojn, sed la nodoj ne havas senpagajn rimedojn por ruli tian nombron da podoj (t.e. la nodo ne povas provizi la petitaj rimedoj al la petoj pod) kaj ĉi tiuj balgoj ŝanĝas al la Atendata stato.
En ĉi tiu kazo, se la provizanto havas respondan IaaS/PaaS (ekzemple, GKE/GCE, AKS, EKS, ktp.), ilo kiel Nodo Aŭtoskaler. Ĝi ebligas al vi agordi la maksimuman kaj minimuman nombron da nodoj en la areto kaj aŭtomate ĝustigi la nunan nombron da nodoj (vokante la nuba provizanto API por ordigi/forigi nodon) kiam mankas rimedoj en la areto kaj la podoj. ne povas esti planita (estas en la Atendata stato).
Konkludo: Por povi aŭtomskali nodojn, necesas agordi petojn en la podujoj, por ke k8s povu ĝuste taksi la ŝarĝon sur la nodoj kaj sekve raporti, ke ne ekzistas rimedoj en la areto por lanĉi la sekvan podaĵon.
konkludo
Oni devas rimarki, ke agordi limojn pri ujrimedo ne estas postulo por ke la aplikaĵo rulu sukcese, sed ankoraŭ estas pli bone fari tion pro la sekvaj kialoj:
Por pli preciza funkciado de la planilo laŭ ŝarĝoekvilibro inter k8s-nodoj
Redukti la verŝajnecon de "pod-eldomigo-" okazaĵo okazanta
Por ke horizontala aŭtoskalo de aplikaĵaj kapsuloj (HPA) funkciu
Por horizontala aŭtoskalado de nodoj (Cluster Autoscaling) por nubaj provizantoj