Üheksa Kubernetese jõudlusnõuannet

Üheksa Kubernetese jõudlusnõuannet

Tere kõigile! Minu nimi on Oleg Sidorenkov, töötan DomClickis infrastruktuuri meeskonna juhina. Oleme Cube’i müügis kasutanud üle kolme aasta ning selle aja jooksul oleme kogenud sellega palju erinevaid huvitavaid hetki. Täna räägin teile, kuidas saate õige lähenemisviisiga vanilje Kubernetesest oma klastri jaoks veelgi rohkem jõudlust välja pigistada. Tähelepanu, valmis olla, läks!

Te kõik teate väga hästi, et Kubernetes on skaleeritav avatud lähtekoodiga süsteem konteinerite orkestreerimiseks; noh, või 5 binaarfaili, mis teevad võlu, hallates teie mikroteenuste elutsüklit serverikeskkonnas. Lisaks on see üsna paindlik tööriist, mida saab kokku panna nagu Lego konstruktorit, et erinevate ülesannete jaoks maksimaalselt kohandada.

Ja tundub, et kõik on korras: viska serverid kobarasse, nagu küttepuud kaminasse, ega tunne leina. Aga kui olete keskkonna eest, siis mõtlete: "Kuidas ma saan hoida tuld ahjus ja kahetseda metsa?". Ehk kuidas leida võimalusi infrastruktuuri parandamiseks ja kulude vähendamiseks.

1. Jälgige meeskonna- ja rakendusressursse

Üheksa Kubernetese jõudlusnõuannet

Üks banaalsemaid, kuid tõhusamaid meetodeid on taotluste/limiitide kehtestamine. Eraldage rakendused nimeruumide ja nimeruumid arendusmeeskondade järgi. Määrake rakendus enne protsessori aja, mälu ja lühiajalise salvestusruumi tarbimise väärtuste juurutamist.

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

Kogemuste põhjal jõudsime järeldusele: limiitide taotlusi ei tasu üle kahe korra paisutada. Klastri maht arvutatakse taotluste põhjal ja kui määrate rakenduste ressursside erinevuse näiteks 5-10 korda, siis kujutage ette, mis juhtub teie sõlmega, kui see täitub kaunadega ja saab ootamatult koormuse . Ei midagi head. Minimaalselt jätke drossel ja maksimaalselt töötajaga hüvasti ja koormake ülejäänud sõlmed pärast kaunade liikuma hakkamist tsükliliselt.

Lisaks abiga limitranges Saate alguses määrata konteineri ressursiväärtused - miinimum, maksimaalne ja vaikeväärtus:

➜  ~ 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

Ärge unustage nimeruumi ressursse piirata, et üks käsk ei saaks võtta kõiki klastri ressursse:

➜  ~ 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

Nagu kirjeldusest näha resourcequotas, kui käsk ops soovib juurutada mooduleid, mis tarbivad veel 10 protsessorit, siis ajakava ei luba seda teha ja annab välja veateate:

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

Sarnase probleemi lahendamiseks võite kirjutada tööriista, näiteks kui see, mis suudab salvestada ja sisestada käsuseisundi ressursse.

2. Valige parim failide salvestusruum

Üheksa Kubernetese jõudlusnõuannet

Siinkohal tahaksin puudutada püsivate mahtude ja Kubernetese töösõlmede ketta alamsüsteemi teemat. Loodan, et keegi ei kasuta tootmises HDD-l olevat "Cube'i", kuid mõnikord ei piisa juba tavalisest SSD-st. Me seisime silmitsi sellise probleemiga, et logid hävitasid ketta I / O-toimingutega ja siin pole palju lahendusi:

  • Kasutage suure jõudlusega SSD-sid või lülituge NVMe-le (kui haldate oma riistvara ise).

  • Langetage metsaraie taset.

  • Tehke ketast vägistavate kaunade "nutikas" tasakaalustamine (podAntiAffinity).

Ülaltoodud ekraanipilt näitab, mis juhtub kettaga nginx-ingress-controlleri all, kui access_logs on lubatud (~12 XNUMX logi/s). Selline olek võib loomulikult kaasa tuua selle sõlme kõigi rakenduste halvenemise.

