Yhdeksän Kubernetesin suorituskykyvinkkiä

Yhdeksän Kubernetesin suorituskykyvinkkiä

Hei kaikki! Nimeni on Oleg Sidorenkov, työskentelen DomClickissa infrastruktuuritiimin päällikkönä. Olemme käyttäneet Kubikia tuotannossa yli kolme vuotta, ja tänä aikana olemme kokeneet sen kanssa monia erilaisia ​​mielenkiintoisia hetkiä. Tänään kerron sinulle, kuinka voit oikealla lähestymistavalla puristaa entistä enemmän suorituskykyä vanilja Kubernetesista klusteriisi. Paikoillanne, valmiit, hep!

Tiedätte kaikki varsin hyvin, että Kubernetes on skaalautuva avoimen lähdekoodin järjestelmä kontin orkestrointiin; tai 5 binaaria, jotka toimivat taikuudella hallitsemalla mikropalveluidesi elinkaarta palvelinympäristössä. Lisäksi se on melko joustava työkalu, joka voidaan koota Legon tapaan maksimaaliseen räätälöintiin eri tehtäviin.

Ja kaikki näyttää olevan kunnossa: heitä palvelimia klusteriin, kuten polttopuita tulipesään, äläkä tunne surua. Mutta jos olet ympäristön puolesta, ajattelet: "Kuinka voin pitää tulen uunissa ja katua metsää?". Toisin sanoen kuinka löytää tapoja parantaa infrastruktuuria ja vähentää kustannuksia.

1. Seuraa tiimi- ja sovellusresursseja

Yhdeksän Kubernetesin suorituskykyvinkkiä

Yksi banaalisimmista mutta tehokkaimmista menetelmistä on pyyntöjen/rajoitusten käyttöönotto. Erottele sovellukset nimiavaruuksien mukaan ja nimiavaruudet kehitysryhmien mukaan. Aseta sovellus ennen kuin otat käyttöön arvot prosessorin ajan, muistin ja lyhytaikaisen tallennustilan kulutukselle.

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

Kokemuksen perusteella tulimme siihen tulokseen, että pyyntöjä ei kannata kasvattaa limiitistä yli kaksinkertaiseksi. Klusterin tilavuus lasketaan pyyntöjen perusteella, ja jos asetat sovellusten resurssien eron esimerkiksi 5-10 kertaa, niin kuvittele mitä tapahtuu solmullesi, kun se on täynnä tyynyjä ja yhtäkkiä saa kuorman . Ei mitään hyvää. Vähintään kuristus ja maksimissaan hyvästit työntekijälle ja syklinen kuormitus muille solmuille sen jälkeen, kun podit alkavat liikkua.

Lisäksi avustuksella limitranges voit asettaa säilön resurssiarvot alussa - minimi, maksimi ja oletus:

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

Muista rajoittaa nimitilan resursseja, jotta yksi komento ei voi ottaa kaikkia klusterin resursseja:

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

Kuten kuvauksesta näkyy resourcequotas, jos ops-komento haluaa ottaa käyttöön podeja, jotka kuluttavat vielä 10 prosessoria, ajastin ei salli sitä ja antaa virheilmoituksen:

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

Voit ratkaista samanlaisen ongelman kirjoittamalla työkalun, esimerkiksi nimellä tämä, joka voi tallentaa ja sitoa komentotilan resursseja.

2. Valitse paras tiedostojen tallennustila

Yhdeksän Kubernetesin suorituskykyvinkkiä

Tässä haluaisin koskettaa aihetta pysyvistä taltioista ja Kubernetes-työntekijäsolmujen levyalijärjestelmästä. Toivottavasti kukaan ei käytä tuotannossa kiintolevyllä olevaa "Cubea", mutta joskus tavallinen SSD ei enää riitä. Havaitsimme ongelman, jossa lokit tuhosivat levyn I/O-toimintojen vuoksi, eikä monia ratkaisuja ole:

  • Käytä tehokkaita SSD-levyjä tai vaihda NVMe:hen (jos hallitset omaa laitteistoasi).

  • Vähennä kirjaamisen tasoa.

  • Tasaa "älykäs" levyn raiskaavien palojen tasapaino (podAntiAffinity).

Yllä oleva kuvakaappaus näyttää, mitä tapahtuu nginx-ingress-controllerin alla levyllä, kun access_logs-kirjaus on käytössä (~12 XNUMX lokia/s). Tällainen tila voi tietysti johtaa kaikkien tämän solmun sovellusten heikkenemiseen.

