Päť zlyhaní pri nasadzovaní prvej aplikácie na Kubernetes

Päť zlyhaní pri nasadzovaní prvej aplikácie na KubernetesZlyhanie od Aris-Dreamer

Mnoho ľudí verí, že stačí migrovať aplikáciu na Kubernetes (či už pomocou Helmu alebo manuálne) a budú spokojní. Ale také jednoduché to nie je.

Tím Cloudové riešenia Mail.ru preložil článok inžiniera DevOps Juliana Gindiho. Podelí sa o to, s akými nástrahami sa jeho spoločnosť počas procesu migrácie stretla, aby ste nešliapali na rovnaké hrable.

Prvý krok: Nastavenie požiadaviek na modul a limitov

Začnime nastavením čistého prostredia, v ktorom budú naše pody bežať. Kubernetes odvádza skvelú prácu pri plánovaní modulov a riešení porúch. Ukázalo sa však, že plánovač niekedy nemôže umiestniť modul, ak je ťažké odhadnúť, koľko zdrojov potrebuje na úspešnú prácu. Tu prichádzajú požiadavky na zdroje a limity. Veľa sa diskutuje o najlepšom prístupe k stanovovaniu požiadaviek a limitov. Niekedy mám naozaj pocit, že je to viac umenie ako veda. Tu je náš prístup.

Žiadosti pod - Toto je hlavná hodnota, ktorú používa plánovač na optimálne umiestnenie modulu.

Z Dokumentácia Kubernetes: Krok filtrovania určuje množinu uzlov, kde je možné naplánovať modul. Filter PodFitsResources napríklad kontroluje, či má uzol dostatok zdrojov na uspokojenie špecifických požiadaviek na zdroje pod.

Žiadosti aplikácií používame na to, aby sa dali použiť na odhad počtu zdrojov v skutočnosti Aplikácia to potrebuje na správne fungovanie. Týmto spôsobom môže plánovač umiestniť uzly realisticky. Pôvodne sme chceli nastaviť požiadavky s maržou, aby sme zabezpečili, že každý modul bude mať dostatočne veľký počet zdrojov, ale všimli sme si, že časy plánovania sa výrazne predĺžili a niektoré moduly neboli nikdy úplne naplánované, akoby pre ne neboli prijaté žiadne požiadavky na zdroje.

V tomto prípade by plánovač často vytlačil moduly a nemohol ich preplánovať, pretože riadiaca rovina netušila, koľko zdrojov bude aplikácia vyžadovať, čo je kľúčový komponent plánovacieho algoritmu.

Obmedzenia pod - to je jasnejšia hranica pre pod. Predstavuje maximálne množstvo zdrojov, ktoré klaster pridelí kontajneru.

Opäť od oficiálna dokumentácia: Ak má kontajner nastavený limit pamäte 4 GiB, potom ho kubelet (a runtime kontajnera) vynúti. Runtime neumožňuje kontajneru použiť viac, ako je špecifikovaný limit prostriedkov. Napríklad, keď sa proces v kontajneri pokúsi použiť viac ako povolené množstvo pamäte, systémové jadro ukončí proces s chybou „nedostatok pamäte“ (OOM).

Kontajner môže vždy použiť viac zdrojov, ako je uvedené v požiadavke na zdroj, ale nikdy nemôže použiť viac, ako je uvedené v limite. Túto hodnotu je ťažké správne nastaviť, no je veľmi dôležitá.

V ideálnom prípade chceme, aby sa požiadavky na zdroje menili počas životného cyklu procesu bez zasahovania do iných procesov v systéme – to je cieľom stanovenia limitov.

Bohužiaľ nemôžem poskytnúť konkrétne pokyny, aké hodnoty nastaviť, ale sami dodržiavame nasledujúce pravidlá:

  1. Pomocou nástroja na testovanie záťaže simulujeme základnú úroveň prevádzky a monitorujeme využitie zdrojov podu (pamäť a procesor).
  2. Požiadavky pod nastavíme na ľubovoľne nízku hodnotu (s limitom zdrojov približne 5-násobkom hodnoty požiadaviek) a pozorujeme. Keď sú požiadavky príliš nízke, proces sa nemôže spustiť, čo často spôsobuje záhadné chyby runtime Go.

