Nio tips för att öka Kubernetes-prestanda

Nio tips för att öka Kubernetes-prestanda

Hej alla! Jag heter Oleg Sidorenkov och jag arbetar som chef för infrastrukturteamet pÄ företaget DomClick. Vi har drivit "Kubik" i produktion i över tre Är och har under den tiden haft mÄnga intressanta upplevelser med den. Idag kommer jag berÀtta för er hur man med rÀtt tillvÀgagÄngssÀtt kan pressa Ànnu mer prestanda ur "vanillja" Kubernetes för din kluster. Klara, fÀrdiga, gÄ!

Ni vet alla att Kubernetes Àr ett skalbart system med öppen kÀllkod för orkestrering av containrar; eller 5 binÀrer som skapar magi genom att hantera livscykeln av era mikrotjÀnster i servermiljö. Dessutom Àr det ett ganska flexibelt verktyg som kan sÀttas ihop som en Lego-kloss för maximal anpassning till olika uppgifter.

Och allt verkar bra: slÀng servrar i klustret som ved i en kamin och ha inga bekymmer. Men om du bryr dig om miljön, börjar du tÀnka: "Hur kan jag hÄlla elden i kaminen och samtidigt vÄrda skogen?". Med andra ord, hur kan man hitta sÀtt att förbÀttra infrastrukturen och sÀnka kostnaderna.

1. HÄll koll pÄ resurserna för team och applikationer

Nio tips för att öka Kubernetes-prestanda

En av de mest grundlÀggande men effektiva metoderna Àr att införa requests/limits. Dela upp applikationerna i namespaces, och namespaces efter utvecklingsteam. Ange resursvÀrden för CPU-tid, minne och ephemeral lagring för applikationen innan deployment.

resources:
   requests:
     memory: 2Gi
     cpu: 250m
   limits:
     memory: 4Gi
     cpu: 500m

Genom erfarenhet har vi kommit fram till att man inte bör öka requests mer Àn dubbelt sÄ mycket som limits. Klusterstorleken berÀknas utifrÄn requests, och om du ger applikationerna en skillnad i resurser, till exempel 5-10 gÄnger, sÄ förestÀll dig vad som kommer hÀnda med din nod nÀr den fylls med pods och plötsligt fÄr belastning. Inget bra. Minst throttling, och som vÀrst, kan du sÀga hejdÄ till workern och fÄ en cyklisk belastning pÄ de andra noderna efter att pods börjar flytta.

Dessutom, med hjÀlp av limitranges kan du vid starten ange resursvÀrden för containern - minimala, maximala och standard:

➜  ~ kubectl describe limitranges --namespace ops
Name:       limit-range
Namespace:  ops
Type        Resource           Min   Max   Default Request  Default Limit  Max Limit/Request Ratio
----        --------           ---   ---   ---------------  -------------  -----------------------
Container   cpu                50m   10    100m             100m           2
Container   ephemeral-storage  12Mi  8Gi   128Mi            4Gi            -
Container   memory             64Mi  40Gi  128Mi            128Mi          2

Kom ihÄg att begrÀnsa resurserna i namnutrymmet, sÄ att inget team kan ta alla resurser i klustret:

➜  ~ kubectl describe resourcequotas --namespace ops
Name:                   resource-quota
Namespace:              ops
Resource                Used          Hard
--------                ----          ----
limits.cpu              77250m        80
limits.memory           124814367488  150Gi
pods                    31            45
requests.cpu            53850m        80
requests.memory         75613234944   150Gi
services                26            50
services.loadbalancers  0             0
services.nodeports      0             0

Som framgÄr av beskrivningen resourcequotas, om teamet ops vill distribuera pods som kommer att konsumera ytterligare 10 cpu, sÄ kommer schemalÀggaren inte att tillÄta detta och ge ett felmeddelande:

Error creating: pods "nginx-proxy-9967d8d78-nh4fs" is forbidden: exceeded quota: resource-quota, requested: limits.cpu=5,requests.cpu=5, used: limits.cpu=77250m,requests.cpu=53850m, limited: limits.cpu=10,requests.cpu=10

För att lösa en sÄdan uppgift kan man skriva ett verktyg, till exempel som det hÀr, som kan lagra och commita tillstÄndet för resurserna i teamen.

2. VĂ€lj ett optimalt filsystem

Nio tips för att öka Kubernetes-prestanda