Mitä tulee PV:hen, valitettavasti en ole kokeillut kaikkea. tyypit Pysyvät volyymit. Käytä sinulle parhaiten sopivaa vaihtoehtoa. Maassamme on historiallisesti käynyt niin, että pieni osa palveluista tarvitsee RWX-volyymeja, ja kauan sitten alettiin käyttää NFS-tallennustilaa tähän tehtävään. Halpa ja... tarpeeksi. Tietysti söimme paskaa hänen kanssaan - ole terve, mutta opimme virittämään hänet, eikä hänen päänsä enää satu. Ja jos mahdollista, vaihda S3-objektien tallennustilaan.

3. Rakenna optimoituja kuvia

Yhdeksän Kubernetesin suorituskykyvinkkiä

On parasta käyttää säiliöön optimoituja kuvia, jotta Kubernetes voi noutaa ne nopeammin ja suorittaa ne tehokkaammin. 

Optimointi tarkoittaa, että kuvat:

  • sisältää vain yhden sovelluksen tai suorittaa vain yhden toiminnon;

  • pieni koko, koska suuret kuvat lähetetään huonommin verkon kautta;

  • niillä on terveys- ja valmiuspäätepisteet, joita Kubernetes voi käyttää toimiin seisokkien sattuessa;

  • käytä konttiystävällisiä käyttöjärjestelmiä (kuten Alpine tai CoreOS), jotka kestävät paremmin määritysvirheitä;

  • käytä monivaiheisia koontiversioita, jotta voit ottaa käyttöön vain käännettyjä sovelluksia etkä mukana tulevia lähteitä.

On olemassa monia työkaluja ja palveluita, joiden avulla voit tarkistaa ja optimoida kuvia lennossa. On tärkeää pitää ne aina ajan tasalla ja testattu turvallisuuden vuoksi. Tuloksena saat:

  1. Vähentynyt verkon kuormitus koko klusterissa.

  2. Lyhentynyt kontin käynnistysaika.

  3. Pienempi koko Docker-rekisteristäsi.

4. Käytä DNS-välimuistia

Yhdeksän Kubernetesin suorituskykyvinkkiä

Jos puhumme suurista kuormituksista, elämä on melko kurjaa ilman klusterin DNS-järjestelmän viritystä. Aikoinaan Kubernetes-kehittäjät tukivat kube-dns-ratkaisuaan. Se otettiin käyttöön myös maassamme, mutta tämä ohjelmisto ei oikein virittynyt eikä antanut vaadittua suorituskykyä, vaikka tehtävä näyttää olevan yksinkertainen. Sitten ilmestyi coredns, johon vaihdoimme emmekä tienneet surua, myöhemmin siitä tuli oletus DNS-palvelu K8:ssa. Jossain vaiheessa kasvoimme DNS-järjestelmään 40 XNUMX rps, eikä tämäkään ratkaisu riittänyt. Mutta onneksi Nodelocaldns ilmestyi, eli solmun paikallinen välimuisti, alias NodeLocal DNS-välimuisti.

Miksi käytämme tätä? Linux-ytimessä on virhe, joka, kun useita pääsyjä conntrack NAT:n kautta UDP:n kautta johtaa kilpailuehtoon conntrack-taulukoihin kirjoittamiselle, ja osa NAT:n kautta kulkevasta liikenteestä menetetään (jokainen matka palvelun kautta on NAT). Nodelocaldns ratkaisee tämän ongelman poistamalla NAT:n ja päivittämällä TCP-yhteyden ylävirran DNS:ään sekä tallentamalla ylävirran DNS-kyselyt paikallisesti välimuistiin (mukaan lukien lyhyt 5 sekunnin negatiivinen välimuisti).

5. Skaalaa tyynyt vaaka- ja pystysuunnassa automaattisesti

Yhdeksän Kubernetesin suorituskykyvinkkiä

Voitko varmuudella sanoa, että kaikki mikropalvelusi ovat valmiita XNUMX-XNUMX-kertaiseen kuormituksen kasvuun? Kuinka allokoida resurssit oikein sovelluksillesi? Muutaman kotelon pitäminen käynnissä yli työtaakan voi olla tarpeetonta, ja niiden pitäminen vastakkain voi aiheuttaa seisokkeja palvelun liikenteen äkillisen lisääntymisen vuoksi. Kultainen keskitie auttaa saavuttamaan kertolaskuloitsuja sellaiset palvelut kuin Horisontaalinen Pod Autoscaler и Vertical Pod Autoscaler.