Mis puutub PV-sse, siis paraku pole ma kõike proovinud. liigid Püsivad mahud. Kasutage teile sobivaimat võimalust. Meie riigis on ajalooliselt juhtunud, et väike osa teenustest vajab RWX-mahtusid ja juba ammu hakati selleks ülesandeks kasutama NFS-mälu. Odav ja ... piisavalt. Muidugi sõime temaga jama - ole terve, aga õppisime teda häälestama ja pea ei valuta enam. Ja võimalusel lülitage S3 objektisalvestusele.

3. Optimeeritud kujutiste loomine

Üheksa Kubernetese jõudlusnõuannet

Parim on kasutada konteineritele optimeeritud pilte, et Kubernetes saaks neid kiiremini tuua ja tõhusamalt täita. 

Optimeerimine tähendab, et pildid:

  • sisaldavad ainult ühte rakendust või täidavad ainult ühte funktsiooni;

  • väike suurus, kuna suuri pilte edastatakse võrgu kaudu halvemini;

  • omama tervise- ja valmisolekukontrolli lõpp-punkte, mille kaudu saab Kubernetes seisaku korral midagi ette võtta;

  • kasutage konteinerisõbralikke operatsioonisüsteeme (nt Alpine või CoreOS), mis on konfiguratsioonivigade suhtes vastupidavamad;

  • kasutage mitmeastmelisi järge, et saaksite juurutada ainult kompileeritud rakendusi, mitte kaasasolevaid allikaid.

On palju tööriistu ja teenuseid, mis võimaldavad teil pilte käigupealt kontrollida ja optimeerida. Oluline on hoida need alati ajakohasena ja ohutuna. Selle tulemusena saate:

  1. Vähendatud võrgukoormus kogu klastrile.

  2. Vähenenud konteineri käivitusaeg.

  3. Kogu teie Dockeri registri väiksem suurus.

4. Kasutage DNS-i vahemälu

Üheksa Kubernetese jõudlusnõuannet

Kui rääkida suurtest koormustest, siis ilma klastri DNS-süsteemi häälestamata on elu päris närune. Kunagi toetasid Kubernetese arendajad nende kube-dns-i lahendust. Seda rakendati ka meie riigis, kuid see tarkvara ei häälestunud eriti ega andnud nõutavat jõudlust, kuigi tundub, et ülesanne on lihtne. Siis ilmus coredns, millele me üle läksime ja leina ei teadnud, hiljem sai sellest K8s vaikimisi DNS-teenus. Mingil hetkel kasvasime DNS-süsteemiga kuni 40 tuhande rps-ni ja ka sellest lahendusest ei piisanud. Kuid õnneliku juhuse läbi tuli välja Nodelocaldns ehk sõlme kohalik vahemälu, aka NodeLocal DNS-vahemälu.

Miks me seda kasutame? Linuxi tuumas on viga, mis mitme juurdepääsu korral conntrack NAT-i kaudu UDP kaudu põhjustab conntrack-tabelitesse kirjutamise võistlustingimuse ja osa NAT-i kaudu toimuvast liiklusest läheb kaotsi (iga teenuse reis on NAT). Nodelocaldns lahendab selle probleemi, vabanedes NAT-ist ja uuendades ülesvoolu DNS-i TCP-ühendusele, samuti salvestab ülesvoolu DNS-päringud kohapeal vahemällu (sealhulgas lühike 5-sekundiline negatiivne vahemälu).

5. Skaalake kaunad horisontaalselt ja vertikaalselt automaatselt

Üheksa Kubernetese jõudlusnõuannet

Kas võite kindlalt väita, et kõik teie mikroteenused on valmis kahe- kuni kolmekordseks koormuse kasvuks? Kuidas oma rakendustele ressursse õigesti eraldada? Paari kaubiku töös hoidmine üle töökoormuse võib olla üleliigne ja nende vastastikku hoidmine ohustab seisakuid teenuse liikluse järsu suurenemise tõttu. Kuldne keskmine aitab saavutada korrutamise loitsu sellised teenused nagu Horisontaalne Pod Autoscaler и Vertikaalne Pod Autoscaler.