HÀr skulle jag vilja ta upp Àmnet om persistenta volymer och lagringssystemet pÄ worker-noder i Kubernetes. Jag hoppas att ingen anvÀnder "Kuben" pÄ HDD i produktion, men ibland Àr Àven en vanlig SSD för lite. Vi har stött pÄ sÄdana problem dÀr loggarna dödade disken pÄ grund av in- och utdataoperationer, och hÀr finns det inte sÄ mÄnga lösningar:

  • AnvĂ€nd högpresterande SSD eller övergĂ„ till NVMe (om du sjĂ€lv ansvarar för din hĂ„rdvara).

  • Minska loggnivĂ„n.

  • Gör en "smart" belastningsbalansering av pods som sliter pĂ„ disken (podAntiAffinity).

SkÀrmen ovan visar vad som hÀnder med nginx-ingress-controller och disken nÀr loggningen av access_logs Àr aktiverad (~12 000 loggar/sek.). Detta tillstÄnd kan sjÀlvklart leda till försÀmring av alla applikationer pÄ denna nod.

NĂ€r det gĂ€ller PV har jag tyvĂ€rr inte testat alla typer BestĂ€ndiga volymer. AnvĂ€nd det bĂ€sta alternativet som passar just dig. Historiskt sett har en liten del av vĂ„ra tjĂ€nster behövt RWX-volymer, och för lĂ€nge sedan började vi anvĂ€nda NFS-lagring för det. Billigt och
 rĂ€cker till. SjĂ€lvklart har vi fĂ„tt mycket skit med det — var sĂ„ god, men vi har lĂ€rt oss att finjustera det, och vi har inte lĂ€ngre huvudvĂ€rk. Om möjligt, övergĂ„ till S3 objektlagring.

3. Samla optimerade bilder

Nio tips för att öka Kubernetes-prestanda

Det Àr bÀst att anvÀnda bilder som Àr optimerade för containrar, sÄ att Kubernetes kan hÀmta dem snabbare och köra dem effektivare. 

Optimering innebÀr att bilder:

  • innehĂ„ller endast en applikation eller utför endast en funktion;

  • Ă€r smĂ„ i storlek, eftersom stora bilder sĂ€mre överförs över nĂ€tverket;

  • har slutpunkter för hĂ€lsokontroll och beredskap, som Kubernetes kan anvĂ€nda för att vidta Ă„tgĂ€rder vid driftsstopp;

  • anvĂ€nder containervĂ€nliga operativsystem (som Alpine eller CoreOS), som Ă€r mer motstĂ„ndskraftiga mot konfigurationsfel;

  • anvĂ€nder flertrinsbyggen sĂ„ att du endast kan distribuera kompilerade applikationer, inte tillhörande kĂ€llkoder.

Det finns mÄnga verktyg och tjÀnster som kan kontrollera och optimera bilder i realtid. Det Àr viktigt att alltid hÄlla dem uppdaterade och verifierade för sÀkerhet. I slutÀndan fÄr du:

  1. Minskad nÀtverksbelastning pÄ hela klustret.

  2. Förkortad starttid för containrar.

  3. Mindre storlek pÄ hela din Docker-registry.

4. AnvÀnd DNS-cache

Nio tips för att öka Kubernetes-prestanda

NÀr vi pratar om hög belastning Àr det ganska plÄgsamt att leva utan finjustering av klustrets DNS-system. För lÀnge sedan stödde Kubernetes-utvecklarna sin egen lösning kube-dns. Den implementerades Àven hos oss, men mjukvaran fick ingen finjustering och visade inte den prestanda vi behövde, Àven om uppgiften verkade enkel. Sedan kom coredns, som vi övergick till och som fungerade utmÀrkt, och blev senare standard DNS-tjÀnsten i K8s. Vid en tidpunkt nÄdde vi 40 000 rps till DNS-systemet, och den lösningen blev ocksÄ otillrÀcklig. Men av en lycklig slump kom Nodelocaldns, Àven kÀnd som node local cache, Àven kallad NodeLocal DNSCache.

Varför anvÀnder vi detta? Det finns en bugg i Linux-kÀrnan som vid flera förfrÄgningar genom conntrack NAT över UDP leder till ett race condition för skrivning till conntrack-tabellerna, och en del trafik genom NAT gÄr förlorad (varje besök genom TjÀnsten Àr NAT). Nodelocaldns löser detta problem genom att eliminera NAT och uppgradera anslutningen till TCP för upstream DNS, samt lokal cache för DNS-förfrÄgningar mot upstream (inklusive en kort negativ cache pÄ 5 sekunder).

5. Skala poddar horisontellt och vertikalt automatiskt

Nio tips för att öka Kubernetes-prestanda