VPA antaa sinun automaattisesti nostaa säilöjesi pyyntöjä/rajoja paketissa todellisen käytön perusteella. Miten siitä voi olla hyötyä? Jos sinulla on podeja, joita ei jostain syystä voida skaalata vaakasuoraan (mikä ei ole täysin luotettava), voit yrittää luottaa VPA:han muuttamaan resurssejaan. Sen ominaisuus on suositusjärjestelmä, joka perustuu metripalvelimen historiallisiin ja nykyisiin tietoihin, joten jos et halua muuttaa pyyntöjä/rajoja automaattisesti, voit yksinkertaisesti seurata säilöidesi suositeltuja resursseja ja optimoida asetukset prosessorin ja muistin säästämiseksi. klusterissa.

Yhdeksän Kubernetesin suorituskykyvinkkiäKuva otettu osoitteesta https://levelup.gitconnected.com/kubernetes-autoscaling-101-cluster-autoscaler-horizontal-pod-autoscaler-and-vertical-pod-2a441d9ad231

Kubernetesin ajoitus perustuu aina pyyntöihin. Riippumatta siitä, minkä arvon asetat sinne, ajoittaja etsii sopivan solmun sen perusteella. Kubletti tarvitsee raja-arvon, jotta se tietää milloin kaasua tai tappaa pod. Ja koska ainoa tärkeä parametri on pyyntöarvo, VPA toimii sen kanssa. Aina kun skaalaat sovelluksesi pystysuunnassa, määrität, mitä pyyntöjen tulee olla. Ja mitä rajoituksille sitten tapahtuu? Tämä parametri skaalataan myös suhteellisesti.

Tässä ovat esimerkiksi tyypilliset pod-asetukset:

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

Suositusmoottori määrittää, että sovelluksesi tarvitsee 300 m CPU:n ja 500 Mi:n toimiakseen kunnolla. Saat nämä asetukset:

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

Kuten edellä mainittiin, tämä on suhteellinen skaalaus, joka perustuu luettelon pyyntöjen ja rajojen suhteeseen:

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

  • Muisti: 250Mi → 500Mi: 1:2-suhde.

Suhteen HPA, silloin toimintamekanismi on läpinäkyvämpi. Kynnysarvot asetetaan mittareille, kuten prosessori ja muisti, ja jos kaikkien replikoiden keskiarvo ylittää kynnyksen, sovellus skaalautuu +1:llä, kunnes arvo laskee kynnyksen alle tai kunnes replikoiden enimmäismäärä saavutetaan.

Yhdeksän Kubernetesin suorituskykyvinkkiäKuva otettu osoitteesta https://levelup.gitconnected.com/kubernetes-autoscaling-101-cluster-autoscaler-horizontal-pod-autoscaler-and-vertical-pod-2a441d9ad231

Tavallisten mittareiden, kuten suorittimen ja muistin, lisäksi voit asettaa kynnysarvoja mukautetuille Prometheus-mittareillesi ja työskennellä niiden kanssa, jos tämä on mielestäsi tarkin tapa määrittää, milloin sovelluksesi skaalataan. Kun sovellus vakiintuu määritetyn metrisen kynnysarvon alapuolelle, HPA alkaa skaalata podeja kopioiden vähimmäismäärään tai kunnes lataus saavuttaa kynnyksen.

6. Älä unohda Node Affinity ja Pod Affinity

Yhdeksän Kubernetesin suorituskykyvinkkiä

Kaikki solmut eivät toimi samalla laitteistolla, eikä kaikkien podien tarvitse suorittaa laskentaintensiivisiä sovelluksia. Kubernetesin avulla voit määrittää solmujen ja tyynyjen erikoistumisen käyttämällä Solmuaffiniteetti и Pod Affinity.

Jos sinulla on laskentaintensiivisiin toimintoihin soveltuvia solmuja, parhaan tehokkuuden saavuttamiseksi on parempi sitoa sovellukset sopiviin solmuihin. Käytä tätä varten nodeSelector solmumerkinnällä.

