
I början av arbetet med Kubernetes glömmer man ofta att konfigurera containerresurser. Vid det här skedet räcker det att se till att Docker-bilden fungerar och kan deployas i Kubernetes-klustret.
Men senare krävs det att applikationen deployas i produktionsklustret tillsammans med andra applikationer. För detta måste resurser tilldelas till containern och det måste säkerställas att det finns tillräckligt med resurser för att starta och köra applikationen, så att det inte uppstår problem i de andra körande applikationerna.
Team översatte artikeln om containerresurser (CPU & MEM), resursförfrågningar och resursbegränsningar. Du får veta vilka fördelar dessa inställningar ger och vad som kommer att hända om de inte ställs in.
Beräkningsresurser
Vi har två typer av resurser med följande enheter:
- Centralprocessor (CPU) – kärnor;
- Minne (MEM) – byte.
Resurser anges för varje container. I den följande YAML-filen för Pod kommer du att se resursavsnittet som innehåller begärda och begränsade resurser:
- Begärda resurser för Pod = summan av begärda resurser för alla containrar;
- Begränsade resurser för Pod = summan av begränsade resurser för alla containrar.
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 # BEGÄRD CPU: 200m kärnor
memory: "1Gi" # BEGÄRT MINNE: 1Gi
limits:
cpu: 1 # MAX CPU ANVÄNDNING: 1 kärna
memory: "1Gi" # MAX MINNE ANVÄNDNING: 1Gi
- name: other-container
image: other-app
tag: v1
ports:
- containerPort: 8000
resources:
requests:
cpu: "200m" # BEGÄRD CPU: 200m kärnor
memory: "0.5Gi" # BEGÄRT MINNE: 0.5Gi
limits:
cpu: 1 # MAX CPU ANVÄNDNING: 1 kärna
memory: "1Gi" # MAX MINNE ANVÄNDNING: 1GiExempel på begärda och begränsade resurser
Fältet resources.requested från Pod-specifikationen — ett av elementen som används för att hitta den nödvändiga noden. Redan här kan man schemalägga distributionen av Pod. Hur letar man efter en lämplig nod?
Kubernetes består av flera komponenter, inklusive en huvudnod eller masternod (Kubernetes Control Plane). I masterknuten finns flera processer: kube-apiserver, kube-controller-manager och kube-scheduler.
Processen kube-scheduler ansvarar för att granska nyskapade moduler och söka efter möjliga arbetsnoder som uppfyller alla modulers krav, inklusive mängden begärda resurser. Listan över noder som kube-scheduler hittar rangordnas. Pod schemaläggs på noden med de högsta poängen.
Vart kommer den lila Pod att placeras?
I bilden kan vi se att kube-scheduler måste schemalägga en ny lila Pod. Kubernetes-klustret innehåller två noder: A och B. Som ni kan notera kan kube-scheduler inte schemalägga Pod på nod A — de tillgängliga (oanvända) resurserna matchar inte kraven för den lila Pod. Så den begärda minneskapaciteten på 1 GB från den lila Pod får inte plats på nod A, eftersom det tillgängliga minnet är 0,5 GB. Men nod B har tillräckligt med resurser. Som resultat beslutar kube-scheduler att destinationen för den lila Pod är nod B.
Nu vet vi hur de begärda resurserna påverkar valet av nod för att köra Pod. Men hur påverkar de maximala resurserna?
Maximala resurser är gränsen som CPU/MEM inte får överskrida. Emellertid är CPU-resursen flexibel, så containrar som har nått begränsningsvärdena för CPU kommer inte att avsluta Pod. Istället kommer CPU att throttlas. Om minnesgränsen nås kommer containern att stoppas av OOM-Killer och startas om om det är tillåtet av inställningen RestartPolicy.
Begärda och maximala resurser i detalj
Resurskopplingen mellan Docker och Kubernetes
Det bästa sättet att förklara hur begärda och maximala resurser fungerar är att visa kopplingen mellan Kubernetes och Docker. På bilden ovan kan du se hur fälten i Kubernetes och startflaggorna för Docker hänger ihop.
Minnesbegäran och begränsning
containers:
...
resources:
requests:
memory: "0.5Gi"
limits:
memory: "1Gi"
Som nämnts ovan mäts minnet i byte. Baserat på , kan vi ange minnet som ett heltal. Normalt är det ett heltal, exempelvis 2678 — det vill säga 2678 byte. Du kan också använda suffix G och Gi, det viktiga är att komma ihåg att de inte är likvärdiga. Den första är decimal och den andra är binär. Som exempel, som nämnts i k8s-dokumentationen: 128974848, 129e6, 129M, 123Mi — de är praktiskt taget ekvivalenta.
Kubernetes-parametern limits.memory motsvarar flaggan --memory från Docker. När det gäller request.memory finns det ingen motsvarande flagg för Docker, eftersom Docker inte använder detta fält. Du kanske undrar om det verkligen behövs? Ja, det behövs. Som jag redan har sagt är fältet betydelsefullt för Kubernetes. Baserat på informationen i det beslutar kube-scheduler vilken nod som Pod ska schemaläggas på.
Vad händer om du sätter en otillräcklig minnesbegäran?
Om containern når gränserna för begärt minne sätts Pod i en grupp av Pods som stoppas när det saknas minne på noden.
Vad händer om du ställer in ett för lågt minnesgränsvärde?
Om containern överskrider minnesgränsen kommer den att avslutas på grund av OOM-Killed. Den kommer att startas om om det är möjligt enligt RestartPolicy, där standardvärdet är Alltid.
Vad händer om du inte anger begärt minne?
Kubernetes tar minnesgränsen och sätter den som standardvärde.
Vad kan hända om du inte anger gräns för minne?
Containern har inga begränsningar och kan använda så mycket minne den vill. Om den börjar använda allt tillgängligt minne på noden kommer den att dödas av OOM. Containern kommer sedan att startas om om det är möjligt enligt RestartPolicy.
Vad händer om du inte anger minnesgränser?
Det värsta scenariot: schemaläggaren vet inte hur mycket resurser containern behöver, vilket kan orsaka allvarliga problem på noden. I så fall är det bra att ha standardgränser i namnområdet (inställda av LimitRange). Det finns inga standardgränser — Poden har inga begränsningar och kan använda så mycket minne den vill.
Om det begära minnet är större än vad noden kan erbjuda, kommer Poden inte att schemaläggas. Det är viktigt att komma ihåg att Requests.memory — är inte ett minimivärde. Det beskriver mängden minne som krävs för att containern ska fungera kontinuerligt.
Det rekommenderas vanligtvis att ställa in samma värde för request.memory och limit.memory. På så sätt kommer Kubernetes inte att schemalägga Poden på en nod som har tillräckligt med minne för att köra Poden, men inte tillräckligt för att driva den. Tänk på att när Kubernetes schemalägger Poden, tar det endast hänsyn till requests.memory, och limits.memory inte räknas med.
CPU: begäran och begränsning
containers:
...
resources:
requests:
cpu: 1
limits:
cpu: "1200m"
Med CPU är det lite mer komplicerat. När vi återvänder till bilden av sambandet mellan Kubernetes och Docker, kan vi se att request.cpu motsvarar --cpu-shares, medan limit.cpu motsvarar flaggan cpus i Docker.
CPU:n som Kubernetes begär multipliceras med 1024 — förhållandet av CPU-cykler. Om du vill begära 1 helt kärna, måste du lägga till cpu: 1, som visas ovan.
Att begära en hel kärna (förhållande = 1024) betyder inte att din container kommer att få den. Om din värd-dator bara har en kärna, och du använder mer än en container, måste alla containrar dela på det tillgängliga CPU:t mellan sig. Hur fungerar det? Låt oss ta en titt på bilden.

