ProHoster > Blogi > antaminen > Automaattinen skaalaus ja resurssien hallinta Kubernetesissa (yleiskatsaus ja videoraportti)
Automaattinen skaalaus ja resurssien hallinta Kubernetesissa (yleiskatsaus ja videoraportti)
Konferenssissa 27. huhtikuuta Lakko 2019, osana "DevOps" -osiota annettiin raportti "Autoscaling and Resource Management in Kubernetes". Siinä kerrotaan, kuinka voit käyttää K8s-laitteita sovelluksiesi korkean käytettävyyden ja huippusuorituskyvyn varmistamiseksi.
Perinteisesti esittelemme mielellämme video raportista (44 minuuttia, paljon informatiivisempi kuin artikkeli) ja päätiivistelmä tekstimuodossa. Mennä!
Analysoidaan raportin aihe sana sanalta ja aloitetaan lopusta.
Kubernetes
Oletetaan, että isännässämme on Docker-kontit. Minkä vuoksi? Toistettavuuden ja eristyksen varmistamiseksi, mikä puolestaan mahdollistaa yksinkertaisen ja hyvän käyttöönoton, CI/CD. Meillä on monia tällaisia konteilla varustettuja ajoneuvoja.
Mitä Kubernetes tarjoaa tässä tapauksessa?
Lopetamme näiden koneiden ajattelemisen ja alamme työskennellä "pilven" kanssa konttien klusteri tai palot (säiliöryhmät).
Lisäksi emme edes ajattele yksittäisiä paloja, vaan hallitsemme enemmänоsuurempia ryhmiä. Sellainen korkean tason primitiivit Salli meidän sanoa, että tietyn työkuorman suorittamiseen on malli, ja tässä on tarvittava määrä esiintymiä sen suorittamiseen. Jos muutamme mallia myöhemmin, kaikki esiintymät muuttuvat.
Kanssa deklaratiivinen API Sen sijaan, että suorittaisimme tiettyjen komentojen sarjan, kuvaamme "maailman rakennetta" (YAML:ssa), jonka Kubernetes on luonut. Ja vielä: kun kuvaus muuttuu, myös sen todellinen näyttö muuttuu.
Resurssienhallinta
prosessori
Ajetaan palvelimella nginx, php-fpm ja mysql. Näissä palveluissa on itse asiassa käynnissä vielä enemmän prosesseja, joista jokainen vaatii laskentaresursseja:
(dian numerot ovat "papukaijoja", kunkin prosessin abstrakti laskentatehotarve)
Tämän kanssa työskentelyn helpottamiseksi on loogista yhdistää prosessit ryhmiin (esimerkiksi kaikki nginx-prosessit yhdeksi ryhmäksi "nginx"). Yksinkertainen ja ilmeinen tapa tehdä tämä on laittaa jokainen ryhmä säilöön:
Jatkamiseksi sinun on muistettava, mikä säilö on (Linuxissa). Niiden ilmestyminen mahdollisti ytimen kolmen keskeisen ominaisuuden ansiosta, jotka on otettu käyttöön melko kauan sitten: kyvyt, nimiavaruudet и ryhmät. Ja jatkokehitystä auttoivat muut tekniikat (mukaan lukien kätevät "kuoret", kuten Docker):
Raportin yhteydessä olemme vain kiinnostuneita ryhmät, koska ohjausryhmät ovat osa säilöjen (Docker jne.) toiminnallisuutta, joka toteuttaa resurssien hallinnan. Ryhmiin yhdistetyt prosessit, kuten halusimme, ovat kontrolliryhmiä.
Palataan näiden prosessien suoritinvaatimuksiin ja nyt prosessiryhmiin:
(Toistan, että kaikki luvut ovat abstrakteja ilmauksia resurssien tarpeesta)
Samaan aikaan CPU:lla itsessään on tietty rajallinen resurssi (esimerkissä tämä on 1000), jota kaikilta saattaa puuttua (kaikkien ryhmien tarpeiden summa on 150+850+460=1460). Mitä tässä tapauksessa tapahtuu?
Ydin alkaa jakaa resursseja ja tekee sen "reilusti" antaen jokaiselle ryhmälle saman määrän resursseja. Mutta ensimmäisessä tapauksessa niitä on enemmän kuin tarvitaan (333>150), joten ylijäämä (333-150=183) jää varaan, joka myös jakautuu tasaisesti kahden muun kontin kesken:
Seurauksena: ensimmäisessä kontissa oli tarpeeksi resursseja, toisessa - sillä ei ollut tarpeeksi resursseja, kolmannessa - sillä ei ollut tarpeeksi resursseja. Tämä on seurausta toimista "rehellinen" aikataulu Linuxissa - CFS. Sen toimintaa voidaan säätää tehtävän avulla paino jokainen säiliö. Esimerkiksi näin:
Tarkastellaan tapausta resurssien puutteesta toisessa säilössä (php-fpm). Kaikki konttiresurssit jaetaan tasaisesti prosessien kesken. Tämän seurauksena pääprosessi toimii hyvin, mutta kaikki työntekijät hidastavat ja saavat alle puolet tarvitsemastaan:
Näin CFS-aikataulu toimii. Kutsumme edelleen konteille määrittämiämme painoja pyynnöt. Miksi näin on - katso lisää.
Katsotaanpa koko tilannetta toiselta puolelta. Kuten tiedätte, kaikki tiet johtavat Roomaan, ja tietokoneen tapauksessa CPU: hin. Yksi prosessori, monta tehtävää - tarvitset liikennevalon. Yksinkertaisin tapa hallita resursseja on "liikennevalo": ne antoivat yhdelle prosessille kiinteän pääsyajan CPU:lle, sitten seuraavalle jne.
Tätä lähestymistapaa kutsutaan koviksi kiintiöiksi (kova rajoittava). Muistetaan se yksinkertaisesti sellaisena rajoja. Jos kuitenkin jaat rajoitukset kaikille konteille, syntyy ongelma: mysql ajoi tietä pitkin ja jossain vaiheessa sen prosessorin tarve loppui, mutta kaikki muut prosessit joutuvat odottamaan CPU:ta tyhjäkäynnillä.
Palataan Linux-ytimeen ja sen vuorovaikutukseen prosessorin kanssa - kokonaiskuva on seuraava:
cgroupilla on kaksi asetusta - pohjimmiltaan nämä ovat kaksi yksinkertaista "käännettä", joiden avulla voit määrittää:
kontin paino (pyynnöt) on osakkeet;
prosenttiosuus kokonaisprosessoriajasta konttitehtävien parissa työskentelemiseen (rajat) on kiintiö.
Kuinka mitata CPU?
On olemassa erilaisia tapoja:
Mikä on papukaijat, kukaan ei tiedä - sinun on neuvoteltava joka kerta.
korko selkeämpi, mutta suhteellinen: 50% palvelimesta, jossa on 4 ydintä ja 20 ydintä, ovat täysin eri asioita.
Voit käyttää jo mainittuja paino, jotka Linux tietää, mutta ne ovat myös suhteellisia.
Sopivin vaihtoehto on mitata laskentaresurssit sekuntia. Nuo. sekunteina prosessorin ajasta suhteessa reaaliajan sekunteihin: 1 sekunti prosessoriaikaa annettiin yhtä todellista sekuntia kohden - tämä on yksi koko CPU-ydin.
Puhumisen helpottamiseksi he alkoivat mitata suoraan ytimiä, mikä tarkoittaa niillä samaa CPU-aikaa suhteessa todelliseen. Koska Linux ymmärtää painot, mutta ei niin paljon suorittimen aikaa/ytimiä, tarvittiin mekanismi kääntääkseen yhdestä toiseen.
Tarkastellaanpa yksinkertaista esimerkkiä palvelimella, jossa on 3 CPU-ydintä, jossa kolmelle podille annetaan painot (500, 1000 ja 1500), jotka on helppo muuntaa niille allokoitujen ytimien vastaaviksi osiksi (0,5, 1 ja 1,5).
Jos otat toisen palvelimen, jossa on kaksi kertaa enemmän ytimiä (6), ja sijoitat samat kotelot sinne, ytimien jakautuminen voidaan helposti laskea kertomalla yksinkertaisesti kahdella (2, 1 ja 2, vastaavasti). Mutta tärkeä hetki tapahtuu, kun tälle palvelimelle ilmestyy neljäs pod, jonka paino on mukavuussyistä 3. Se vie osan CPU-resursseista (puolet ytimistä), ja jäljellä oleville podille ne lasketaan uudelleen (puolitetaan):
Kubernetes ja CPU-resurssit
Kubernetesissa prosessoriresurssit mitataan yleensä milliadrax, eli Peruspainoksi otetaan 0,001 ydintä. (Samaa asiaa Linux/cgroups-terminologiassa kutsutaan prosessorin jaoksi, vaikka tarkemmin sanottuna 1000 milliydintä = 1024 CPU-osuutta.) K8s varmistaa, että se ei sijoita palvelimelle enempää podeja kuin on prosessoriresurssit kaikkien podien painojen summalla.
Miten tämä tapahtuu? Kun lisäät palvelimen Kubernetes-klusteriin, raportoidaan, kuinka monta CPU-ydintä sillä on käytettävissä. Ja kun luot uutta podia, Kubernetes-ajastin tietää, kuinka monta ydintä tämä pod tarvitsee. Siten pod osoitetaan palvelimelle, jossa on tarpeeksi ytimiä.
Mitä tapahtuu jos ei pyyntö on määritetty (eli podissa ei ole määritettyä määrää sen tarvitsemia ytimiä)? Selvitetään, kuinka Kubernetes yleensä laskee resursseja.
Podille voit määrittää sekä pyynnöt (CFS-aikataulu) että rajat (muistatko liikennevalon?):
Jos ne määritetään yhtäläisiksi, podille määritetään QoS-luokka taattu. Tämä aina käytettävissä oleva määrä ytimiä on taattu.
Jos pyyntö on pienempi kuin raja - QoS-luokka räjähtävä. Nuo. Odotamme esimerkiksi podin käyttävän aina yhtä ydintä, mutta tämä arvo ei ole sille rajoitus: joskus pod voi käyttää enemmän (kun palvelimella on vapaita resursseja tähän).
Siellä on myös QoS-luokka paras ponnistus — se sisältää juuri ne palot, joille pyyntöä ei ole määritelty. Resurssit annetaan heille viimeisenä.
Память
Muistin kanssa tilanne on samanlainen, mutta hieman erilainen - loppujen lopuksi näiden resurssien luonne on erilainen. Yleisesti ottaen analogia on seuraava:
Katsotaan kuinka pyynnöt toteutetaan muistissa. Anna podien elää palvelimella ja muuttaa muistin kulutusta, kunnes yksi niistä kasvaa niin suureksi, että sen muisti loppuu. Tässä tapauksessa OOM-tappaja ilmestyy ja tappaa suurimman prosessin:
Tämä ei aina sovi meille, joten on mahdollista säännellä, mitkä prosessit ovat meille tärkeitä ja joita ei pidä tappaa. Käytä tätä varten parametria oom_score_adj.
Palataan CPU:n QoS-luokkiin ja piirretään analogia oom_score_adj-arvojen kanssa, jotka määrittävät podien muistinkulutusprioriteetit:
Alin oom_score_adj arvo podille -998 - tarkoittaa, että tällainen pod tulisi tappaa viimeisenä, tämä taattu.
Korkein - 1000 - on paras ponnistus, tällaiset palot tapetaan ensin.
Laskeaksesi jäljellä olevat arvot (räjähtävä) on kaava, jonka ydin kiteytyy siihen, että mitä enemmän resursseja pod on pyytänyt, sitä vähemmän todennäköistä on, että se tapetaan.
Toinen "käänne" - limit_in_bytes - rajoja varten. Sen avulla kaikki on yksinkertaisempaa: määritämme yksinkertaisesti myönnetyn muistin enimmäismäärän, ja täällä (toisin kuin CPU) ei ole kysymys siitä, kuinka se mitataan (muisti).
Yhteensä
Jokainen Kubernetesin pod on annettu requests и limits - molemmat parametrit suorittimelle ja muistille:
pyyntöjen perusteella toimii Kubernetes-ajastin, joka jakaa podeja palvelimien kesken;
kaikkien parametrien perusteella podin QoS-luokka määritetään;
Suhteelliset painot lasketaan suorittimen pyyntöjen perusteella;
CFS-aikataulu on konfiguroitu CPU-pyyntöjen perusteella;
OOM-killer on määritetty muistipyyntöjen perusteella;
"liikennevalo" on määritetty suorittimen rajojen perusteella;
Muistirajojen perusteella cgroupille on määritetty raja.
Yleisesti ottaen tämä kuva vastaa kaikkiin kysymyksiin siitä, kuinka pääosa resurssienhallinnasta tapahtuu Kubernetesissa.
Automaattinen skaalaus
K8s cluster-autoscaler
Kuvitellaan, että koko klusteri on jo varattu ja uusi pod on luotava. Vaikka pod ei näy, se roikkuu tilassa Odotustilassa. Jotta se ilmestyisi, voimme yhdistää klusteriin uuden palvelimen tai... asentaa cluster-autoscalerin, joka tekee sen puolestamme: tilaa virtuaalikoneen pilvipalveluntarjoajalta (API-pyynnön avulla) ja yhdistä se klusteriin. , jonka jälkeen pod lisätään .
Tämä on Kubernetes-klusterin automaattinen skaalaus, joka toimii hyvin (kokemuksemme mukaan). Kuitenkin, kuten muuallakin, tässä on joitain vivahteita...
Niin kauan kuin lisäsimme klusterin kokoa, kaikki oli hyvin, mutta mitä tapahtuu, kun klusteri alkoi vapauttaa itsensä? Ongelmana on, että podien siirtäminen (isäntien vapauttamiseksi) on teknisesti erittäin vaikeaa ja kallista resurssien kannalta. Kubernetes käyttää täysin erilaista lähestymistapaa.
Harkitse 3 palvelimen klusteria, jossa on käyttöönotto. Siinä on 6 podia: nyt niitä on 2 jokaiselle palvelimelle. Jostain syystä halusimme sammuttaa yhden palvelimista. Tätä varten käytämme komentoa kubectl drain, joka:
kieltää uusien koteloiden lähettämisen tälle palvelimelle;
poistaa olemassa olevat podit palvelimelta.
Koska Kubernetes on vastuussa palojen lukumäärän (6) ylläpitämisestä, se yksinkertaisesti tulee luomaan uudelleen ne muissa solmuissa, mutta ei siinä, joka on poistettu käytöstä, koska se on jo merkitty ei-käytettävissä uusien podien isännöintiin. Tämä on Kubernetesin perusmekaniikka.
Tässä on kuitenkin myös vivahde. Samanlaisessa tilanteessa StatefulSetin (Deploymentin sijaan) toiminnot ovat erilaisia. Nyt meillä on jo tilallinen sovellus - esimerkiksi kolme podia MongoDB:n kanssa, joista yhdessä on jonkinlainen ongelma (tiedot ovat vioittuneet tai jokin muu virhe, joka estää podia käynnistymästä oikein). Ja päätämme jälleen poistaa yhden palvelimen käytöstä. Mitä tapahtuu?
MongoDB voisi kuolee, koska se tarvitsee päätösvaltaisuuden: kolmen asennuksen klusterissa vähintään kahden on toimittava. Kuitenkin tämä ei tapahdu - kiitokset PodDisruptionBudget. Tämä parametri määrittää tarvittavan työpalojen vähimmäismäärän. Tietäen, että yksi MongoDB-tyypeistä ei enää toimi, ja nähdä, että PodDisruptionBudget on asetettu MongoDB:lle minAvailable: 2, Kubernetes ei salli podin poistamista.
Bottom line: jotta podien siirto (ja itse asiassa uudelleenluominen) toimisi oikein, kun klusteri vapautetaan, sinun on määritettävä PodDisruptionBudget.
Vaakasuora skaalaus
Ajatellaanpa toista tilannetta. Kubernetesissa on sovellus, joka toimii käyttöönottona. Käyttäjäliikenne tulee sen podeihin (niitä on esimerkiksi kolme), ja mittaamme niissä tietyn indikaattorin (esim. prosessorin kuormituksen). Kun kuormitus kasvaa, tallennamme sen aikataulun mukaisesti ja lisäämme podien määrää pyyntöjen jakamiseksi.
Nykyään Kubernetesissa tätä ei tarvitse tehdä manuaalisesti: koteloiden lukumäärän automaattinen lisäys/vähennys konfiguroidaan mitattujen kuormitusilmaisimien arvojen mukaan.
Tärkeimmät kysymykset tässä ovat: mitä tarkalleen mitataan и miten tulkita saadut arvot (palojen lukumäärän muuttamisen päätöksen tekemiseksi). Voit mitata paljon:
Kuinka tehdä tämä teknisesti - kerää mittareita jne. – Puhuin raportissa yksityiskohtaisesti aiheesta Valvonta ja Kubernetes. Ja tärkein neuvo optimaalisten parametrien valitsemiseksi on koe!
On KÄYTÄ menetelmää(Käyttökylläisyys ja virheet), jonka merkitys on seuraava. Millä perusteella on järkevää skaalata esimerkiksi php-fpm? Perustuu siihen, että työntekijät ovat loppumassa, tämä on käyttö. Ja jos työntekijät ovat loppuneet eikä uusia yhteyksiä oteta vastaan, tämä on jo kyllästyminen. Molemmat parametrit on mitattava ja arvoista riippuen on suoritettava skaalaus.
Sen sijaan johtopäätös
Raportissa on jatkoa: vertikaalisesta skaalauksesta ja oikeiden resurssien valitsemisesta. Puhun tästä tulevissa videoissa meidän YouTube - Tilaa niin et jää paitsi!