Oletetaan, että sinulla on kaksi solmua: yksi CPUType=HIGHFREQ ja suuri määrä nopeita ytimiä, toisessa MemoryType=HIGHMEMORY enemmän muistia ja nopeampi suorituskyky. Helpoin tapa on määrittää pod-käyttöönotto solmulle HIGHFREQlisäämällä osioon spec tällainen valitsin:

…
nodeSelector:
	CPUType: HIGHFREQ

Kalliin ja tarkempi tapa tehdä tämä on käyttää nodeAffinity kentällä affinity osio spec. Vaihtoehtoja on kaksi:

  • requiredDuringSchedulingIgnoredDuringExecution: kova asetus (ajoitusohjelma ottaa podit käyttöön vain tietyissä solmuissa (eikä missään muualla));

  • preferredDuringSchedulingIgnoredDuringExecution: pehmeä asetus (ajastin yrittää ottaa käyttöön tiettyihin solmuihin, ja jos se epäonnistuu, se yrittää ottaa käyttöön seuraavaan käytettävissä olevaan solmuun).

Voit määrittää tietyn syntaksin solmutunnisteiden hallintaan, esimerkiksi In, NotIn, Exists, DoesNotExist, Gt tai Lt. Muista kuitenkin, että monimutkaiset menetelmät pitkissä tarraluetteloissa hidastavat päätöksentekoa kriittisissä tilanteissa. Toisin sanoen, älä monimutkaistu liikaa.

Kuten edellä mainittiin, Kubernetes antaa sinun asettaa nykyisten podien affiniteetin. Toisin sanoen voit saada tietyt podit toimimaan yhdessä muiden samassa käytettävyysvyöhykkeessä olevien podien (koskee pilviä) tai solmuja.

В podAffinity kenttiä affinity osio spec samat kentät ovat käytettävissä kuin tapauksessa nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution и preferredDuringSchedulingIgnoredDuringExecution. Ainoa ero on se matchExpressions sitoo podit solmuun, jossa on jo kyseisellä tunnisteella varustettu pod.

Kubernetes tarjoaa myös kentän podAntiAffinity, joka päinvastoin ei sido podia tiettyjä podeja sisältävään solmuun.

Tietoja ilmaisuista nodeAffinity Sama neuvo voidaan antaa: yritä pitää säännöt yksinkertaisina ja loogisina, älä yritä ylikuormittaa pod-määrittelyä monimutkaisilla säännöillä. On erittäin helppoa luoda sääntö, joka ei vastaa klusterin ehtoja, mikä kuormittaa ajastinta ja heikentää yleistä suorituskykyä.

7. Haitat ja toleranssit

On toinenkin tapa hallita ajastinta. Jos sinulla on suuri klusteri, jossa on satoja solmuja ja tuhansia mikropalveluita, on erittäin vaikeaa estää tiettyjä podeja isännöimästä tietyt solmut.

Tahrojen mekanismi - kieltävät säännöt - auttaa tässä. Voit esimerkiksi estää tiettyjä solmuja käyttämästä podeja tietyissä skenaarioissa. Käytä tätä vaihtoehtoa, jos haluat lisätä pilaan tiettyyn solmuun taint julkaisussa kubectl. Määritä avain ja arvo ja sitten pilata NoSchedule tai NoExecute:

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

On myös syytä huomata, että tahramekanismi tukee kolmea päävaikutusta: NoSchedule, NoExecute и PreferNoSchedule.

  • NoSchedule tarkoittaa, että kunnes pod-määrityksessä on vastaava merkintä tolerations, sitä ei voi ottaa käyttöön solmussa (tässä esimerkissä node10).

  • PreferNoSchedule - yksinkertaistettu versio NoSchedule. Tässä tapauksessa ajoittaja yrittää olla allokoimatta podeja, joilla ei ole vastaavaa merkintää. tolerations solmukohtaisesti, mutta tämä ei ole kova raja. Jos klusterissa ei ole resursseja, podit alkavat ottaa käyttöön tässä solmussa.

  • NoExecute - Tämä vaikutus laukaisee välittömän evakuoinnin paloista, joilla ei ole vastaavaa merkintää tolerations.

Kummallista kyllä, tämä käyttäytyminen voidaan kumota toleranssimekanismin avulla. Tämä on kätevää, kun on olemassa "kielletty" solmu ja sinun täytyy sijoittaa siihen vain infrastruktuuripalvelut. Kuinka tehdä se? Salli vain ne palot, joille on sopiva toleranssi.