VPA võimaldab teil automaatselt tõsta oma konteinerite taotlusi/piiranguid kaustas tegeliku kasutuse alusel. Kuidas see kasulik võib olla? Kui teil on Pod, mida ei saa mingil põhjusel horisontaalselt skaleerida (mis ei ole täiesti usaldusväärne), võite proovida usaldada VPA-le oma ressursside muutmist. Selle funktsioon on soovitussüsteem, mis põhineb meetrikaserveri ajaloolistel ja praegustel andmetel, nii et kui te ei soovi taotlusi/piiranguid automaatselt muuta, saate lihtsalt jälgida oma konteinerite jaoks soovitatud ressursse ja optimeerida seadeid, et säästa protsessorit ja mälu. klastris.

Üheksa Kubernetese jõudlusnõuannetPilt on võetud saidilt https://levelup.gitconnected.com/kubernetes-autoscaling-101-cluster-autoscaler-horizontal-pod-autoscaler-and-vertical-pod-2a441d9ad231

Kubernetese ajakava põhineb alati päringutel. Ükskõik, millise väärtuse sinna panete, otsib planeerija selle põhjal sobiva sõlme. Limiitväärtust vajab kublet, et teada saada, millal kasti gaasistada või tappa. Ja kuna ainus oluline parameeter on päringu väärtus, töötab VPA sellega. Iga kord, kui skaleerite oma rakendust vertikaalselt, määrate kindlaks, millised taotlused peaksid olema. Ja mis saab siis piirangutest? Seda parameetrit muudetakse ka proportsionaalselt.

Näiteks siin on tüüpilised podi seaded:

resources:
   requests:
     memory: 250Mi
     cpu: 200m
   limits:
     memory: 500Mi
     cpu: 350m

Soovitusmootor teeb kindlaks, et teie rakendus vajab korralikult töötamiseks 300 m protsessorit ja 500 mi. Saate järgmised seaded:

resources:
   requests:
     memory: 500Mi
     cpu: 300m
   limits:
     memory: 1000Mi
     cpu: 525m

Nagu ülalpool mainitud, on see proportsionaalne skaleerimine, mis põhineb manifestis olevate taotluste ja piirangute suhtel:

  • CPU: 200m → 300m: suhe 1:1.75;

  • Mälu: 250Mi → 500Mi: 1:2 suhe.

suhtes HPA, siis on töömehhanism läbipaistvam. Mõõdikutele (nt protsessor ja mälu) määratakse läved ja kui kõigi koopiate keskmine ületab läve, siis skaleerib rakendus +1 ühiku võrra, kuni väärtus langeb alla läve või kuni saavutatakse maksimaalne koopiate arv.

Üheksa Kubernetese jõudlusnõuannetPilt on võetud saidilt https://levelup.gitconnected.com/kubernetes-autoscaling-101-cluster-autoscaler-horizontal-pod-autoscaler-and-vertical-pod-2a441d9ad231

Lisaks tavalistele mõõdikutele, nagu protsessor ja mälu, saate määrata oma kohandatud Prometheuse mõõdikutele läved ja töötada nendega, kui tunnete, et see on kõige täpsem viis rakenduse skaleerimise aja määramiseks. Kui rakendus stabiliseerub alla kindlaksmääratud meetrilise läve, hakkab HPA vähendama kaustasid minimaalse koopiate arvuni või seni, kuni koormus vastab määratud läviväärtusele.

6. Ärge unustage sõlmede ja kaustade afiinsust

Üheksa Kubernetese jõudlusnõuannet

Kõik sõlmed ei tööta samal riistvaral ja kõik sõlmed ei pea töötama arvutusmahukaid rakendusi. Kubernetes võimaldab teil määrata sõlmede ja kaunade spetsialiseerumise Sõlme afiinsus и Podi afiinsus.

Kui teil on arvutusmahukateks toiminguteks sobivad sõlmed, on maksimaalse efektiivsuse saavutamiseks parem siduda rakendused vastavate sõlmedega. Selleks kasutage nodeSelector sõlmesildiga.