CPU-förfrågan — system med ett kärna
Låt oss föreställa oss att du har ett värdsystem med ett kärna där containrar körs. Mamma (Kubernetes) har bakat en paj (CPU) och vill dela den mellan sina barn (containrar). Tre barn vill ha en hel paj (andel = 1024), ett barn vill ha hälften av pajen (512). Mamma vill vara rättvis och gör en enkel beräkning.
# Сколько пирогов хотят дети?
# 3 ребенка хотят по целому пирогу и еще один хочет половину пирога
cakesNumberKidsWant = (3 * 1) + (1 * 0.5) = 3.5
# Выражение получается так:
3 (ребенка/контейнера) * 1 (целый пирог/полное ядро) + 1 (ребенок/контейнер) * 0.5 (половина пирога/половина ядра)
# Сколько пирогов испечено?
availableCakesNumber = 1
# Сколько пирога (максимально) дети реально могут получить?
newMaxRequest = 1 / 3.5 =~ 28%Baserat på beräkningen kommer tre barn att få 28 % av en kärna, inte en hel kärna. Det fjärde barnet kommer att få 14 % av en hel kärna, inte hälften. Men allt kommer att vara annorlunda om du har ett flerkärnigt system.

CPU-förfrågan — flerkärnigt (4) system
På bilden ovan kan vi se att tre barn vill ha en hel paj och ett barn vill ha hälften. Eftersom mamma har bakat fyra pajer, kommer varje barn att få så mycket som de vill ha. I ett flerkärnigt system fördelas CPU-resurserna över alla tillgängliga kärnor. Om en container begränsas till mindre än en hel CPU-kärna kan den ändå använda den till 100 %.
De ovanstående beräkningarna är förenklade för att förstå hur CPU fördelas mellan containrar. Naturligtvis finns det andra processer som också använder CPU-resurser utöver själva containrarna. När processer i en container är inaktiva kan andra använda dess resurser. CPU: "200m" motsvarar CPU: 0,2, vilket motsvarar ungefär 20 % av en kärna.
Nu låt oss prata om limit.cpu. CPU som begränsar Kubernetes multipliceras med 100. Resultatet är hur mycket tid en container kan använda var 100 µs (cpu-period).
limit.cpu motsvarar Docker-flaggorna --cpus. Det är en ny kombination av gamla --cpu-period och --cpu-quota. Genom att sätta detta anger vi hur mycket tillgängliga CPU-resurser en container maximalt kan använda innan dämpning börjar:
- cpus — kombinationen
cpu-periodochcpu-quota. cpus = 1.5motsvarar inställningencpu-period = 100000ochcpu-quota = 150000; - cpu-period — period , som standard 100 mikrosekunder;
- cpu-quota — antal mikrosekunder inne i
cpu-period, som containern är begränsad till.
Vad händer om du sätter en otillräcklig CPU-förfrågan?
Om containern behöver mer än vad som är inställt, kommer den att stjäla CPU från andra processer.
Vad händer om du sätter en otillräcklig CPU-gräns?
Eftersom CPU-resursen är reglerbar kommer dämpning att aktiveras.
Vad händer om du inte anger en CPU-förfrågan?
Precis som med minnet, motsvarar begäran gränsvärdet.
Vad händer om man inte anger CPU-gräns?
Containern kommer att använda så mycket CPU som den behöver. Om det finns en standardpolicy för CPU definierad i namnområdet (LimitRange) används denna gräns även för containern.
Vad händer om varken begäran eller CPU-gräns anges?
Precis som med minnet är detta det värsta scenariot. Schemaläggaren vet inte hur mycket resurser din container behöver, vilket kan orsaka allvarliga problem på noden. För att undvika detta bör man ställa in standardgränser för namnområden (LimitRange).
Kom ihåg: om du begär mer CPU än noderna kan tillhandahålla, kommer Podden inte att schemaläggas. Requests.cpu — inte ett minimumvärde, utan ett värde som är tillräckligt för att starta Podden och fungera utan avbrott. Om applikationen inte utför komplicerade beräkningar är det bästa alternativet att ställa in request.cpu <= 1 och köra så många replikat som behövs.
Det optimala antal begärda resurser eller resursgränser
Vi har lärt oss om begränsning av datorkapacitet. Nu är det dags att svara på frågan: "Hur mycket resurser kräver min Pod för att köra applikationen utan problem? Vad är det optimala antalet?".
Tyvärr finns det inga entydiga svar på dessa frågor. Om du inte vet hur din applikation fungerar, hur mycket CPU eller minne den behöver, är det bästa alternativet att ge applikationen mycket minne och CPU och sedan köra prestandatest.
Förutom prestandatester, under en vecka, observera applikationens beteende i övervakningen. Om graferna visar att din applikation använder mindre resurser än du begt, kan du minska mängden begärd CPU eller minne.
Som exempel, kika på denna . Den visar skillnaden mellan begärda resurser eller resursgränser och nuvarande resursanvändning.
Slutsats
Begärningar och resursbegränsningar hjälper till att hålla Kubernetes-klustret i drift. Rätt konfiguration av gränser minimerar kostnaderna och håller applikationerna ständigt i drift.
Sammanfattningsvis är det viktigt att tänka på flera saker:
- De begärda resurserna är en konfiguration som beaktas vid start (när Kubernetes planerar placeringen av applikationen). Å sin sida är resursbegränsningen viktig under drift — när applikationen redan körs på en nod.
- Jämfört med minne är CPU en reglerbar resurs. Vid brist på CPU kommer din Pod inte att avslutas, utan det kommer att aktiveras en throttling-mekanism.
- Begärda resurser och resursgränser är inte minimala och maximala värden! Genom att definiera begärda resurser säkerställer du att applikationen fungerar utan problem.
- En bra praxis är att ställa in minnesbegäran lika med minnesgränsen.
- Det är bra att ställa in begärd
CPU <=1, om applikationen inte utför komplexa beräkningar. - Om du begär mer resurser än vad som finns på noden kommer Pod aldrig att schemaläggas på denna nod.
- För att bestämma rätt mängd begärda resurser/gränser, använd belastningstestning och övervakning.
Jag hoppas att denna artikel hjälper dig att förstå huvudkonceptet för resursbegränsningar. Och att du kan tillämpa dessa kunskaper i ditt arbete.
Lycka till!
Vad mer att läsa:
- .
- .
- .
Källa: habr.com
