
Når man begynder at arbejde med Kubernetes, glemmer man ofte at indstille containerressourcer. På dette trin er det nok at sikre, at Docker-billedet fungerer, og at det kan implementeres i Kubernetes-klusteret.
Men senere kræves det, at applikationen implementeres i produktionsklusteret sammen med andre applikationer. For dette skal der tildeles ressourcer til containeren, og det skal sikres, at der er tilstrækkeligt til at starte og køre applikationen uden problemer i de øvrige kørende applikationer.
Kommandoen oversatte artiklen om containerressourcer (CPU & MEM), ressourceanmodninger og -begrænsninger. Du vil lære, hvilke fordele disse indstillinger giver, og hvad der vil ske, hvis de ikke indstilles.
Beregning ressourcer
Vi har to typer ressourcer med følgende enheder:
- Central processor (CPU) — kerner;
- Hukommelse (MEM) — byte.
Ressourcer angives for hver container. I den følgende YAML-fil Pod vil du se en ressourceafsnit, der indeholder anmodede og maksimale ressourcer:
- Anmodede ressourcer for Pod = summen af de anmodede ressourcer for alle containere;
- Maksimale ressourcer for Pod = summen af de maksimale ressourcer for alle containere.
apiVersion: v1
kind: Pod
metadata:
name: backend-pod-name
labels:
application: backend
spec:
containers:
- name: main-container
image: my-backend
tag: v1
ports:
- containerPort: 8080
resources:
requests:
cpu: 0.2 # ANMODET CPU: 200m kerner
memory: "1Gi" # ANMODET MEM: 1Gi
limits:
cpu: 1 # MAKSIMAL CPU BRUG: 1 kerne
memory: "1Gi" # MAKSIMAL MEM BRUG: 1Gi
- name: other-container
image: other-app
tag: v1
ports:
- containerPort: 8000
resources:
requests:
cpu: "200m" # ANMODET CPU: 200m kerner
memory: "0.5Gi" # ANMODET MEM: 0.5Gi
limits:
cpu: 1 # MAKSIMAL CPU BRUG: 1 kerne
memory: "1Gi" # MAKSIMAL MEM BRUG: 1GiEksempel på anmodede og maksimale ressourcer
Felt resources.requested fra Pod-specifikationen — et af elementerne, der bruges til at finde den relevante node. Den kan allerede planlægges til implementeringen af Pod. Hvordan finder man den passende node?
Kubernetes består af flere komponenter, herunder indeholder en hovednode eller master-node (Kubernetes Control Plane). I master-noden findes der flere processer: kube-apiserver, kube-controller-manager og kube-scheduler.
Processen kube-scheduler er ansvarlig for at se på nyoprettede pods og finde mulige arbejdsnoder, der opfylder alle pods anmodninger, herunder mængden af anmodede ressourcer. Listen over noder fundet af kube-scheduler rangeres. Pod planlægges på noden med de højeste scores.
Hvor vil den lilla Pod blive placeret?
På billedet kan vi se, at kube-scheduler skal planlægge en ny violet Pod. Kubernetes-klustret indeholder to noder: A og B. Som det kan ses, kan kube-scheduler ikke planlægge Pod'en på node A — de tilgængelige (uafkrævede) ressourcer opfylder ikke anmodningen fra den violet Pod. Den anmodede 1 GB hukommelse fra den violet Pod kan ikke passe ind på node A, da den tilgængelige hukommelse er 0,5 GB. Men node B har tilstrækkelige ressourcer. I sidste ende beslutter kube-scheduler, at destinationen for den violet Pod er node B.
Nu ved vi, hvordan de anmodede ressourcer påvirker valget af node til at køre Pod. Men hvordan påvirker grænseressourcerne?
Grænseressourcer er den grænse, som CPU/MEM ikke kan overskride. Dog er CPU-ressourcen fleksibel, så containere, der når grænseværdierne for CPU, vil ikke få Pod'en til at stoppe. I stedet vil der blive implementeret throttling af CPU. Hvis grænsen for brugen af MEM derimod nås, vil containeren blive stoppet af OOM-Killer og derefter genstartes, hvis det er tilladt i indstillingen RestartPolicy.
Anmodede og grænseressourcer i detaljer
Forbindelsen mellem ressourcerne i Docker og Kubernetes
Den bedste måde at forklare, hvordan anmodede og grænseressourcer fungerer, er at præsentere forbindelsen mellem Kubernetes og Docker. På billedet ovenfor kan du se, hvordan felterne i Kubernetes og Docker's opstartssflags hænger sammen.
Hukommelse: anmodning og grænse
containers:
...
resources:
requests:
memory: "0.5Gi"
limits:
memory: "1Gi"
Som nævnt ovenfor, måles hukommelse i byte. Baseret på , kan vi angive hukommelsen som et tal. Det er normalt et helt tal, for eksempel 2678 — det vil sige 2678 byte. Du kan også bruge suffikserne G og Gi, det vigtigste er at huske, at de ikke er ens. Den første er decimal, mens den anden er binær. Som eksempel nævnt i k8s-dokumentationen: 128974848, 129e6, 129M, 123Mi — de er praktisk talt ens.
Kubernetes parameter limits.memory svarer til flaget --memory fra Docker. I tilfælde af request.memory er der ikke noget tilsvarende flag i Docker, da Docker ikke bruger dette felt. Du spørger måske, om det overhovedet er nødvendigt? Ja, det er nødvendigt. Som jeg sagde, har feltet betydning for Kubernetes. Baseret på informationer herfra beslutter kube-scheduler, hvilken node der skal planlægges til Pod'en.
Hvad sker der, hvis der anmodes om for lidt hukommelse?
Hvis containeren når grænserne for den anmodede hukommelse, placeres Pod'en i en gruppe af Pods, der stoppes, når der opstår hukommelsesmangel på node.
Hvad sker der, hvis der indstilles en for lav grænse for hukommelse?
Hvis containeren overstiger hukommelsesgrænsen, afsluttes den med OOM-Killed. Den vil blive genstartet, hvis det er muligt i henhold til RestartPolicy, hvor standardværdien er Altid.
Hvad sker der, hvis der ikke angives anmodet hukommelse?
Kubernetes vil tage grænseværdien og indstille den som standardværdi.
Hvad kan der ske, hvis der ikke angives grænse for hukommelse?
Containeren har ingen begrænsninger og kan bruge så meget hukommelse, som den vil. Hvis den begynder at bruge al den tilgængelige hukommelse på noden, vil den blive dræbt af OOM. Derefter vil containeren blive genstartet, hvis det er muligt i henhold til RestartPolicy.
Hvad sker der, hvis der ikke angives hukommelsesbegrænsninger?
Det er det værste scenarie: Planlæggeren ved ikke, hvor mange ressourcer containeren har brug for, og det kan forårsage alvorlige problemer på noden. I dette tilfælde ville det være godt at have standardbegrænsninger i navnerummet (fastsat af LimitRange). Der er ingen standardbegrænsninger — Pod har ingen begrænsninger og kan bruge så meget hukommelse, som den vil.
Hvis den anmodede hukommelse er mere, end noden kan tilbyde, vil Pod ikke blive planlagt. Det er vigtigt at huske, at Requests.memory — ikke er minimumsværdien. Det er en beskrivelse af den mængde hukommelse, der er tilstrækkelig til, at containeren kan køre stabilt.
Det anbefales generelt at indstille den samme værdi for request.memory og limit.memory. Ved dette vil Kubernetes ikke planlægge Pod på en node, der har nok hukommelse til at starte Pod'en, men ikke nok til at køre den. Husk: Når Kubernetes planlægger Pod, tager det kun requests.memory, og limits.memory i betragtning.
CPU: anmodning og grænse
containers:
...
resources:
requests:
cpu: 1
limits:
cpu: "1200m"
Med CPU'en er det lidt mere kompliceret. Når vi ser tilbage på billedet af forholdet mellem Kubernetes og Docker, kan vi bemærke, at request.cpu svarer til --cpu-shares, mens limit.cpu svarer til flaget cpus i Docker.
CPU'en, som Kubernetes anmoder om, ganges med 1024 — forholdet for CPU-cyklusser. Hvis du vil anmode om 1 fuld kerne, skal du tilføje cpu: 1, som vist ovenfor.
Anmodning om en fuld kerne (forhold = 1024) betyder ikke, at din container vil få den. Hvis din værtscomputer kun har en kerne, og du bruger mere end én container, skal alle containerne dele den tilgængelige CPU imellem sig. Hvordan sker det? Lad os se på billedet.