Všimnite si, že vyššie limity zdrojov sťažujú plánovanie, pretože modul potrebuje cieľový uzol s dostatkom dostupných zdrojov.

Predstavte si situáciu, že máte ľahký webový server s veľmi vysokým limitom zdrojov, povedzme 4 GB pamäte. Tento proces sa pravdepodobne bude musieť škálovať horizontálne a každý nový modul bude musieť byť naplánovaný na uzle s najmenej 4 GB dostupnej pamäte. Ak takýto uzol neexistuje, klaster musí zaviesť nový uzol na spracovanie tohto modulu, čo môže chvíľu trvať. Je dôležité udržiavať rozdiel medzi požiadavkami na zdroje a limitmi na minimum, aby sa zabezpečilo rýchle a plynulé škálovanie.

Druhý krok: nastavenie testov živosti a pripravenosti

Toto je ďalšia jemná téma, o ktorej sa v komunite Kubernetes často diskutuje. Je dôležité dobre porozumieť testom živosti a pripravenosti, pretože poskytujú mechanizmus, aby softvér fungoval hladko a minimalizovali prestoje. Ak však nie sú správne nakonfigurované, môžu spôsobiť vážny zásah do výkonu vašej aplikácie. Nižšie je súhrn toho, aké sú obe vzorky.

Živosť ukazuje, či je kontajner spustený. Ak zlyhá, kubelet zabije kontajner a povolí sa preň politika reštartu. Ak kontajner nie je vybavený sondou Liveness, potom bude predvolený stav úspešný - to je to, čo hovorí Dokumentácia Kubernetes.

Sondy živosti by mali byť lacné, čo znamená, že by nemali spotrebovať veľa zdrojov, pretože bežia často a potrebujú informovať Kubernetes, že aplikácia beží.

Ak nastavíte možnosť spúšťať každú sekundu, pridá sa 1 požiadavka za sekundu, takže si uvedomte, že na spracovanie tejto prevádzky budú potrebné ďalšie zdroje.

Testy životnosti v našej spoločnosti kontrolujú základné komponenty aplikácie, aj keď údaje (napríklad zo vzdialenej databázy alebo vyrovnávacej pamäte) nie sú plne dostupné.

Aplikácie sme nakonfigurovali so „zdravým“ koncovým bodom, ktorý jednoducho vracia kód odpovede 200. To znamená, že proces beží a je schopný spracovať požiadavky (ale ešte nie je prevádzka).

test pripravenosť označuje, či je kontajner pripravený na poskytovanie žiadostí. Ak sonda pripravenosti zlyhá, radič koncového bodu odstráni IP adresu podu z koncových bodov všetkých služieb zodpovedajúcich pod. Toto je uvedené aj v dokumentácii Kubernetes.

Sondy pripravenosti spotrebúvajú viac zdrojov, pretože musia byť odoslané do backendu spôsobom, ktorý naznačuje, že aplikácia je pripravená prijímať požiadavky.

V komunite sa veľa diskutuje o tom, či priamo pristupovať k databáze. Vzhľadom na réžiu (kontroly sa vykonávajú často, ale možno ich upraviť) sme sa rozhodli, že pre niektoré aplikácie sa pripravenosť na obsluhu prevádzky počíta až po overení, či sa záznamy vracajú z databázy. Dobre navrhnuté testy pripravenosti zabezpečili vyššiu úroveň dostupnosti a eliminovali prestoje počas nasadenia.

Ak sa rozhodnete dotazovať databázu, aby ste otestovali pripravenosť vašej aplikácie, uistite sa, že je to čo najlacnejšie. Zoberme si túto požiadavku:

SELECT small_item FROM table LIMIT 1

Tu je príklad toho, ako konfigurujeme tieto dve hodnoty v Kubernetes:

livenessProbe: 
 httpGet:   
   path: /api/liveness    
   port: http 
readinessProbe:  
 httpGet:    
   path: /api/readiness    
   port: http  periodSeconds: 2

