ProHoster > Log > administrasjon > Kubernetes: hvorfor er det så viktig å konfigurere systemressursadministrasjon?
Kubernetes: hvorfor er det så viktig å konfigurere systemressursadministrasjon?
Som regel er det alltid behov for å gi en dedikert ressurssamling til en applikasjon for korrekt og stabil drift. Men hva om flere applikasjoner kjører på samme strøm? Hvordan gi hver av dem de minste nødvendige ressursene? Hvordan kan du begrense ressursforbruket? Hvordan fordele belastningen riktig mellom noder? Hvordan sikre at den horisontale skaleringsmekanismen fungerer hvis applikasjonsbelastningen øker?
Du må starte med hvilke hovedtyper av ressurser som finnes i systemet - dette er selvfølgelig prosessortid og RAM. I k8s-manifester måles disse ressurstypene i følgende enheter:
CPU - i kjerner
RAM - i byte
Dessuten, for hver ressurs er det mulig å stille to typer krav - forespørsler и grenser. Forespørsler - beskriver minimumskravene for ledige ressurser til en node for å kjøre en container (og pod som helhet), mens limits setter en hard grense for ressursene som er tilgjengelige for containeren.
Det er viktig å forstå at manifestet ikke trenger å eksplisitt definere begge typer, men atferden vil være som følger:
Hvis bare grensene for en ressurs er eksplisitt spesifisert, vil forespørsler om denne ressursen automatisk ha en verdi som tilsvarer grenser (du kan bekrefte dette ved å kalle describe entities). De. faktisk vil beholderen være begrenset til samme mengde ressurser som den krever for å kjøre.
Hvis bare forespørsler er eksplisitt spesifisert for en ressurs, er ingen øvre restriksjoner satt på denne ressursen - dvs. beholderen begrenses kun av ressursene til selve noden.
Det er også mulig å konfigurere ressursadministrasjon ikke bare på nivået til en bestemt beholder, men også på navneromsnivået ved å bruke følgende enheter:
LimitRange — beskriver restriksjonspolicyen på beholder-/pod-nivå i ns og er nødvendig for å beskrive standardgrensene på beholderen/poden, samt forhindre at det lages åpenbart fete containere/pods (eller omvendt), begrense antallet og bestemme den mulige forskjellen i verdiene i grenser og forespørsler
Ressurskvoter — beskrive restriksjonspolitikken generelt for alle containere i ns og brukes som regel for å avgrense ressurser mellom miljøer (nyttig når miljøer ikke er strengt avgrenset på nodenivå)
Følgende er eksempler på manifester som setter ressursgrenser:
De. i dette tilfellet, for å kjøre en container med nginx, trenger du minst 1G ledig RAM og 0.2 CPU på noden, mens containeren maksimalt kan forbruke 0.2 CPU og all tilgjengelig RAM på noden.
De. summen av alle forespørselsbeholdere i standard ns kan ikke overstige 300m for CPU og 1G for OP, og summen av alle grenser er 700m for CPU og 2G for OP.
De. i standard navneområde for alle beholdere, vil forespørselen bli satt til 100m for CPU og 1G for OP, limit - 1 CPU og 2G. Samtidig settes det også en grense på mulige verdier i request/limit for CPU (50m < x < 2) og RAM (500M < x < 4G).
De. for hver pod i standard ns vil det være en grense på 4 vCPU og 1G.
Nå vil jeg gjerne fortelle deg hvilke fordeler det kan gi oss å sette disse begrensningene.
Lastbalanseringsmekanisme mellom noder
Som du vet er k8s-komponenten ansvarlig for fordelingen av pods blant noder, som f.eks planleggeren, som fungerer i henhold til en bestemt algoritme. Denne algoritmen går gjennom to stadier når du velger den optimale noden å starte:
filtrering
Rangering
De. i henhold til den beskrevne policyen, velges noder i utgangspunktet der det er mulig å starte en pod basert på et sett predikater (inkludert å sjekke om noden har nok ressurser til å kjøre poden - PodFitsResources), og deretter for hver av disse nodene, iht. prioriteringer poeng tildeles (inkludert, jo flere ledige ressurser en node har, jo flere poeng tildeles den - LeastResourceAllocation/LeastRequestedPriority/BalancedResourceAllocation) og poden startes på noden med flest poeng (hvis flere noder tilfredsstiller denne betingelsen samtidig, da en tilfeldig er valgt).
Samtidig må du forstå at planleggeren, når du vurderer de tilgjengelige ressursene til en node, styres av dataene som er lagret i etcd - dvs. for mengden av den forespurte/begrense ressursen for hver pod som kjører på denne noden, men ikke for det faktiske ressursforbruket. Denne informasjonen kan hentes fra kommandoutgangen kubectl describe node $NODE, for eksempel:
Her ser vi alle podene som kjører på en bestemt node, samt ressursene som hver pod ber om. Og her er hvordan planleggerloggene ser ut når cronjob-cron-events-1573793820-xt6q9-poden startes (denne informasjonen vil vises i planleggerloggen når det 10. loggingsnivået er satt i argumentene til startkommandoen -v=10 ):
Logg
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
Her ser vi at planleggeren først filtrerer og genererer en liste med 3 noder som den kan startes på (nxs-k8s-s8, nxs-k8s-s9, nxs-k8s-s10). Deretter beregner den skårer basert på flere parametere (inkludert BalancedResourceAllocation, LeastResourceAllocation) for hver av disse nodene for å finne den mest passende noden. Til syvende og sist er poden planlagt på noden med høyest antall poeng (her har to noder samme antall poeng 100037, så en tilfeldig en er valgt - nxs-k8s-s10).
Utgang: hvis en node kjører pods som det ikke er satt noen restriksjoner for, så for k8s (fra et ressursforbruk) vil dette tilsvare som om det ikke fantes slike poder på denne noden i det hele tatt. Derfor, hvis du, betinget, har en pod med en fråtsende prosess (for eksempel wowza) og ingen begrensninger er satt for den, kan det oppstå en situasjon når denne poden faktisk spiste alle ressursene til noden, men for k8s denne noden regnes som ubelastet og det vil bli tildelt samme antall poeng ved rangering (nøyaktig i poeng som vurderer tilgjengelige ressurser) som en node som ikke har fungerende pods, noe som til slutt kan føre til ujevn fordeling av lasten mellom noder.
Pods utkastelse
Som du vet, er hver pod tildelt en av 3 QoS-klasser:
garantert — tildeles når for hver beholder i poden en forespørsel og grense er spesifisert for minne og cpu, og disse verdiene må samsvare
sprengbar — minst én beholder i poden har en forespørsel og en grense, med forespørsel < grense
beste innsats — når ikke en eneste beholder i poden er ressursbegrenset
Samtidig, når en node opplever mangel på ressurser (disk, minne), begynner kubelet å rangere og kaste ut poder i henhold til en spesifikk algoritme som tar hensyn til prioriteten til poden og dens QoS-klasse. Hvis vi for eksempel snakker om RAM, tildeles poeng basert på QoS-klassen i henhold til følgende prinsipp:
De. med samme prioritet vil kubelet først kaste ut poder med den beste QoS-klassen fra noden.
Utgang: hvis du vil redusere sannsynligheten for at ønsket pod blir kastet ut av noden i tilfelle mangel på ressurser på den, så må du sammen med prioriteringen også sørge for å sette forespørselen/grensen for den.
Mekanisme for horisontal autoskalering av applikasjonsputer (HPA)
Når oppgaven er å automatisk øke og redusere antall pods avhengig av ressursbruken (system - CPU/RAM eller bruker - rps), for eksempel en k8s-enhet som HPA (Horizontal Pod Autoscaler). Algoritmen som er som følger:
Gjeldende avlesninger for den observerte ressursen bestemmes (currentMetricValue)
De ønskede verdiene for ressursen bestemmes (desiredMetricValue), som for systemressurser settes ved hjelp av forespørsel
Det nåværende antallet replikaer bestemmes (currentReplicas)
Følgende formel beregner ønsket antall replikaer (ønskede replikaer)
ønsketReplicas = [ currentReplicas * ( currentMetricValue / ønsketMetricValue )]
I dette tilfellet vil ikke skalering forekomme når koeffisienten (currentMetricValue / ønsketMetricValue) er nær 1 (i dette tilfellet kan vi angi den tillatte feilen selv; som standard er den 0.1).
La oss se på hvordan hpa fungerer ved å bruke eksemplet med app-testapplikasjonen (beskrevet som Deployment), der det er nødvendig å endre antall replikaer avhengig av CPU-forbruk:
De. vi ser at applikasjonspoden i utgangspunktet lanseres i to tilfeller, som hver inneholder to nginx- og nginx-eksportørbeholdere, for hver av dem en spesifisert forespørsler for CPU.
De. Vi opprettet en hpa som vil overvåke deployment app-testen og justere antall pods med applikasjonen basert på cpu-indikatoren (vi forventer at poden skal forbruke 30 % av CPUen den ber om), med antall replikaer i området 2-10.
La oss nå se på mekanismen for hpa-drift hvis vi legger en belastning på en av ildstedene:
# kubectl top pod
NAME CPU(cores) MEMORY(bytes)
app-test-78559f8f44-pgs58 101m 243Mi
app-test-78559f8f44-cj4jz 4m 240Mi
Totalt har vi følgende:
Ønsket verdi (ønsketMetricValue) - i henhold til hpa-innstillingene har vi 30 %
Gjeldende verdi (currentMetricValue) - for beregning beregner controller-manager gjennomsnittsverdien av ressursforbruket i %, dvs. betinget gjør følgende:
Mottar absolutte verdier av pod-beregninger fra metrisk server, dvs. 101m og 4m
Får absolutt verdi for ønsket ressursforbruk (for dette summeres forespørslene til alle containere) 60m + 30m = 90m
Beregner den gjennomsnittlige prosentandelen av CPU-forbruk i forhold til forespørselspoden, dvs. 53 m / 90 m * 100 % = 59 %
Nå har vi alt vi trenger for å finne ut om vi trenger å endre antall kopier; for å gjøre dette, beregner vi koeffisienten:
ratio = 59% / 30% = 1.96
De. antall replikaer bør økes med ~2 ganger og utgjøre [2 * 1.96] = 4.
Konklusjon: Som du kan se, for at denne mekanismen skal fungere, er en nødvendig betingelse tilstedeværelsen av forespørsler for alle beholdere i den observerte poden.
Mekanisme for horisontal autoskalering av noder (Cluster Autoscaler)
For å nøytralisere den negative påvirkningen på systemet under belastningsstøt, er det ikke nok å ha en konfigurert hpa. For eksempel, i henhold til innstillingene i hpa controller manager, bestemmer den at antall replikaer må økes med 2 ganger, men nodene har ikke ledige ressurser til å kjøre et slikt antall pods (dvs. noden kan ikke gi forespurte ressurser til forespørsler-poden), og disse podene bytter til Venter-tilstanden.
I dette tilfellet, hvis leverandøren har en tilsvarende IaaS/PaaS (for eksempel GKE/GCE, AKS, EKS, etc.), et verktøy som Node Autoscaler. Den lar deg angi maksimalt og minimum antall noder i klyngen og automatisk justere gjeldende antall noder (ved å ringe skyleverandørens API for å bestille/fjerne en node) når det er mangel på ressurser i klyngen og podene kan ikke planlegges (er i ventende tilstand).
Konklusjon: For å kunne autoskalere noder, er det nødvendig å sette forespørsler i pod-beholderne slik at k8s kan korrekt vurdere belastningen på nodene og følgelig rapportere at det ikke er ressurser i klyngen for å starte neste pod.
Konklusjon
Det skal bemerkes at det ikke er et krav for at applikasjonen skal kunne kjøres, å sette beholderressursgrenser, men det er likevel bedre å gjøre det av følgende grunner:
For mer nøyaktig drift av planleggeren når det gjelder lastbalansering mellom k8s noder
For å redusere sannsynligheten for at en "pod-utkastelse"-hendelse inntreffer
For at horisontal autoskalering av applikasjonsputer (HPA) skal fungere
For horisontal autoskalering av noder (Cluster Autoscaling) for skyleverandører