Kan du med sÀkerhet sÀga att alla dina mikrotjÀnster Àr redo för en tvÄ- till trefaldig ökning av belastningen? Hur ska resurser fördelas till dina applikationer? Att ha ett par poddar igÄng över arbetsbelastningen kan visa sig vara överflödigt, medan att köra alldeles för nÀra grÀnsen riskerar att orsaka stillestÄnd vid en plötslig ökning av trafik till tjÀnsten. Den gyllene medelvÀgen nÄs med hjÀlp av förmÄgan att skala sÄdana tjÀnster som Horizontal Pod Autoscaler och Vertical Pod Autoscaler.

VPA möjliggör att automatiskt justera requests/limits för dina containrar i en pod baserat pÄ faktisk anvÀndning. Hur kan det vara anvÀndbart? Om du har poddar som av nÄgon anledning inte kan skalas horisontellt (vilket inte Àr helt tillförlitligt), kan du prova att lÄta VPA justera dess resurser. Dess funktion Àr ett rekommendationssystem baserat pÄ historiska och aktuella data frÄn metric-server, sÄ om du inte vill Àndra requests/limits automatiskt, kan du helt enkelt övervaka de rekommenderade resurserna för dina containrar och optimera instÀllningarna för att spara processor- och minnesanvÀndning i klustret.

Nio tips för att öka Kubernetes-prestandaBild tagen frÄn https://levelup.gitconnected.com/kubernetes-autoscaling-101-cluster-autoscaler-horizontal-pod-autoscaler-and-vertical-pod-2a441d9ad231

SchemalÀggaren i Kubernetes baseras alltid pÄ requests. Vilket vÀrde du Àn anger dÀr, kommer schemalÀggaren att söka efter en lÀmplig nod baserat pÄ det. VÀrdena för limits behövs av kubelet för att förstÄ nÀr den ska begrÀnsa eller döda en pod. Och eftersom den enda viktiga parametern Àr vÀrdet för requests, kommer VPA att arbeta med detta. Varje gÄng du stÀller in vertikal skalning av applikationen definierar du vilka requests som ska gÀlla. Men vad hÀnder dÄ med limits? Detta parameter kommer ocksÄ att skalas proportionellt.

Till exempel, hÀr Àr vanliga instÀllningar för en pod:

resurser:
   begÀrningar:
     minne: 250Mi
     cpu: 200m
   grÀnser:
     minne: 500Mi
     cpu: 350m

Rekommendationssystemet bestÀmmer att din applikation behöver 300m CPU och 500Mi för att fungera normalt. Du fÄr följande instÀllningar:

resurser:
   begÀrningar:
     minne: 500Mi
     cpu: 300m
   grÀnser:
     minne: 1000Mi
     cpu: 525m

Som nÀmnts ovan Àr detta proportionell skalning baserat pÄ förhÄllandet mellan begÀrningar/grÀnser i manifestet:

  • CPU: 200m → 300m: förhĂ„llande 1:1.75;

  • Minne: 250Mi → 500Mi: förhĂ„llande 1:2.

NÀr det gÀller HPA, Àr mekanismen hÀr tydligare. TröskelvÀrden för metrik, som CPU och minne, stÀlls in, och om det genomsnittliga vÀrdet för alla repliker överstiger tröskeln, skalas applikationen upp med +1 podd tills vÀrdet sjunker under tröskeln eller det maximala antalet repliker uppnÄs.

Nio tips för att öka Kubernetes-prestandaBild tagen frÄn https://levelup.gitconnected.com/kubernetes-autoscaling-101-cluster-autoscaler-horizontal-pod-autoscaler-and-vertical-pod-2a441d9ad231

Utöver vanliga metrik som CPU och minne kan du stÀlla in trösklar för dina egna anpassade metrik frÄn Prometheus och arbeta med dem om du anser att det Àr den mest precisa definieringen av nÀr du bör skala din applikation. NÀr applikationen stabiliseras under den angivna grÀnsen för metrik, kommer HPA att börja skala ner poddar till det minimala antalet repliker eller tills lasten uppfyller den angivna tröskeln.

6. Glöm inte Node Affinity och Pod Affinity

Nio tips för att öka Kubernetes-prestanda

Inte alla noder arbetar med samma hÄrdvara, och inte alla poddar behöver köra applikationer som krÀver intensiva berÀkningar. Kubernetes tillÄter specialisering av noder och poddar med hjÀlp av Node Affinity och Pod Affinity.

Om du har noder som Àr lÀmpade för berÀkningstunga operationer, Àr det bÀst att knyta applikationerna till dessa noder för maximal effektivitet. AnvÀnd nodeSelector med nodens mÀrkning.