Oletame, et teil on kaks sõlme: üks koos CPUType=HIGHFREQ ja suur hulk kiireid südamikke, teine ​​koos MemoryType=HIGHMEMORY rohkem mälu ja kiirem jõudlus. Lihtsaim viis on määrata sõlme juurutus HIGHFREQjaotisesse lisades spec selline valija:

…
nodeSelector:
	CPUType: HIGHFREQ

Kulukam ja spetsiifilisem viis selleks on kasutada nodeAffinity valdkonnas affinity jaotises spec. On kaks võimalust.

  • requiredDuringSchedulingIgnoredDuringExecution: kõva seadistus (planeerija juurutab kaustasid ainult teatud sõlmedesse (ja mitte kuhugi mujale));

  • preferredDuringSchedulingIgnoredDuringExecution: pehme säte (planeerija proovib juurutada konkreetsetesse sõlmedesse ja kui see ebaõnnestub, proovib see juurutada järgmisele saadaolevale sõlmele).

Saate määrata konkreetse süntaksi sõlme siltide haldamiseks, näiteks In, NotIn, Exists, DoesNotExist, Gt või Lt. Pidage siiski meeles, et keerukad meetodid pikkades siltide loendites aeglustavad kriitilistes olukordades otsuste tegemist. Teisisõnu, ärge tehke liiga keeruliseks.

Nagu eespool mainitud, võimaldab Kubernetes määrata praeguste kaunade sidumise. See tähendab, et saate panna teatud kaustad töötama koos teiste samas kättesaadavustsoonis (pilvede puhul asjakohane) või sõlmedes olevate kaustadega.

В podAffinity marginaalid affinity jaotises spec saadaval on samad väljad, mis puhul nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution и preferredDuringSchedulingIgnoredDuringExecution. Ainus erinevus seisneb selles matchExpressions seob kaustad sõlmega, mis juba käitab selle sildiga kausta.

Rohkem Kubernetes pakub välja podAntiAffinity, mis seevastu ei seo kauna konkreetsete kaunadega sõlmega.

Väljendite kohta nodeAffinity Sama nõu võib anda: püüdke hoida reeglid lihtsad ja loogilised, ärge proovige podi spetsifikatsiooni keerulise reeglistikuga üle koormata. Väga lihtne on luua reeglit, mis ei vasta klastri tingimustele, koormates planeerijat ja halvendades üldist jõudlust.

7. Rikkumised ja talumised

Planeerija haldamiseks on veel üks viis. Kui teil on suur klaster sadade sõlmede ja tuhandete mikroteenustega, on väga raske takistada teatud sõlmede hostimist teatud sõlmedes.

Selle vastu aitab määrdumismehhanism – reeglite keelamine. Näiteks saate teatud stsenaariumide korral takistada teatud sõlmede kaustade käitamist. Konkreetsele sõlmele mustuse rakendamiseks kasutage valikut taint in kubectl. Täpsustage võti ja väärtus ning seejärel määrduge NoSchedule või NoExecute:

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

Samuti väärib märkimist, et kahjustusmehhanism toetab kolme peamist mõju: NoSchedule, NoExecute и PreferNoSchedule.

  • NoSchedule tähendab, et kuni podi spetsifikatsioonis on vastav kirje tolerations, ei saa seda sõlme juurutada (selles näites node10).

  • PreferNoSchedule - lihtsustatud versioon NoSchedule. Sel juhul püüab planeerija mitte eraldada kaustasid, millel pole sobivat kirjet. tolerations sõlme kohta, kuid see ei ole range piirang. Kui klastris pole ressursse, hakatakse kaunasid selles sõlmes juurutama.

  • NoExecute - see efekt käivitab kohese evakueerimise kaunadest, millel pole sobivat sisestust tolerations.

Kummalisel kombel saab seda käitumist lubade mehhanismi abil tagasi võtta. See on mugav, kui on olemas "keelatud" sõlm ja peate sellele paigutama ainult infrastruktuuriteenused. Kuidas seda teha? Lubage ainult neid kaunasid, mille puhul on sobiv tolerants.

