Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

27. aprila na konferenci Stavka 2019, v okviru razdelka “DevOps” je bilo podano poročilo “Autoscaling and resource management in Kubernetes”. Govori o tem, kako lahko s K8s zagotovite visoko razpoložljivost svojih aplikacij in zagotovite vrhunsko zmogljivost.

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

Po tradiciji se z veseljem predstavljamo video poročila (44 minut, veliko bolj informativno kot članek) in glavni povzetek v besedilni obliki. Pojdi!

Analizirajmo temo poročila besedo za besedo in začnimo od konca.

Kubernetes

Recimo, da imamo na našem gostitelju vsebnike Docker. Za kaj? Za zagotovitev ponovljivosti in izolacije, kar omogoča enostavno in dobro uvajanje, CI/CD. Takih vozil s kontejnerji imamo veliko.

Kaj ponuja Kubernetes v tem primeru?

  1. Nehamo razmišljati o teh strojih in začnemo delati z "oblakom" grozd zabojnikov ali stroki (skupine posod).
  2. Še več, niti ne razmišljamo o posameznih strokih, ampak upravljamo večоvečje skupine. Takšna primitivci na visoki ravni nam omogočajo, da rečemo, da obstaja predloga za izvajanje določene delovne obremenitve in tukaj je zahtevano število primerkov za njeno izvajanje. Če naknadno spremenimo predlogo, se bodo spremenile vse instance.
  3. Z deklarativni API Namesto izvajanja zaporedja specifičnih ukazov opisujemo »strukturo sveta« (v YAML), ki jo ustvari Kubernetes. In še enkrat: ko se spremeni opis, se spremeni tudi njegov dejanski prikaz.

Upravljanje virov

CPU

Zaženimo nginx, php-fpm in mysql na strežniku. Te storitve bodo dejansko izvajale celo več procesov, od katerih vsak zahteva računalniške vire:

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)
(številke na prosojnici so "papagaji", abstraktna potreba vsakega procesa po računalniški moči)

Za lažje delo s tem je logično združiti procese v skupine (na primer vse procese nginx v eno skupino "nginx"). Preprost in očiten način za to je, da vsako skupino postavite v vsebnik:

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

Če želite nadaljevati, se morate spomniti, kaj je vsebnik (v Linuxu). Njihov videz je bil mogoč zaradi treh ključnih funkcij v jedru, implementiranih že pred časom: Zmogljivosti, prostore imen и skupin. In nadaljnji razvoj so olajšale druge tehnologije (vključno s priročnimi "lupinami", kot je Docker):

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

V okviru poročila nas zanima le skupin, ker so nadzorne skupine tisti del funkcionalnosti vsebnikov (Docker ipd.), ki izvaja upravljanje virov. Procesi, združeni v skupine, kot smo želeli, so kontrolne skupine.

Vrnimo se k zahtevam CPE za te procese in zdaj k skupinam procesov:

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)
(Ponavljam, da so vse številke abstrakten izraz potrebe po virih)

Hkrati ima sam CPE določen končni vir (v primeru je to 1000), ki jih morda primanjkuje vsem (vsota potreb vseh skupin je 150+850+460=1460). Kaj se bo zgodilo v tem primeru?

Jedro začne razdeljevati vire in to počne "pravično", tako da vsaki skupini dodeli enako količino virov. Toda v prvem primeru jih je več kot je potrebno (333>150), tako da presežek (333-150=183) ostane v rezervi, ki se prav tako enakomerno porazdeli med drugi dve posodi:

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

Kot rezultat: prvi vsebnik je imel dovolj virov, drugi - ni imel dovolj virov, tretji - ni imel dovolj virov. To je rezultat dejanj "pošten" planer v Linuxu - CFS. Njegovo delovanje je mogoče prilagoditi z dodelitvijo uteži vsako od posod. Na primer takole:

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

Poglejmo primer pomanjkanja virov v drugem vsebniku (php-fpm). Vsi viri vsebnika so enakomerno porazdeljeni med procese. Posledično glavni proces deluje dobro, vendar se vsi delavci upočasnijo in prejmejo manj kot polovico tistega, kar potrebujejo:

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

Tako deluje razporejevalnik CFS. Nadalje bomo imenovali uteži, ki jih dodelimo vsebnikom zahteve. Zakaj je tako - glej naprej.

Poglejmo celotno situacijo z druge strani. Kot veste, vse poti vodijo v Rim, v primeru računalnika pa v CPE. En procesor, veliko nalog - potrebujete semafor. Najenostavnejši način upravljanja z viri je "semafor": enemu procesu so dali fiksen dostopni čas do CPE, nato naslednjemu itd.

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

Ta pristop se imenuje trde kvote (trda omejitev). Zapomnimo si ga preprosto kot omejitve. Če pa omejitve razdelite na vse vsebnike, se pojavi težava: mysql se je vozil po cesti in na neki točki je njegova potreba po CPE prenehala, vsi drugi procesi pa so prisiljeni čakati, dokler CPE ne nedejaven.

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

Vrnimo se k jedru Linuxa in njegovi interakciji s CPU - splošna slika je naslednja:

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

cgroup ima dve nastavitvi - v bistvu sta to dva preprosta "zasuka", ki vam omogočata, da določite:

  1. teža za kontejner (zahteve) je Delnice;
  2. odstotek celotnega CPU časa za delo na opravilih vsebnika (omejitve) je kvota.

Kako izmeriti CPU?

Obstajajo različni načini:

  1. Kaj je papige, nihče ne ve – vsakič se morate pogajati.
  2. Obresti bolj jasno, a relativno: 50% strežnika s 4 jedri in z 20 jedri je popolnoma različnih stvari.
  3. Uporabite lahko že omenjene uteži, ki jih Linux pozna, a so tudi relativni.
  4. Najprimernejša možnost je merjenje računalniških virov v sekund. Tisti. v sekundah procesorskega časa glede na sekunde realnega časa: 1 sekunda procesorskega časa je bila dana na 1 realno sekundo - to je eno celotno jedro CPU.

Da bi še lažje govorili, so začeli meriti neposredno v jedrca, kar pomeni enak procesorski čas glede na dejanskega. Ker Linux razume uteži, ne pa toliko procesorskega časa/jeder, je bil potreben mehanizem za prevajanje iz enega v drugega.

Oglejmo si preprost primer s strežnikom s 3 jedri CPU, kjer bodo trem podom dodeljene uteži (500, 1000 in 1500), ki se zlahka pretvorijo v ustrezne dele jeder, ki so jim dodeljena (0,5, 1 in 1,5).

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

Če vzamete drugi strežnik, kjer bo dvakrat več jeder (6), in tja postavite iste pode, lahko porazdelitev jeder preprosto izračunate tako, da preprosto pomnožite z 2 (1, 2 oziroma 3). Toda pomemben trenutek se zgodi, ko se na tem strežniku pojavi četrti pod, katerega teža bo zaradi udobja 3000. Odvzame del virov CPE (polovica jeder), za preostale pode pa se preračunajo (prepolovijo):

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

Kubernetes in CPE viri

V Kubernetesu se viri procesorja običajno merijo v milliadrax, tj. Za osnovno težo se vzame 0,001 jedra. (Ista stvar se v terminologiji Linux/cgroups imenuje delež CPU, čeprav, natančneje, 1000 milicores = 1024 delež CPE.) K8s zagotavlja, da na strežnik ne postavi več podov, kot je CPU virov za vsoto teže vseh podov.

Kako se to zgodi? Ko dodate strežnik v gručo Kubernetes, se sporoči, koliko jeder CPU ima na voljo. In ko ustvarja nov pod, razporejevalnik Kubernetes ve, koliko jeder bo ta pod potreboval. Tako bo pod dodeljen strežniku, kjer je dovolj jeder.

Kaj se bo zgodilo, če ne je zahteva določena (tj. pod nima določenega števila jeder, ki jih potrebuje)? Ugotovimo, kako Kubernetes na splošno šteje vire.

Za pod lahko določite zahteve (razporejevalnik CFS) in omejitve (se spomnite semaforja?):

  • Če sta določena enaka, je modulu dodeljen razred QoS zagotovljena. To število jeder, ki mu je vedno na voljo, je zagotovljeno.
  • Če je zahteva manjša od omejitve - razred QoS razpočen. Tisti. Pričakujemo, da bo pod na primer vedno uporabljal 1 jedro, vendar ta vrednost zanj ni omejitev: včasih pod lahko uporabi več (ko ima strežnik prosta sredstva za to).
  • Obstaja tudi razred QoS najboljši trud — vključuje prav tiste stroke, za katere zahteva ni navedena. Sredstva so jim dana nazadnje.

spomin

S pomnilnikom je situacija podobna, vendar nekoliko drugačna - navsezadnje je narava teh virov drugačna. Na splošno je analogija naslednja:

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

Poglejmo, kako so zahteve implementirane v pomnilnik. Pustite pode živeti na strežniku, spreminjajte porabo pomnilnika, dokler eden od njih ne postane tako velik, da mu zmanjka pomnilnika. V tem primeru se pojavi ubijalec OOM in ubije največji proces:

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

To nam vedno ne ustreza, zato je mogoče regulirati, kateri procesi so za nas pomembni in jih ne smemo uničiti. Če želite to narediti, uporabite parameter oom_score_adj.

Vrnimo se k razredom QoS CPU in potegnite analogijo z vrednostmi oom_score_adj, ki določajo prioritete porabe pomnilnika za pods:

  • Najnižja vrednost oom_score_adj za strok - -998 - pomeni, da je treba tak strok ubiti zadnji, to zagotovljena.
  • Najvišja - 1000 - je najboljši trud, takšne stroke najprej usmrtimo.
  • Za izračun preostalih vrednosti (razpočen) obstaja formula, katere bistvo se spušča v dejstvo, da več virov, kot je zahtevala stroka, manjša je verjetnost, da bo ubita.

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

Drugi "zasuk" - omejitev_v_bajtih - za omejitve. Z njim je vse preprostejše: preprosto dodelimo največjo količino izdanega pomnilnika in tukaj (za razliko od CPU) ni vprašanja, kako ga izmeriti (pomnilnik).

Skupno

Vsak pod v Kubernetesu je podan requests и limits - oba parametra za CPU in pomnilnik:

  1. Na podlagi zahtev deluje razporejevalnik Kubernetes, ki pode razdeli med strežnike;
  2. na podlagi vseh parametrov se določi razred QoS sklopa;
  3. Relativne uteži se izračunajo na podlagi zahtev procesorja;
  4. razporejevalnik CFS je konfiguriran na podlagi zahtev procesorja;
  5. OOM killer je konfiguriran na podlagi pomnilniških zahtev;
  6. "semafor" je konfiguriran glede na omejitve procesorja;
  7. Na podlagi omejitev pomnilnika je konfigurirana omejitev za skupino c.

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

Na splošno ta slika odgovarja na vsa vprašanja o tem, kako poteka glavni del upravljanja virov v Kubernetesu.

Samodejno skaliranje

Samodejni skalirnik gruče K8s

Predstavljajmo si, da je celotna gruča že zasedena in je treba ustvariti nov pod. Čeprav se pod ne more prikazati, visi v statusu Do. Da se pojavi, lahko na gručo povežemo nov strežnik ali ... namestimo cluster-autoscaler, ki bo to naredil namesto nas: pri ponudniku v oblaku naročimo navidezni stroj (z uporabo API zahteve) in ga povežemo z gručo , nato pa bo dodan pod.

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

To je samodejno skaliranje gruče Kubernetes, ki deluje odlično (po naših izkušnjah). Vendar, tako kot drugod, tudi tukaj obstajajo nekatere nianse ...

Dokler smo povečevali velikost grozda, je bilo vse v redu, kaj pa se zgodi, ko grozd se je začel osvobajati? Težava je v tem, da je selitev podov (za sprostitev gostiteljev) zelo tehnično težka in draga v smislu virov. Kubernetes uporablja popolnoma drugačen pristop.

Razmislite o skupini 3 strežnikov, ki ima Deployment. Ima 6 podov: zdaj sta 2 za vsak strežnik. Iz neznanega razloga smo želeli izklopiti enega od strežnikov. Za to bomo uporabili ukaz kubectl drain, ki:

  • bo prepovedal pošiljanje novih podov na ta strežnik;
  • bo izbrisal obstoječe sklope na strežniku.

Ker je Kubernetes odgovoren za vzdrževanje števila podov (6), preprosto bo poustvarjal na drugih vozliščih, vendar ne na onemogočenem, saj je že označeno kot nedosegljivo za gostovanje novih podov. To je temeljna mehanika za Kubernetes.

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

Vendar pa je tudi tukaj odtenek. V podobni situaciji bodo dejanja za StatefulSet (namesto Deployment) drugačna. Zdaj že imamo aplikacijo s stanjem - na primer tri pode z MongoDB, od katerih ima ena nekakšno težavo (podatki so se poškodovali ali druga napaka, ki preprečuje pravilen zagon poda). In spet se odločimo onemogočiti en strežnik. Kaj se bo zgodilo?

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

MongoDB bi lahko umre, ker potrebuje kvorum: za gručo treh instalacij morata delovati vsaj dve. Vendar pa to ne dogaja - zahvale gredo PodDisruptionBudget. Ta parameter določa minimalno zahtevano število delovnih strokov. Vedeti, da eden od modulov MongoDB ne deluje več, in videti, da je PodDisruptionBudget nastavljen za MongoDB minAvailable: 2, vam Kubernetes ne bo dovolil brisanja sklopa.

Bistvo: da bo premikanje (in pravzaprav ponovno ustvarjanje) podov delovalo pravilno, ko je gruča sproščena, morate konfigurirati PodDisruptionBudget.

Horizontalno skaliranje

Razmislimo o drugi situaciji. V Kubernetesu se izvaja aplikacija kot uvedba. Uporabniški promet pride na njegove pode (te so na primer trije), v njih pa izmerimo določen indikator (recimo obremenitev procesorja). Ko se obremenitev poveča, jo zabeležimo na urnik in povečamo število podov za distribucijo zahtev.

Danes v Kubernetesu tega ni treba narediti ročno: samodejno povečanje/zmanjšanje števila podov je konfigurirano glede na vrednosti izmerjenih indikatorjev obremenitve.

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

Glavna vprašanja tukaj so: kaj natančno meriti и kako razlagati dobljene vrednosti (za odločitev o spremembi števila strokov). Izmerite lahko veliko:

Samodejno skaliranje in upravljanje virov v Kubernetesu (pregled in video poročilo)

Kako to tehnično narediti - zbirati metrike itd. — Podrobno sem govoril v poročilu o Spremljanje in Kubernetes. In glavni nasvet za izbiro optimalnih parametrov je poskus!

Obstaja UPORABA metode (Nasičenost uporabe in napake), katerega pomen je naslednji. Na podlagi česa je smiselno skalirati npr. php-fpm? Glede na to, da delavcev zmanjkuje, je to uporaba. In če je delavcev konec in nove povezave niso sprejete, je to že nasičenost. Oba parametra je treba izmeriti in glede na vrednosti je treba izvesti skaliranje.

Namesto zaključka

Poročilo ima nadaljevanje: o vertikalnem skaliranju in kako izbrati prave vire. O tem bom govoril v prihodnjih videoposnetkih naš YouTube - naročite se, da ne zamudite!

Video posnetki in diapozitivi

Video z nastopa (44 minut):

Predstavitev poročila:

PS

Druga poročila o Kubernetesu na našem blogu:

Vir: www.habr.com

Dodaj komentar