Anta att du har tvÄ noder: en med CPUType=HIGHFREQ och mÄnga snabba kÀrnor, och den andra med MemoryType=HIGHMEMORY mycket minne och högre prestanda. Det enklaste sÀttet Àr att tilldela distributionen av podden till noden HIGHFREQ, genom att lÀgga till denna selektor i spec :



nodeSelector:
	CPUType: HIGHFREQ

Ett mer kostsamt och specifikt sÀtt att göra detta Àr att anvÀnda nodeAffinity i fÀltet affinity i sektionen spec. Det finns tvÄ alternativ:

  • requiredDuringSchedulingIgnoredDuringExecution: strikt konfiguration (planeraren kommer att distribuera poddar endast pĂ„ specifika noder (och ingen annanstans));

  • preferredDuringSchedulingIgnoredDuringExecution: mjuk konfiguration (planeraren kommer att försöka distribuera pĂ„ specifika noder, och om det misslyckas kommer den att försöka distribuera pĂ„ den nĂ€sta tillgĂ€ngliga noden).

Du kan ange en specifik syntax för nodernas etikettkontroll, till exempel, In, NotIn, Exists, DoesNotExist, Gt eller Lt. Men kom ihÄg att komplexa metoder i lÄnga listor med etiketter kan fördröja beslutsfattandet i kritiska situationer. Med andra ord, gör det inte mer komplicerat.

Som nÀmnts ovan tillÄter Kubernetes att ange bindning av nuvarande pods. Det vill sÀga att du kan göra sÄ att vissa pods arbetar tillsammans med andra pods i samma tillgÀnglighetszon (relevant för molntjÀnster) eller noder.

I podAffinity fÀlt affinity i sektionen spec Àr desamma som vid nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution och preferredDuringSchedulingIgnoredDuringExecution. Den enda skillnaden Àr att matchExpressions binder pods till noder dÀr en pod med sÄdan etikett redan körs.

Dessutom erbjuder Kubernetes ett fÀlt podAntiAffinity, vilket Ä sin sida inte binder en pod till en nod med specifika pods.

NÀr det gÀller uttryck nodeAffinity kan samma rÄd ges: försök att hÄlla reglerna enkla och logiska, försök inte överbelasta pod-dokumentationen med en komplicerad uppsÀttning regler. Det Àr mycket lÀtt att skapa en regel som inte kommer att uppfylla klustrets villkor, vilket skapar onödig belastning pÄ planeraren och minskar den totala prestandan.

7. Taints & Tolerations

Det finns ocksÄ ett annat sÀtt att hantera planeraren. Om du har ett stort kluster med hundratals noder och tusentals mikrotjÀnster, Àr det mycket svÄrt att förhindra vissa pods frÄn att placeras pÄ vissa noder.

Detta underlĂ€ttas av mekanismen taints — förbud regler. Till exempel kan man i vissa scenarier förbjuda vissa noder att köra pods pĂ„ sig. För att tillĂ€mpa en taint pĂ„ en viss nod bör du anvĂ€nda alternativet taint i kubectl. Ange nyckel och vĂ€rde, och sedan taint som NoSchedule eller NoExecute:

$ kubectl taint nodes node10 node-role.kubernetes.io/ingress=true:NoSchedule

Det Àr ocksÄ vÀrt att notera att taint-mekanismen stöder tre grundlÀggande effekter: NoSchedule, NoExecute och PreferNoSchedule.

  • NoSchedule betyder att sĂ„ lĂ€nge det inte finns nĂ„gon motsvarande post i pod-specifikationen tolerations, kan den inte distribueras pĂ„ noden (i detta exempel node10).

  • PreferNoSchedule — en förenklad version NoSchedule. I detta fall kommer planeraren att försöka undvika att distribuera pods utan motsvarande post tolerations till noden, men detta Ă€r ingen strikt begrĂ€nsning. Om det inte finns nĂ„gra resurser i klustret, kommer pods att börja distribueras pĂ„ denna nod.

  • NoExecute — denna effekt utlöser omedelbar evakuering av pods som inte har nĂ„gon motsvarande post tolerations.

Intressant nog kan sÄdant beteende Ängras med hjÀlp av toleranser. Detta Àr anvÀndbart nÀr det finns en "förbjuden" nod och du behöver placera enbart infrastrukturtjÀnster pÄ den. Hur gör man detta? TillÄt endast de pods för vilka det finns en lÀmplig tolerans.

SÄ hÀr kommer pod-specifikationen att se ut:

spec:
   tolerations:
     - key: "node-role.kubernetes.io\/ingress"
        operator: "Equal"
        value: "true"
        effect: "NoSchedule"