Podi spetsifikatsioon näeks välja järgmine:

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

See ei tähenda, et järgmise ümberpaigutamise ajal tabab pod täpselt seda sõlme, see ei ole sõlme afiinsusmehhanism ja nodeSelector. Kuid mitme funktsiooni kombineerimisega saate saavutada väga paindliku ajakava seadistuse.

8. Määrake Podi juurutamise prioriteet

See, et olete konfigureerinud pod-to-sõlme sidumise, ei tähenda, et kõiki kaustasid tuleks käsitleda sama prioriteediga. Näiteks võite soovida juurutada mõned Pod enne teisi.

Kubernetes pakub erinevaid viise Podi prioriteedi ja Preemptioni määramiseks. Seade koosneb mitmest osast: objekt PriorityClass ja väljade kirjeldused priorityClassName kauna spetsifikatsioonis. Kaaluge näidet:

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 99999
globalDefault: false
description: "This priority class should be used for very important pods only"

Meie loome PriorityClass, andke sellele nimi, kirjeldus ja väärtus. Mida kõrgem value, seda kõrgem on prioriteet. Väärtus võib olla mis tahes 32-bitine täisarv, mis on väiksem või võrdne 1 000 000 000. Kõrgemad väärtused on reserveeritud missioonikriitiliste süsteemimoodulite jaoks, mida tavaliselt ei saa ennetada. Väljatõstmine toimub ainult siis, kui kõrge prioriteediga kambril pole kuhugi ümber pöörata, siis evakueeritakse osa konkreetsest sõlmest. Kui see mehhanism on teie jaoks liiga jäik, saate selle valiku lisada preemptionPolicy: Never, ja siis eelisostust ei toimu, pod on järjekorras esimene ja ootab, kuni ajakava selle jaoks vabad ressursid leiab.

Järgmisena loome kausta, milles määrame nime 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
          

Saate luua nii palju prioriteetseid klasse, kui soovite, kuigi on soovitatav sellest mitte lasta end ära lasta (näiteks piirduda madala, keskmise ja kõrge prioriteediga).

Seega saate vajadusel suurendada kriitiliste teenuste, nagu nginx-ingress-controller, coredns jne, juurutamise efektiivsust.

9. Optimeerige oma ETCD klaster

Üheksa Kubernetese jõudlusnõuannet

ETCD-d võib nimetada kogu klastri ajuks. On väga oluline säilitada selle andmebaasi töö kõrgel tasemel, kuna sellest sõltub toimingute kiirus "Kuubis". Üsna standardne ja samas hea lahendus oleks hoida põhisõlmedes ETCD-klastrit, et kube-apiserveril oleks minimaalne viivitus. Kui see pole võimalik, asetage ETCD võimalikult lähedale, nii et osalejate vahel oleks hea ribalaius. Pöörake tähelepanu ka sellele, kui palju ETCD sõlme võib klastrit kahjustamata välja kukkuda.

Üheksa Kubernetese jõudlusnõuannet

Pidage meeles, et klastris osalejate arvu liigne kasv võib suurendada veataluvust jõudluse arvelt, kõik peaks olema mõõdukas.

Kui me räägime teenuse seadistamisest, siis on mõned soovitused:

  1. Kas teil on hea riistvara, mis põhineb klastri suurusel (saate lugeda siin).

  2. Kohandage mõnda parameetrit, kui olete laotanud klastri paari DC või võrgu vahel ja kettad jätavad palju soovida (saate lugeda siin).

Järeldus

Selles artiklis kirjeldatakse punkte, mida meie meeskond püüab järgida. See ei ole toimingute samm-sammuline kirjeldus, vaid valikud, mis võivad olla kasulikud klastri üldkulude optimeerimiseks. Selge on see, et iga klaster on omal moel ainulaadne ja häälestuslahendused võivad olla väga erinevad, seega oleks huvitav saada tagasisidet: kuidas jälgite oma Kubernetese klastrit, kuidas parandate selle jõudlust. Jagage oma kogemusi kommentaarides, see on huvitav teada saada.

Allikas: www.habr.com