Môžete pridať ďalšie možnosti konfigurácie:

  • initialDelaySeconds — koľko sekúnd uplynie medzi spustením nádoby a spustením vzoriek.
  • periodSeconds — čakací interval medzi odbermi vzoriek.
  • timeoutSeconds — počet sekúnd, po ktorých sa jednotka považuje za núdzovú. Pravidelný časový limit.
  • failureThreshold — počet zlyhaní testu pred odoslaním signálu reštartu do modulu.
  • successThreshold — počet úspešných sond predtým, ako modul prejde do stavu pripravenosti (po zlyhaní, keď modul naštartuje alebo sa zotaví).

Tretí krok: nastavenie predvolených sieťových zásad pre modul

Kubernetes má „plochú“ sieťovú topografiu; v predvolenom nastavení všetky moduly komunikujú priamo medzi sebou. V niektorých prípadoch to nie je žiaduce.

Potenciálnym bezpečnostným problémom je, že útočník by mohol použiť jedinú zraniteľnú aplikáciu na odoslanie prevádzky do všetkých modulov v sieti. Ako v mnohých oblastiach bezpečnosti, aj tu platí zásada najmenšieho privilégia. V ideálnom prípade by sieťové pravidlá mali explicitne špecifikovať, ktoré spojenia medzi modulmi sú povolené a ktoré nie.

Nižšie je napríklad jednoduchá zásada, ktorá zakazuje všetku prichádzajúcu návštevnosť pre konkrétny menný priestor:

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:  
 name: default-deny-ingress
spec:  
 podSelector: {}  
 policyTypes:  
   - Ingress

Vizualizácia tejto konfigurácie:

Päť zlyhaní pri nasadzovaní prvej aplikácie na Kubernetes
(https://miro.medium.com/max/875/1*-eiVw43azgzYzyN1th7cZg.gif)
Viac podrobností tu.

Krok štyri: vlastné správanie pomocou hákov a init kontajnerov

Jedným z našich hlavných cieľov bolo poskytnúť nasadenie pre Kubernetes bez prestojov pre vývojárov. Je to ťažké, pretože existuje veľa možností na vypnutie aplikácií a uvoľnenie zdrojov, ktoré používali.

Osobitné ťažkosti sa vyskytli s Nginx. Všimli sme si, že keď boli tieto moduly nasadzované postupne, aktívne pripojenia boli zrušené pred úspešným dokončením.

Po rozsiahlom online prieskume sa ukázalo, že Kubernetes nečaká, kým sa pripojenia Nginx nevyčerpajú pred ukončením modulu. Pomocou predbežného háku sme implementovali nasledujúcu funkciu a úplne sme sa zbavili prestojov:

lifecycle: 
 preStop:
   exec:
     command: ["/usr/local/bin/nginx-killer.sh"]

a tu nginx-killer.sh:

#!/bin/bash
sleep 3
PID=$(cat /run/nginx.pid)
nginx -s quit
while [ -d /proc/$PID ]; do
   echo "Waiting while shutting down nginx..."
   sleep 10
done

Ďalšou mimoriadne užitočnou paradigmou je použitie init kontajnerov na zvládnutie spúšťania špecifických aplikácií. Toto je obzvlášť užitočné, ak máte proces migrácie databázy náročný na prostriedky, ktorý je potrebné spustiť pred spustením aplikácie. Môžete tiež zadať vyšší limit prostriedkov pre tento proces bez nastavenia takéhoto limitu pre hlavnú aplikáciu.

Ďalšou bežnou schémou je prístup k tajomstvám v iniciačnom kontajneri, ktorý poskytuje tieto poverenia hlavnému modulu, čo zabraňuje neoprávnenému prístupu k tajomstvám zo samotného hlavného aplikačného modulu.

Ako obvykle, citujte z dokumentácie: Init kontajnery bezpečne spúšťajú vlastný kód alebo nástroje, ktoré by inak znížili bezpečnosť obrazu kontajnera aplikácie. Udržaním nepotrebných nástrojov oddelene obmedzíte útočnú plochu obrazu aplikačného kontajnera.

Piaty krok: Konfigurácia jadra

Na záver si povieme niečo o pokročilejšej technike.

Kubernetes je mimoriadne flexibilná platforma, ktorá vám umožňuje spúšťať úlohy tak, ako uznáte za vhodné. Máme množstvo vysokovýkonných aplikácií, ktoré sú mimoriadne náročné na zdroje. Po vykonaní rozsiahleho testovania záťaže sme zistili, že jedna aplikácia mala problémy so zvládnutím očakávanej záťaže, keď boli v platnosti predvolené nastavenia Kubernetes.

Kubernetes vám však umožňuje spustiť privilegovaný kontajner, ktorý mení parametre jadra iba pre konkrétny pod. Tu je to, čo sme použili na zmenu maximálneho počtu otvorených pripojení:

initContainers:
  - name: sysctl
     image: alpine:3.10
     securityContext:
         privileged: true
      command: ['sh', '-c', "sysctl -w net.core.somaxconn=32768"]

Ide o pokročilejšiu techniku, ktorá často nie je potrebná. Ak sa však vaša aplikácia snaží vyrovnať sa s veľkou záťažou, môžete skúsiť vyladiť niektoré z týchto nastavení. Viac podrobností o tomto procese a nastavení rôznych hodnôt - ako vždy v oficiálnej dokumentácii.

na záver

Aj keď sa Kubernetes môže zdať ako hotové riešenie hneď po vybalení, existuje niekoľko kľúčových krokov, ktoré musíte urobiť, aby vaše aplikácie fungovali hladko.

Počas migrácie Kubernetes je dôležité dodržiavať „cyklus testovania záťaže“: spustite aplikáciu, otestujte ju, sledujte metriky a škálovanie, upravte konfiguráciu na základe týchto údajov a potom cyklus zopakujte.

Buďte realistickí v súvislosti s očakávanou návštevnosťou a pokúste sa ju prekonať, aby ste zistili, ktoré komponenty sa pokazia ako prvé. Pri tomto iteračnom prístupe môže na dosiahnutie úspechu stačiť len niekoľko z uvedených odporúčaní. Alebo to môže vyžadovať hlbšie prispôsobenie.

Vždy si položte tieto otázky:

  1. Koľko prostriedkov spotrebujú aplikácie a ako sa tento objem zmení?
  2. Aké sú skutočné požiadavky na škálovanie? Akú priemernú návštevnosť aplikácia zvládne? A čo dopravná špička?
  3. Ako často sa bude musieť služba horizontálne škálovať? Ako rýchlo je potrebné uviesť nové moduly online, aby mohli prijímať návštevnosť?
  4. Ako správne sa moduly vypínajú? Je to vôbec potrebné? Je možné dosiahnuť nasadenie bez prestojov?
  5. Ako môžete minimalizovať bezpečnostné riziká a obmedziť škody spôsobené akýmikoľvek napadnutými modulmi? Majú nejaké služby povolenia alebo prístup, ktoré nevyžadujú?

Kubernetes poskytuje neuveriteľnú platformu, ktorá vám umožňuje využiť osvedčené postupy na nasadenie tisícok služieb v klastri. Každá aplikácia je však iná. Niekedy si implementácia vyžaduje trochu viac práce.

Našťastie Kubernetes poskytuje potrebnú konfiguráciu na dosiahnutie všetkých technických cieľov. Pomocou kombinácie požiadaviek na zdroje a limitov, testov Liveness and Readiness, init kontajnerov, sieťových politík a vlastného ladenia jadra môžete dosiahnuť vysoký výkon spolu s odolnosťou voči chybám a rýchlou škálovateľnosťou.

Čo ešte čítať:

  1. Osvedčené postupy a osvedčené postupy pre spustenie kontajnerov a Kubernetes v produkčných prostrediach.
  2. 90+ užitočných nástrojov pre Kubernetes: nasadenie, správa, monitorovanie, zabezpečenie a ďalšie.
  3. Náš kanál Okolo Kubernetes v telegrame.

Zdroj: hab.com

Pridať komentár