Detta betyder inte att vid nÀsta redeployment kommer podden att gÄ pÄ just denna nod, det Àr inte mekanismen för Node Affinity och nodeSelector. Men genom att kombinera flera funktioner kan du uppnÄ en mycket flexibel konfiguration av schemalÀggaren.

8. StÀll in prioritet för distribution av pods

Det faktum att du har konfigurerat bindning av pods till noder betyder inte att alla pods ska behandlas med samma prioritet. Till exempel kan du vilja distribuera vissa pods tidigare Àn andra.

Kubernetes erbjuder olika sÀtt att konfigurera prioriteringar för pods (Pod Priority and Preemption). Konfigurationen bestÄr av flera delar: objektet PriorityClass och beskrivningen av fÀltet priorityClassName i pod-specifikationen. LÄt oss titta pÄ ett exempel:

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 99999
globalDefault: false
description: "Denna prioritetsklass bör endast anvÀndas för mycket viktiga pods"

Vi skapar PriorityClass, ger den ett namn, en beskrivning och ett vÀrde. Ju högre value, desto högre prioritet. VÀrdet kan vara vilket 32-bit heltal som helst, mindre eller lika med 1 000 000 000. Högre vÀrden Àr reserverade för kritiskt viktiga system-pods som vanligtvis inte kan bli avvisade. Avvisning kommer att ske endast om den högprioriterade podden inte har nÄgonstans att distribuera, dÄ kommer vissa pods frÄn en viss nod att evakueras. Om detta mekanism Àr för strÀng kan du lÀgga till alternativet preemptionPolicy: Never, och dÄ blir det ingen avvisning, podden kommer att stÄ först i kön och vÀnta pÄ att schemalÀggaren hittar lediga resurser för den.

DÀrefter skapar vi en pod dÀr vi anger namnet priorityClassName:

apiVersion: v1
kind: Pod
metadata:
  name: static-web
  labels:
    role: myrole
 spec:
  containers:
    - name: web
      image: nginx
      ports:
        - name: web
          containerPort: 80
          protocol: TCP
  priorityClassName: high-priority
          

Du kan skapa hur mÄnga prioritetsklasser som helst, men det rekommenderas att man inte överdriver (lÄt oss sÀga, begrÀnsa sig till lÄg, medelhög och hög prioritet).

PÄ sÄ sÀtt kan du, om det behövs, öka effektiviteten i distribueringsassistenter för kritiska tjÀnster som nginx-ingress-controller, coredns osv.

9. Optimera ETCD-klustret

Nio tips för att öka Kubernetes-prestanda

ETCD kan beskrivas som hjÀrnan i hela klustret. Det Àr mycket viktigt att hÄlla denna databas pÄ hög nivÄ, eftersom hastigheten pÄ operationerna i "Kub" beror pÄ den. Ett ganska standard och samtidigt bra alternativ Àr att hÄlla ETCD-klustret pÄ master-noder för att fÄ minimal fördröjning till kube-apiserver. Om det inte Àr möjligt, placera ETCD sÄ nÀra som möjligt, med bra bandbredd mellan deltagarna. TÀnk ocksÄ pÄ hur mÄnga noder av ETCD som kan falla bort utan att skada klustret.

Nio tips för att öka Kubernetes-prestanda

TÀnk pÄ att en överdriven ökning av antalet deltagare i klustret kan förbÀttra tillgÀngligheten pÄ bekostnad av prestanda; allt bör vara i balans.

NÀr det gÀller att konfigurera tjÀnsten finns det inte sÄ mÄnga rekommendationer:

  1. Ha bra hÄrdvara, baserat pÄ klustrets storlek (du kan lÀsa mer ). Ett typiskt exempel pÄ anvÀndning:).

  2. Finjustera nÄgra parametrar, om du har spridit klustret över ett par datacenter eller om ditt nÀtverk och dina diskar lÀmnar mycket att önska (du kan lÀsa mer ). Ett typiskt exempel pÄ anvÀndning:).

Slutsats

I den hÀr artikeln beskrivs punkterna som vÄrt team försöker följa. Det hÀr Àr inte en steg-för-steg-beskrivning av ÄtgÀrder, utan alternativ som kan vara anvÀndbara för att optimera kostnaderna för klustret. Det Àr klart att varje kluster Àr unikt och instÀllningarna kan variera mycket, sÄ det skulle vara intressant att fÄ din feedback: hur övervakar du ditt Kubernetes-kluster och hur förbÀttrar du dess prestanda? Dela med dig av din erfarenhet i kommentarerna, det skulle vara intressant att höra.

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster