Sziasztok! A nevem Oleg Sidorenkov, a DomClicknél dolgozom az infrastrukturális csapat vezetőjeként. Több mint három éve használjuk a Kubikot a gyártásban, és ezalatt sok érdekes pillanatot éltünk át vele. Ma elmondom, hogyan préselhet ki még nagyobb teljesítményt a megfelelő megközelítéssel a vaníliás Kubernetes-ből a fürtje számára. Indulásra készen!
Mindannyian jól tudják, hogy a Kubernetes egy méretezhető, nyílt forráskódú rendszer konténerhangszereléshez; nos, vagy 5 bináris, amelyek varázslatosan működnek azáltal, hogy szerverkörnyezetben kezelik a mikroszolgáltatások életciklusát. Ráadásul ez egy meglehetősen rugalmas eszköz, amely Lego-hoz hasonlóan összeszerelhető a különböző feladatok maximális testreszabása érdekében.
És úgy tűnik, minden rendben van: dobd a szervereket a klaszterbe, mint a tűzifát a tűztérbe, és nem fogsz tudni semmi bánatról. De ha Ön a környezetért, azt fogja gondolni: „Hogyan tarthatnám égve a tüzet és kímélhetném meg az erdőt?” Más szóval, hogyan lehet módot találni az infrastruktúra fejlesztésére és a költségek csökkentésére.
1. Figyelje a csapat- és alkalmazásforrásokat
Az egyik legelterjedtebb, de hatékony módszer a kérések/korlátok bevezetése. Ossza fel az alkalmazásokat névterekre, a névtereket pedig fejlesztőcsapatok szerint. Üzembe helyezés előtt állítsa be az alkalmazás értékeit a processzoridő, a memória és az átmeneti tárhely fogyasztásához.
A tapasztalatok alapján arra a következtetésre jutottunk, hogy a kéréseket nem szabad kétszeresére növelni a korlátoktól. A fürt mennyiségét a kérések alapján számítják ki, és ha például 5-10-szeres erőforrás-különbséget ad az alkalmazásoknak, akkor képzelje el, mi történik a csomóponttal, ha megtelik podokkal és hirtelen terhelést kap. Semmi jó. Minimálisan fojtással, maximumon pedig búcsút vesz a dolgozótól, és ciklikus terhelést kap a maradék csomópontokon, miután a hüvelyek elkezdenek mozogni.
Ráadásul a segítséggel limitranges Kezdetben beállíthatja a tároló erőforrásértékeit - minimum, maximum és alapértelmezett:
➜ ~ 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
Ne felejtse el korlátozni a névtér erőforrásait, hogy egy csapat ne tudja átvenni a fürt összes erőforrását:
Ahogy a leírásból is látszik resourcequotas, ha az operatív csapat további 10 CPU-t fogyasztó podokat akar telepíteni, az ütemező ezt nem engedi, és hibát fog kiadni:
Egy ilyen probléma megoldásához írhat egy eszközt, például tetszik ezt, képes tárolni és lekötni a parancs állapotú erőforrásait.
2. Válassza ki az optimális fájltárolót
Itt szeretném érinteni a perzisztens kötetek témáját és a Kubernetes worker csomópontok lemezes alrendszerét. Remélem, hogy a gyártás során senki sem használja a HDD-n lévő „Kockát”, de néha már nem elég egy normál SSD. Olyan problémába ütköztünk, hogy a naplók megölték a lemezt az I/O műveletek miatt, és nincs sok megoldás:
Használjon nagy teljesítményű SSD-ket, vagy váltson NVMe-re (ha saját hardverét kezeli).
Csökkentse a naplózási szintet.
Végezzen „okos” kiegyensúlyozást a lemezt feltörő hüvelyeknél (podAntiAffinity).
A fenti képernyőn látható, hogy mi történik az nginx-ingress-controller alatt a lemezzel, ha az access_logs naplózás engedélyezve van (~12 ezer napló/mp). Ez a feltétel természetesen az összes alkalmazás leromlásához vezethet ezen a csomóponton.
Ami a PV-t illeti, sajnos nem próbáltam ki mindent típusok Állandó kötetek. Használja az Önnek legmegfelelőbb lehetőséget. Történelmileg hazánkban előfordult, hogy a szolgáltatások egy kis része igényel RWX-kötetet, és nagyon régen elkezdték NFS-tárolót használni erre a feladatra. Olcsó és... elég. Természetesen ő és én szart ettünk – áldjuk meg, de megtanultuk kihangolni, és már nem fáj a fejem. És ha lehetséges, lépjen át az S3 objektumtárolóra.
3. Gyűjtse össze az optimalizált képeket
A legjobb, ha tárolóra optimalizált képeket használ, hogy a Kubernetes gyorsabban lekérhesse és hatékonyabban végrehajthassa azokat.
Az optimalizált azt jelenti, hogy a képek:
csak egy alkalmazást tartalmazzon, vagy csak egy funkciót hajtson végre;
kis méretű, mert a nagy képeket rosszabbul továbbítják a hálózaton;
olyan állapot- és készenléti végpontokkal kell rendelkeznie, amelyek lehetővé teszik a Kubernetesnek, hogy leállás esetén intézkedjen;
használjon konténerbarát operációs rendszereket (például Alpine vagy CoreOS), amelyek jobban ellenállnak a konfigurációs hibáknak;
használjon többlépcsős összeállításokat, így csak a lefordított alkalmazásokat telepítheti, a kapcsolódó forrásokat nem.
Számos eszköz és szolgáltatás lehetővé teszi a képek menet közbeni ellenőrzését és optimalizálását. Fontos, hogy ezeket mindig naprakészen tartsa és a biztonság érdekében tesztelje. Ennek eredményeként a következőket kapja:
Csökkentett hálózati terhelés a teljes fürtön.
A konténer indítási idejének csökkentése.
A teljes Docker-nyilvántartás kisebb mérete.
4. Használja a DNS-gyorsítótárat
Ha nagy terhelésről beszélünk, akkor az élet elég silány a fürt DNS-rendszerének hangolása nélkül. Egyszer régen a Kubernetes fejlesztők támogatták a kube-dns megoldásukat. Itt is implementálták, de ez a szoftver nem volt különösebben tuningolva és nem produkálta a kellő teljesítményt, pedig egyszerű feladatnak tűnt. Aztán megjelent a coredns, amelyre áttértünk, és nem volt bánat, később ez lett az alapértelmezett DNS szolgáltatás a K8s-ban. Valamikor 40 ezer rps-re nőttünk a DNS rendszerhez, és ez a megoldás is elégtelenné vált. De szerencsére kijött a Nodelocaldns, más néven csomóponti helyi gyorsítótár, más néven NodeLocal DNSCache.
Miért használjuk ezt? Van egy hiba a Linux kernelben, amely ha többszörös hívás a conntrack NAT-on keresztül UDP-n keresztül, versenyfeltételhez vezet a conntrack táblák bejegyzéseihez, és a NAT-on keresztüli forgalom egy része elvész (a szolgáltatáson keresztül minden egyes út NAT). A Nodelocaldns úgy oldja meg ezt a problémát, hogy megszabadul a NAT-tól, és frissíti a TCP-kapcsolatot upstream DNS-re, valamint helyi gyorsítótárazza az upstream DNS-lekérdezéseket (beleértve egy rövid, 5 másodperces negatív gyorsítótárat is).
5. Vízszintes és függőleges skálázása automatikusan
Biztosan állíthatja, hogy minden mikroszolgáltatása készen áll a terhelés két-háromszoros növekedésére? Hogyan lehet megfelelően hozzárendelni az erőforrásokat az alkalmazásokhoz? A munkaterhelésen túlmenően néhány pod futása felesleges lehet, de ezek egymás mellett tartása leállás kockázatával jár a szolgáltatás felé irányuló forgalom hirtelen megnövekedése miatt. Szolgáltatások, mint pl Vízszintes Pod Autoscaler и Vertical Pod Autoscaler.
VPA lehetővé teszi a podban lévő tárolók kérésének/korlátainak automatikus emelését a tényleges használattól függően. Hogyan lehet hasznos? Ha vannak olyan podjai, amelyek valamilyen oknál fogva nem skálázhatók vízszintesen (ami nem teljesen megbízható), akkor megpróbálhatja erőforrásainak módosítását a VPA-ra bízni. Jellemzője a metrika-szerver előzmény- és aktuális adatain alapuló ajánlási rendszer, így ha nem szeretné automatikusan megváltoztatni a kéréseket/korlátokat, egyszerűen figyelheti a konténerekhez ajánlott erőforrásokat, és optimalizálhatja a beállításokat a CPU és a CPU megtakarítása érdekében. memória a klaszterben.
A kép innen származott: https://levelup.gitconnected.com/kubernetes-autoscaling-101-cluster-autoscaler-horizontal-pod-autoscaler-and-vertical-pod-2a441d9ad231
A Kubernetes ütemezője mindig a kéréseken alapul. Bármilyen értéket adsz meg, az ütemező ez alapján keres egy megfelelő csomópontot. A határértékekre azért van szükség, hogy a kocka megértse, mikor kell fojtani vagy megölni a hüvelyt. És mivel az egyetlen fontos paraméter a kérések értéke, a VPA működik vele. Amikor egy alkalmazást függőlegesen méretez, meg kell határoznia, hogy melyek legyenek a kérések. Mi lesz akkor a korlátokkal? Ez a paraméter is arányosan lesz skálázva.
Amint fentebb említettük, ez arányos skálázás a jegyzékben szereplő kérések/korlátok arányon alapul:
CPU: 200m → 300m: arány 1:1.75;
Memória: 250Mi → 500Mi: 1:2 arány.
vonatkozóan HPA, akkor átláthatóbb a működési mechanizmus. Az olyan metrikák, mint a CPU és a memória, küszöbértéket kapnak, és ha az összes replika átlaga meghaladja a küszöbértéket, az alkalmazás +1 alértékkel skálázódik, amíg az érték a küszöb alá nem esik, vagy amíg el nem éri a replikák maximális számát.
A kép innen származott: https://levelup.gitconnected.com/kubernetes-autoscaling-101-cluster-autoscaler-horizontal-pod-autoscaler-and-vertical-pod-2a441d9ad231
A szokásos mérőszámokon, például a CPU-n és a memórián kívül beállíthat küszöbértékeket a Prometheus egyéni mérőszámaihoz, és együttműködhet velük, ha úgy gondolja, hogy ez a legpontosabb jelzés arra vonatkozóan, hogy mikor méretezheti az alkalmazást. Amint az alkalmazás a megadott metrikai küszöb alatt stabilizálódik, a HPA megkezdi a sorba rendezések leskálázását a replikák minimális számára, vagy amíg a betöltés el nem éri a megadott küszöbértéket.
6. Ne feledkezzünk meg a csomópont-affinitásról és a pod-affinitásról sem
Nem minden csomópont fut ugyanazon a hardveren, és nem minden podnak kell számításigényes alkalmazásokat futtatnia. A Kubernetes segítségével beállíthatja a csomópontok és pod-ok specializációját Csomópont-affinitás и Pod Affinity.
Ha olyan csomópontjai vannak, amelyek alkalmasak a számításigényes műveletekre, akkor a maximális hatékonyság érdekében jobb, ha az alkalmazásokat a megfelelő csomópontokhoz köti. Ehhez használja nodeSelector csomóponti címkével.
Tegyük fel, hogy két csomópontja van: az egyik CPUType=HIGHFREQ és nagyszámú gyors mag, egy másik MemoryType=HIGHMEMORY több memória és gyorsabb teljesítmény. A legegyszerűbb módja a központi telepítés hozzárendelése egy csomóponthoz HIGHFREQszakaszhoz való hozzáadásával spec ez a választó:
…
nodeSelector:
CPUType: HIGHFREQ
Ennek drágább és specifikusabb módja a használata nodeAffinity mezőben affinity razdela spec. Két lehetőség van:
requiredDuringSchedulingIgnoredDuringExecution: kemény beállítás (az ütemező csak meghatározott csomópontokra telepíti a podokat (és sehol máshol));
preferredDuringSchedulingIgnoredDuringExecution: soft beállítás (az ütemező megpróbálja a telepítést meghatározott csomópontokra, és ha ez nem sikerül, akkor megpróbálja a következő elérhető csomópontra telepíteni).
Megadhat egy adott szintaxist a csomópontcímkék kezeléséhez, mint pl In, NotIn, Exists, DoesNotExist, Gt vagy Lt. Ne feledje azonban, hogy a címkék hosszú listáiban alkalmazott összetett módszerek lelassítják a döntéshozatalt kritikus helyzetekben. Más szóval, legyen egyszerű.
Mint fentebb említettük, a Kubernetes lehetővé teszi az aktuális podok affinitásának beállítását. Ez azt jelenti, hogy bizonyos podokat együttműködhet más, ugyanabban a rendelkezésre állási zónában (felhőkre vonatkozó) vagy csomópontokkal.
В podAffinity mezők affinity razdela spec ugyanazok a mezők állnak rendelkezésre, mint a esetén nodeAffinity: requiredDuringSchedulingIgnoredDuringExecutionи preferredDuringSchedulingIgnoredDuringExecution. Az egyetlen különbség az matchExpressions egy olyan csomóponthoz köti a podokat, amelyen már fut az adott címkével ellátott pod.
A Kubernetes teret is kínál podAntiAffinity, amely éppen ellenkezőleg, nem köti a hüvelyt egy adott hüvelyekkel rendelkező csomóponthoz.
A kifejezésekről nodeAffinity Ugyanez a tanács adható: próbálja meg a szabályokat egyszerűnek és logikusnak tartani, ne próbálja túlterhelni a pod specifikációt összetett szabályokkal. Nagyon könnyű olyan szabályt létrehozni, amely nem egyezik a fürt feltételeivel, ami szükségtelen terhelést jelent az ütemezőre, és csökkenti az általános teljesítményt.
7. Tűrések és tűrések
Van egy másik módja az ütemező kezelésének. Ha egy nagy fürttel rendelkezik több száz csomóponttal és több ezer mikroszolgáltatással, akkor nagyon nehéz nem engedélyezni, hogy bizonyos podokat bizonyos csomópontokon hosztoljanak.
A szennyeződések mechanizmusa – a tiltó szabályok – segít ebben. Például bizonyos forgatókönyvek esetén megtilthatja bizonyos csomópontok sorba rendezését. Ha szennyeződést szeretne alkalmazni egy adott csomópontra, akkor ezt az opciót kell használnia taint in kubectl. Adja meg a kulcsot és az értéket, majd a szennyeződést NoSchedule vagy NoExecute:
Azt is érdemes megjegyezni, hogy a szennyeződési mechanizmus három fő hatást támogat: NoSchedule, NoExecute и PreferNoSchedule.
NoScheduleazt jelenti, hogy egyelőre nem lesz megfelelő bejegyzés a pod specifikációban tolerations, nem lesz telepíthető a csomóponton (ebben a példában node10).
PreferNoSchedule - egyszerűsített változat NoSchedule. Ebben az esetben az ütemező megpróbálja nem lefoglalni azokat a sorba rendezéseket, amelyeknek nincs egyező bejegyzése tolerations csomópontonként, de ez nem szigorú korlátozás. Ha nincsenek erőforrások a fürtben, a sorba rendezések megkezdik a telepítést ezen a csomóponton.
NoExecute- ez a hatás a megfelelő bejegyzéssel nem rendelkező hüvelyek azonnali evakuálását váltja ki tolerations.
Érdekes módon ez a viselkedés megszüntethető a tolerancia mechanizmussal. Ez akkor kényelmes, ha van egy „tiltott” csomópont, és csak infrastrukturális szolgáltatásokat kell elhelyeznie rajta. Hogyan kell csinálni? Csak azokat a hüvelyeket engedje meg, amelyeknél megfelelő a tűréshatár.
Ez nem jelenti azt, hogy a következő újratelepítés erre az adott csomópontra esik, ez nem a csomóponti affinitási mechanizmus és nodeSelector. De több funkció kombinálásával nagyon rugalmas ütemezési beállításokat érhet el.
8. Állítsa be a pod telepítési prioritást
Csak azért, mert a csomópontokhoz sorba rendezések vannak hozzárendelve, még nem jelenti azt, hogy az összes sorba rendezést azonos prioritással kell kezelni. Előfordulhat például, hogy egyes podokat a többi előtt telepíthet.
A Kubernetes különböző módokat kínál a pod prioritás és az elővásárlás konfigurálására. A beállítás több részből áll: objektum PriorityClassés mezőleírások priorityClassNamea pod specifikációjában. Nézzünk egy példát:
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"
Mi alkotunk PriorityClass, adjon neki nevet, leírást és értéket.A magasabb value, annál magasabb a prioritás. Az érték bármely 32 bites egész szám lehet, amely kisebb vagy egyenlő, mint 1 000 000 000. A magasabb értékek a kritikus rendszerelemek számára vannak fenntartva, amelyeket általában nem lehet megelőzni.Az elmozdulás csak akkor következik be, ha egy magas prioritású podnak nincs helye megfordulni, akkor egy bizonyos csomópontból néhány pod kiürül. Ha ez a mechanizmus túl merev az Ön számára, hozzáadhatja a lehetőséget preemptionPolicy: Never, és akkor nem lesz elővásárlás, a pod először áll a sorban, és várja, hogy az ütemező találjon hozzá szabad erőforrásokat.
Ezután létrehozunk egy pod-ot, amelyben feltüntetjük a nevet 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
Annyi prioritási osztályt hozhat létre, amennyit csak akar, bár ajánlott, hogy ezzel ne ragadjon el (mondjuk, korlátozza magát alacsony, közepes és magas prioritásúra).
Így szükség esetén növelheti a kritikus szolgáltatások, például az nginx-ingress-controller, a coredns stb. telepítésének hatékonyságát.
9. Optimalizálja az ETCD-fürtöt
Az ETCD-t az egész klaszter agyának nevezhetjük. Nagyon fontos ennek az adatbázisnak a működését magas szinten tartani, hiszen ettől függ a Cube-ban a műveletek sebessége. Meglehetősen szabványos és egyben jó megoldás az ETCD-fürt megtartása a fő csomópontokon, hogy minimális késleltetést érjen el a kube-apiserver. Ha ezt nem tudja megtenni, helyezze az ETCD-t a lehető legközelebb, jó sávszélességgel a résztvevők között. Ügyeljen arra is, hogy az ETCD-ből hány csomópont eshet ki anélkül, hogy kárt tenne a fürtben
Ne feledje, hogy a klaszter taglétszámának túlzott növelése növelheti a hibatűrést a teljesítmény rovására, mindennek mérsékelten kell lennie.
Ha a szolgáltatás beállításáról beszélünk, néhány javaslat van:
Legyen jó hardvered a fürt mérete alapján (elolvashatod itt).
Módosítson néhány paramétert, ha egy klasztert osztott ki pár DC vagy a hálózat között, és a lemezek sok kívánnivalót hagynak maguk után (olvashatja itt).
Következtetés
Ez a cikk azokat a pontokat ismerteti, amelyeknek csapatunk megpróbál megfelelni. Ez nem a műveletek lépésenkénti leírása, hanem olyan lehetőségek, amelyek hasznosak lehetnek a fürt többletterhelésének optimalizálásához. Nyilvánvaló, hogy minden fürt egyedi a maga módján, és a konfigurációs megoldások nagyon eltérőek lehetnek, ezért érdekes lenne visszajelzést kapni arról, hogyan figyeli a Kubernetes-fürtöt és hogyan javítja a teljesítményét. Ossza meg tapasztalatait a megjegyzésekben, érdekes lesz tudni.