ProHoster > Blogi > Haldamine > Automaatne skaleerimine ja ressursside haldamine Kubernetesis (ülevaade ja videoaruanne)
Automaatne skaleerimine ja ressursside haldamine Kubernetesis (ülevaade ja videoaruanne)
27. aprillil konverentsil Streik 2019, jaotise "DevOps" osana esitati aruanne "Automaatne skaleerimine ja ressursside haldamine Kubernetesis". See räägib sellest, kuidas saate K8-sid kasutada, et tagada oma rakenduste kõrge kättesaadavus ja tippjõudlus.
Traditsiooni kohaselt on meil hea meel esitleda video raportist (44 minutit, palju informatiivsem kui artikkel) ja põhikokkuvõte teksti kujul. Mine!
Analüüsime aruande teemat sõna-sõnalt ja alustame lõpust.
Kubernetes
Oletame, et meie hostis on Dockeri konteinerid. Milleks? Korratavuse ja isolatsiooni tagamiseks, mis omakorda võimaldab lihtsat ja head juurutamist, CI/CD. Meil on palju selliseid konteineritega sõidukeid.
Mida Kubernetes sel juhul pakub?
Lõpetame nendele masinatele mõtlemise ja hakkame töötama "pilvega" konteinerite klaster või kaunad (konteinerite rühmad).
Lisaks ei mõtle me isegi üksikutele kaunadele, vaid juhime rohkemоsuuremad rühmad. Sellised kõrgetasemelised primitiivid lubage meil öelda, et teatud töökoormuse käitamiseks on mall ja siin on selle käitamiseks vajalik arv eksemplare. Kui hiljem malli muudame, muutuvad kõik eksemplarid.
Koos deklaratiivne API Konkreetsete käskude jada täitmise asemel kirjeldame "maailma struktuuri" (YAML-is), mille on loonud Kubernetes. Ja veel: kui kirjeldus muutub, muutub ka selle tegelik kuva.
Ressursside haldamine
Protsessor
Laske meil serveris käivitada nginx, php-fpm ja mysql. Nendel teenustel töötab tegelikult veelgi rohkem protsesse, millest igaüks nõuab arvutusressursse:
(numbrid slaidil on "papagoid", iga protsessi abstraktne vajadus arvutusvõimsuse järele)
Sellega töötamise hõlbustamiseks on loogiline ühendada protsessid rühmadesse (näiteks kõik nginxi protsessid ühte rühma “nginx”). Lihtne ja ilmne viis selleks on panna iga rühm konteinerisse:
Jätkamiseks peate meeles pidama, mis on konteiner (Linuxis). Nende ilmumine sai võimalikuks tänu kolmele kerneli põhifunktsioonile, mis rakendati üsna kaua aega tagasi: võimeid, nimeruumi и rühmad. Ja edasist arengut hõlbustasid muud tehnoloogiad (sealhulgas mugavad "kestad", nagu Docker):
Aruande kontekstis oleme huvitatud ainult sellest rühmad, sest kontrollrühmad on konteinerite (Docker jne) funktsionaalsuse osa, mis rakendab ressursside haldust. Rühmadeks kombineeritud protsessid, nagu soovisime, on kontrollrühmad.
Pöördume tagasi nende protsesside ja nüüd protsessirühmade CPU nõuete juurde:
(Ma kordan, et kõik numbrid on ressursside vajaduse abstraktne väljend)
Samal ajal on protsessoril endal teatud piiratud ressurss (näites on see 1000), millest kõigil võib puudust tunda (kõikide rühmade vajaduste summa on 150+850+460=1460). Mis sel juhul juhtub?
Tuum hakkab ressursse jaotama ja teeb seda "õiglaselt", andes igale rühmale sama palju ressursse. Aga esimesel juhul on neid rohkem kui vaja (333>150), seega jääb ülejääk (333-150=183) reservi, mis samuti jaotub võrdselt kahe teise konteineri vahel:
Selle tulemusena: esimesel konteineril oli piisavalt ressursse, teisel - sellel ei olnud piisavalt ressursse, kolmandal - sellel ei olnud piisavalt ressursse. See on tegude tulemus "aus" planeerija Linuxis - CFS. Selle tööd saab ülesande abil reguleerida kaal iga konteiner. Näiteks nii:
Vaatame teise konteineri (php-fpm) ressursside puudumise juhtumit. Kõik konteineriressursid jaotatakse protsesside vahel võrdselt. Selle tulemusel toimib põhiprotsess hästi, kuid kõik töötajad aeglustavad, saades vähem kui poole vajalikust:
Nii töötab CFS-i planeerija. Edasi nimetame konteineritele määratud raskusi taotlusi. Miks see nii on - vaata edasi.
Vaatame kogu olukorda teisest küljest. Teatavasti viivad kõik teed Rooma ja arvuti puhul protsessorini. Üks protsessor, palju ülesandeid – vajate valgusfoori. Lihtsaim viis ressursside haldamiseks on "valgusfoor": nad andsid ühele protsessile CPU-le kindla juurdepääsuaja, seejärel järgmisele jne.
Seda lähenemisviisi nimetatakse kõvadeks kvootideks (raske piiramine). Jätame seda lihtsalt nii piirid. Kui aga jaotada limiidid kõikidele konteineritele, tekib probleem: mysql sõitis mööda teed ja mingil hetkel lõppes selle protsessori vajadus, kuid kõik muud protsessid on sunnitud ootama kuni CPU tühikäigul.
Tuleme tagasi Linuxi tuuma ja selle koostoime juurde CPU-ga – üldpilt on järgmine:
cgroupil on kaks seadistust – sisuliselt on need kaks lihtsat keerdkäiku, mis võimaldavad teil kindlaks teha:
konteineri kaal (päringud) on aktsiad;
protsent kogu CPU ajast konteineriülesannetega töötamiseks (limiidid). kvoot.
Kuidas CPU-d mõõta?
On erinevaid viise:
Mis on papagoid, keegi ei tea – iga kord on vaja läbi rääkida.
Huvi selgem, aga suhteline: 50% 4 tuumaga ja 20 tuumaga serverist on täiesti erinevad asjad.
Võite kasutada juba mainitud kaal, mida Linux teab, kuid need on ka suhtelised.
Kõige sobivam võimalus on mõõta arvutusressursse sekundit. Need. protsessori aja sekundites reaalaja sekundite suhtes: 1 sekund protsessori aega anti 1 reaalsekundi kohta – see on üks terve protsessori tuum.
Et rääkida oleks veelgi lihtsam, hakati otse mõõtma tuumad, mis tähendab nende jaoks sama protsessori aega võrreldes tegeliku protsessoriga. Kuna Linux mõistab kaalusid, kuid mitte nii palju CPU aega/tuumasid, oli vaja mehhanismi, mis tõlkiks ühelt teisele.
Vaatleme lihtsat näidet 3 protsessori tuumaga serveriga, kus kolmele podile antakse kaalud (500, 1000 ja 1500), mis on kergesti teisendatavad neile eraldatud tuumade vastavateks osadeks (0,5, 1 ja 1,5).
Kui võtate teise serveri, kus on kaks korda rohkem südamikke (6), ja asetate sinna samad kaustad, saab tuumade jaotuse hõlpsalt arvutada, korrutades lihtsalt 2-ga (vastavalt 1, 2 ja 3). Kuid oluline hetk saabub siis, kui sellesse serverisse ilmub neljas pod, mille kaal on mugavuse huvides 3000. See võtab osa CPU ressurssidest (pooled tuumad) ära ja ülejäänud podude jaoks arvutatakse need ümber (poolitatakse):
Kubernetes ja CPU ressursid
Kubernetesis mõõdetakse protsessori ressursse tavaliselt milliadrax, st. Baaskaaluks võetakse 0,001 südamikku. (Sama asja nimetatakse Linuxi/cgroupsi terminoloogias protsessori jagamiseks, kuigi täpsemalt 1000 millituuma = 1024 protsessori jagamist.) K8s tagab, et see ei paiguta serverisse rohkem mooduleid, kui on protsessori ressursse kõigi podide kaalude summaks.
Kuidas see juhtub? Kui lisate Kubernetese klastrisse serveri, antakse teada, mitu protsessorituuma sellel on saadaval. Ja uue podi loomisel teab Kubernetese ajakava, kui palju südamikke see pod vajab. Seega määratakse pod serverile, kus on piisavalt südamikke.
Mis saab siis, kui ei päring on täpsustatud (st podil pole määratletud arvu tuumasid, mida ta vajab)? Mõelgem välja, kuidas Kubernetes üldiselt ressursse loeb.
Podi jaoks saate määrata nii päringud (CFS-i ajakava) kui ka piirangud (kas mäletate valgusfoori?):
Kui need on määratud võrdseks, määratakse podile QoS klass tagatud. See alati saadaval olev südamike arv on garanteeritud.
Kui päring on limiidist väiksem - QoS klass purunev. Need. Eeldame, et näiteks pod kasutab alati 1 tuuma, kuid see väärtus ei ole selle jaoks piiratud: mõnikord pod saab kasutada rohkem (kui serveril on selleks vabu ressursse).
Samuti on olemas QoS klass parim pingutus — see hõlmab just neid kaunasid, mille kohta taotlust ei ole täpsustatud. Ressursid antakse neile viimasena.
mälu
Mäluga on olukord sarnane, kuid veidi erinev - lõppude lõpuks on nende ressursside olemus erinev. Üldiselt on analoogia järgmine:
Vaatame, kuidas päringuid mällu rakendatakse. Laske kaunadel serveris elada, muutes mälutarbimist, kuni üks neist muutub nii suureks, et mälu saab otsa. Sel juhul ilmub OOM-i tapja ja tapab suurima protsessi:
See meile alati ei sobi, seega on võimalik reguleerida, millised protsessid on meile olulised ja neid ei tohi tappa. Selleks kasutage parameetrit oom_score_adj.
Pöördume tagasi CPU QoS-klasside juurde ja toome analoogia oom_score_adj väärtustega, mis määravad kaustade mälutarbimise prioriteedid:
Podi madalaim oom_score_adj väärtus -998 - tähendab, et selline pod tuleks tappa viimasena. tagatud.
Kõrgeim – 1000 – on parim pingutus, sellised kaunad tapetakse kõigepealt.
Ülejäänud väärtuste arvutamiseks (purunev) on olemas valem, mille põhiolemus seisneb selles, et mida rohkem ressursse kaun on taotlenud, seda väiksem on selle tapmise tõenäosus.
Teine "keerd" - limit_in_bytes - piirangute jaoks. Sellega on kõik lihtsam: määrame lihtsalt maksimaalse väljastatud mälumahu ja siin (erinevalt CPU-st) pole küsimust, kuidas seda (mälu) mõõta.
Kogusummas
Iga Kubernetese kaun on antud requests и limits - mõlemad protsessori ja mälu parameetrid:
päringute alusel töötab Kubernetese planeerija, mis jaotab podid serverite vahel;
kõigi parameetrite põhjal määratakse podi QoS klass;
CFS-i planeerija on konfigureeritud CPU päringu alusel;
OOM killer on konfigureeritud mälupäringu alusel;
valgusfoor on konfigureeritud protsessori piirangute alusel;
Mälupiirangute põhjal on cgroupi jaoks konfigureeritud limiit.
Üldiselt vastab see pilt kõigile küsimustele, kuidas Kubernetesis ressursside haldamise põhiosa toimub.
Automaatne skaleerimine
K8s klastri-automaatne skaleerija
Kujutagem ette, et kogu klaster on juba hõivatud ja vaja on luua uus pod. Kuigi kausta ei saa kuvada, ripub see olekus kuni. Selle ilmumiseks saame ühendada klastriga uue serveri või... installida cluster-autoscaler, mis teeb seda meie eest: tellib pilveteenuse pakkujalt virtuaalmasina (kasutades API päringut) ja ühenda klastriga , mille järel lisatakse kaun .
See on Kubernetese klastri automaatne skaleerimine, mis töötab suurepäraselt (meie kogemuse kohaselt). Samas, nagu mujalgi, on ka siin omad nüansid...
Niikaua kui me klastri suurust suurendasime, oli kõik korras, aga mis saab siis, kui klastrit hakkas end vabastama? Probleem on selles, et kaubikute migreerimine (hostide vabastamiseks) on tehniliselt väga keeruline ja ressursside poolest kallis. Kubernetes kasutab täiesti teistsugust lähenemist.
Kaaluge 3-st serverist koosnevat klastrit, millel on juurutamine. Sellel on 6 kausta: nüüd on iga serveri jaoks 2. Millegipärast tahtsime ühe serveri välja lülitada. Selleks kasutame käsku kubectl drain, mis:
keelab sellesse serverisse uute kaustade saatmise;
kustutab serveris olemasolevad kaustad.
Kuna Kubernetes vastutab kaunade arvu (6) säilitamise eest, on see lihtsalt hakkab uuesti looma neid teistes sõlmedes, kuid mitte sellel, mis on keelatud, kuna see on juba märgitud uute kaustade majutamiseks kättesaamatuks. See on Kubernetese põhimehaanik.
Siiski on siin ka nüanss. Sarnases olukorras on StatefulSeti (juurutamise asemel) toimingud erinevad. Nüüd on meil juba olekupõhine rakendus - näiteks kolm podi MongoDB-ga, millest ühes on mingi probleem (andmed on rikutud või muu viga, mis ei lase podil õigesti käivituda). Ja taas otsustame ühe serveri keelata. Mis juhtub?
MongoDB võiks surema, sest see vajab kvoorumit: kolmest installatsioonist koosneva klastri puhul peab toimima vähemalt kaks. Siiski, see ei toimu - tänu PodDisruptionBudget. See parameeter määrab minimaalse nõutava töötavate kaunade arvu. Teades, et üks MongoDB kaustadest enam ei tööta, ja nähes, et PodDisruptionBudget on MongoDB jaoks määratud minAvailable: 2, Kubernetes ei luba teil kausta kustutada.
Alumine rida: selleks, et kaunade liikumine (ja tegelikult ka taasloomine) klastri vabastamisel õigesti toimiks, on vaja konfigureerida PodDisruptionBudget.
Horisontaalne skaleerimine
Vaatleme teist olukorda. Kubernetesis töötab juurutusena rakendus. Kasutajaliiklus tuleb selle kaustadesse (neid on näiteks kolm) ja me mõõdame neis teatud näitajat (näiteks protsessori koormust). Kui koormus suureneb, salvestame selle ajakava järgi ja suurendame taotluste levitamiseks kaunade arvu.
Täna ei pea Kubernetesis seda käsitsi tegema: kaunade arvu automaatne suurendamine/vähendamine on konfigureeritud sõltuvalt mõõdetud koormuse indikaatorite väärtustest.
Siin on peamised küsimused: mida täpselt mõõta и kuidas tõlgendada saadud väärtused (kaunade arvu muutmise otsuse tegemiseks). Saate mõõta palju:
Kuidas seda tehniliselt teha – koguda mõõdikuid jne. — Rääkisin raportis üksikasjalikult Järelevalve ja Kubernetes. Ja peamine nõuanne optimaalsete parameetrite valimiseks on katse!
On KASUTAGE meetodit(Kasutamise küllastus ja vead), mille tähendus on järgmine. Mille alusel on mõtet skaleerida näiteks php-fpm? Arvestades asjaolu, et töötajad hakkavad otsa saama, on see nii ärakasutamine. Ja kui töötajad on läbi ja uusi sidemeid vastu ei võeta, on see juba nii küllastus. Mõlemad parameetrid tuleb mõõta ja sõltuvalt väärtustest tuleb läbi viia skaleerimine.
Selle asemel, et järeldus
Aruandel on jätk: vertikaalse skaleerimise ja õigete ressursside valimise kohta. Ma räägin sellest tulevastes videotes meie YouTube - tellige, et mitte ilma jääda!