Tältä pod-spesifikaatio näyttäisi:

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

Tämä ei tarkoita, että seuraavan uudelleenasennuksen aikana pod osuu täsmälleen tähän solmuun, tämä ei ole solmun affiniteettimekanismi ja nodeSelector. Mutta yhdistämällä useita ominaisuuksia, voit saavuttaa erittäin joustavan aikataulun asennuksen.

8. Aseta Pod-käyttöönoton prioriteetti

Se, että olet määrittänyt pod-to-solmu-sidoksia, ei tarkoita, että kaikkia podeja pitäisi käsitellä samalla prioriteetilla. Saatat esimerkiksi haluta ottaa käyttöön joitain podeja ennen muita.

Kubernetes tarjoaa erilaisia ​​tapoja määrittää Pod Priority ja Preemption. Asetus koostuu useista osista: objekti PriorityClass ja kenttien kuvaukset priorityClassName pod-erittelyssä. Harkitse esimerkkiä:

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"

Me luomme PriorityClass, anna sille nimi, kuvaus ja arvo. Korkeampi value, sitä korkeampi prioriteetti. Arvo voi olla mikä tahansa 32-bittinen kokonaisluku, joka on pienempi tai yhtä suuri kuin 1 000 000 000. Suuremmat arvot on varattu kriittisille järjestelmätyypeille, joita ei yleensä voida estää. Häätö tapahtuu vain, jos korkean prioriteetin podilla ei ole minnekään kääntyä, jolloin osa tietyn solmun podeista evakuoidaan. Jos tämä mekanismi on liian jäykkä sinulle, voit lisätä vaihtoehdon preemptionPolicy: Never, ja silloin ei ole etuostoa, pod on ensimmäinen jonossa ja odottaa, että ajastin löytää vapaita resursseja sille.

Seuraavaksi luomme pod, jossa määritämme nimen 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
          

Voit luoda niin monta prioriteettiluokkaa kuin haluat, vaikka on suositeltavaa, ettei se jää tähän (esimerkiksi rajoita matalaan, keskitasoon ja korkeaan prioriteettiin).

Siten voit tarvittaessa tehostaa kriittisten palvelujen, kuten nginx-ingress-controller, coredns jne., käyttöönottoa.

9. Optimoi ETCD-klusterisi

Yhdeksän Kubernetesin suorituskykyvinkkiä

ETCD:tä voidaan kutsua koko klusterin aivoiksi. On erittäin tärkeää säilyttää tämän tietokannan toiminta korkealla tasolla, koska "Kuution" toimintojen nopeus riippuu siitä. Melko tavallinen ja samalla hyvä ratkaisu olisi pitää ETCD-klusteri pääsolmuissa, jotta kube-apiserverillä olisi mahdollisimman vähän viivettä. Jos tämä ei ole mahdollista, sijoita ETCD mahdollisimman lähelle ja hyvä kaistanleveys osallistujien välillä. Kiinnitä myös huomiota siihen, kuinka monta ETCD:n solmua voi pudota vahingoittamatta klusteria.

Yhdeksän Kubernetesin suorituskykyvinkkiä

Muista, että klusterin osallistujamäärän liiallinen kasvu voi lisätä vikasietokykyä suorituskyvyn kustannuksella, kaiken pitäisi olla maltillista.

Jos puhumme palvelun perustamisesta, on muutamia suosituksia:

  1. Sinulla on hyvä laitteisto klusterin koon perusteella (voit lukea täällä).

  2. Säädä muutamia parametreja, jos olet hajauttanut klusterin DC-parin tai verkkosi välille ja levyt jättävät paljon toivomisen varaa (voit lukea täällä).

Johtopäätös

Tässä artikkelissa kuvataan kohdat, joita tiimimme yrittää noudattaa. Tämä ei ole vaiheittainen kuvaus toimista, vaan vaihtoehdoista, joista voi olla hyötyä klusterin yleiskustannusten optimoinnissa. On selvää, että jokainen klusteri on omalla tavallaan ainutlaatuinen ja viritysratkaisut voivat vaihdella suuresti, joten olisi mielenkiintoista saada teiltä palautetta: miten valvot Kubernetes-klusteriasi, miten parannat sen suorituskykyä. Jaa kokemuksesi kommenteissa, on mielenkiintoista tietää se.

Lähde: will.com