CPU-anmodning - et system med et enkelt kerne
Lad os forestille os, at du har et værtssystem med ét kerne, hvor containere kører. Mor (Kubernetes) har bagt en kage (CPU) og vil dele den mellem børnene (containere). Tre børn ønsker en hel kage (forhold = 1024), mens et andet barn ønsker halvdelen af en kage (512). Mor ønsker at være retfærdig og udfører en simpel beregning.
# Сколько пирогов хотят дети?
# 3 ребенка хотят по целому пирогу и еще один хочет половину пирога
cakesNumberKidsWant = (3 * 1) + (1 * 0.5) = 3.5
# Выражение получается так:
3 (ребенка/контейнера) * 1 (целый пирог/полное ядро) + 1 (ребенок/контейнер) * 0.5 (половина пирога/половина ядра)
# Сколько пирогов испечено?
availableCakesNumber = 1
# Сколько пирога (максимально) дети реально могут получить?
newMaxRequest = 1 / 3.5 =~ 28%Ifølge beregningen vil de tre børn få 28% af kernen, i stedet for en hel kerne. Det fjerde barn vil få 14% af en hel kerne, i stedet for halvdelen. Men alt vil være anderledes, hvis du har et multicore-system.

CPU-anmodning - multicore (4) system
På billedet ovenfor kan man se, at tre børn ønsker en hel kage, mens et ønsker halvdelen. Da mor har bagt fire kager, vil hvert af hendes børn få så meget, som de ønsker. I et multicore-system fordeles CPU-ressourcerne over alle tilgængelige kerner. Hvis en container er begrænset til mindre end én hel CPU-kerne, kan den stadig bruge den 100%.
De ovenstående beregninger er forenklet for at forstå, hvordan CPU fordeles mellem containere. Selvfølgelig er der også andre processer, udover selve containerne, som også bruger CPU-ressourcer. Når processerne i én container er inaktive, kan andre bruge dens ressourcer. CPU: "200m" svarer til CPU: 0,2, hvilket svarer til cirka 20% af én kerne.
Lad os nu tale om limit.cpu. CPU, der begrænser Kubernetes, multipliceres med 100. Resultatet er mængden af tid, som en container kan bruge hver 100 µs (cpu-period).
limit.cpu svare til Docker-flaget --cpus. Det er en ny kombination af gamle --cpu-period og --cpu-quota. Når vi indstiller det, angiver vi, hvor mange tilgængelige CPU-ressourcer en container maksimalt kan bruge, indtil throttling begynder:
- cpus — kombinationen af
cpu-periodogcpu-quota. cpus = 1.5motsvarer indstillingencpu-period = 100000ogcpu-quota = 150000; - cpu-period — perioder , som standard 100 mikrosekunder;
- cpu-quota — antal mikrosekunder indenfor
cpu-period, som containeren er begrænset til.
Hvad sker der, hvis man sætter en utilstrækkelig CPU-anmodning?
Hvis containeren har brug for mere, end der er indstillet, vil den stjæle CPU fra andre processer.
Hvad vil der ske, hvis man sætter en utilstrækkelig CPU-grænse?
Da CPU-ressourcen er justerbar, vil throttling blive aktiveret.
Hvad vil der ske, hvis man ikke angiver CPU-anmodningen?
Ligesom med hukommelse er anmodningen lig med grænsen.
Hvad sker der, hvis grænsen for CPU не er angivet?
Containeren vil bruge så meget CPU, som den har brug for. Hvis der er defineret en standard CPU-politik i navnerummet (LimitRange), vil denne grænse blive anvendt for containeren.
Hvad sker der, hvis hverken anmodningen eller grænsen for CPU angives?
Som med hukommelse er dette det værste scenarie. Planlæggeren ved ikke, hvor mange ressourcer din container har brug for, og det kan forårsage alvorlige problemer på noden. For at undgå dette skal der opsættes standardgrænser for navnerumene (LimitRange).
Husk: hvis du anmoder om mere CPU, end noderne kan levere, vil Pod'en ikke blive planlagt. Requests.cpu — ikke et minimalt beløb, men et beløb, der er tilstrækkeligt til at køre Pod'en og fungere uden problemer. Hvis applikationen ikke udfører komplekse beregninger, er det bedste valg at indstille request.cpu <= 1 og køre så mange replikaer, som nødvendigt.
Det ideelle antal anmodede ressourcer eller ressourcegrænser
Vi har lært om begrænsningen af computerressourcer. Nu er det tid til at besvare spørgsmålet: "Hvor mange ressourcer har min Pod brug for for at køre applikationen problemfrit? Hvad er det ideelle antal?".
Desværre er der ikke entydige svar på disse spørgsmål. Hvis du ikke ved, hvordan din applikation fungerer, og hvor meget CPU eller hukommelse den har brug for, er det bedste valg at give applikationen rigeligt med hukommelse og CPU og derefter køre ytelsestests.
Udover ytelsestests skal du over en uge overvåge applikationens adfærd i overvågningen. Hvis graferne viser, at din applikation bruger færre ressourcer, end du har anmodet om, kan du reducere antallet af anmodet CPU eller hukommelse.
Som et eksempel kan du se dette . Det viser forskellen mellem anmodede ressourcer eller ressourcegrænser og den aktuelle ressourcedistribution.
Konklusion
Anmodning og begrænsning af ressourcer hjælper med at opretholde Kubernetes-klyngens drift. Korrekt konfiguration af grænser minimerer omkostningerne og opretholder konstant applikationerne i drift.
Kort sagt, husk på flere ting:
- De anmodede ressourcer er en konfiguration, der tages i betragtning under opstarten (når Kubernetes planlægger placeringen af applikationen). Omvendt er ressourcegrænse vigtig under drift — når applikationen allerede kører på en node.
- I forhold til hukommelse er CPU en reguleret ressource. I tilfælde af CPU-mangel vil din Pod ikke afslutte, men throttling-mekanismer aktiveres.
- De anmodede ressourcer og ressourcegrænse er ikke minimums- og maksimumsværdier! Ved at definere de anmodede ressourcer sikrer du, at applikationen fungerer problemfrit.
- En god praksis er at indstille en hukommelsesforespørgsel, der svarer til hukommelsesgrænsen.
- Det er en god idé at indstille den anmodede
CPU <=1, hvis applikationen ikke udfører komplekse beregninger. - Hvis du anmoder om flere ressourcer, end der er tilgængeligt på noden, vil Pod aldrig blive planlagt på denne node.
- For at bestemme den rigtige mængde anmodede ressourcer/ressourcegrænser, brug belastningstest og overvågning.
Jeg håber, denne artikel hjælper dig med at forstå grundkonceptet for ressourcebegrænsninger. Og at du kan anvende denne viden i dit arbejde.
Held og lykke!
Yderligere læsning:
- .
- .
- .
Kilde: habr.com
