Öt hiba az első alkalmazás Kubernetes alatt való telepítésekor

Öt hiba az első alkalmazás Kubernetes alatt való telepítésekorHiba Aris-Dreamertől

Sokan úgy vélik, hogy elegendő átkonvertálni az alkalmazást Kubernetesre (akár Helm segítségével, akár manuálisan), és máris minden rendben lesz. De nem ennyire egyszerű.

A parancs Mail.ru Cloud Solutions Lefordítottam Julian Gindi DevOps mérnök cikkét. Megosztja, milyen csapdákkal találkoztak cégénél a migráció során, hogy ne lépj a rázós helyekre.

Első lépés: a pod kérések és limitek beállítása

Kezdjük egy tiszta környezet beállításával, ahol a podjaink működni fognak. A Kubernetes kiválóan tervezi meg a podokat és kezeli a hibás állapotokat. De kiderült, hogy a ütemező néha nem tud egy podot elhelyezni, ha nem tudja felmérni, mennyi erőforrásra van szüksége a sikeres működéshez. Itt jönnek be a kérések és limitek. Sok vita folyik a legjobb megközelítésről a kérések és limitek beállításában. Néha úgy tűnik, hogy ez inkább művészet, mint tudomány. Íme a megközelítésünk.

Pod kérések Ez a fő érték, amelyet az ütemező az optimális pod elhelyezésére használ.

A a Kubernetes dokumentációjának: a szűrési lépésnél meghatározzák azon csomópontok készletét, ahol a pod ütemezhető. Például a PodFitsResources szűrő ellenőrzi, hogy elegendő erőforrás áll-e rendelkezésre a csomóponton a pod adott erőforrás-kéréseinek teljesítéséhez.

Az alkalmazások kéréseit úgy használjuk, hogy ez alapján megbecsülhessük, mennyi erőforrásra valóban van szüksége az alkalmazásnak a normális működéshez. Ily módon az ütemező reálisan tudja elhelyezni a csomópontokat. Eredetileg úgy terveztük, hogy a kéréseket túlbiztosítjuk, hogy elegendő erőforrást garantáljunk minden pod számára, de észrevettük, hogy a tervezési idő jelentősen megnőtt, és néhány podot soha nem ütemeztek teljesen, mintha nem is érkeztek volna hozzájuk erőforrás-kérések.

Ebben az esetben az ütemező gyakran "kiszorította" a podokat, és nem tudta őket újra ütemezni, mert a vezérlő sík nem tudta, mennyi erőforrásra van szüksége az alkalmazásnak, pedig ez kulcsfontosságú komponens az ütemezési algoritmusban.

Pod limitek Ez egy tisztább korlátozás a pod számára. Ez a maximális erőforrásmennyiség, amelyet a klaszter a konténernek biztosít.

Ismét hivatalos dokumentációban: ha a konténer memóriakorlátja 4 GiB, akkor a kubelet (és a konténer végrehajtási környezet) kényszeríteni fogja ezt. A végrehajtási környezet nem engedi, hogy a konténer több erőforrást használjon, mint a megadott korlát. Például, amikor a folyamat a konténerben megpróbál több memóriát használni, mint a megengedett mennyiség, a rendszer magja hibával zárja le ezt a folyamatot: „túl sok memória” (OOM).

A konténer mindig használhat több erőforrást, mint amit a kérelemben megadtak, de soha nem használhat többet, mint ami a korlátozásban szerepel. Ezt az értéket nehéz pontosan beállítani, de nagyon fontos.

Ideális esetben azt szeretnénk, hogy a pod erőforrásigényei a folyamat életciklusa alatt változzanak anélkül, hogy zavarják a rendszer más folyamatait – ez a cél a korlátok beállítása.

Sajnos nem tudok konkrét iránymutatásokat adni, hogy mely értékeket állítsuk be, de mi az alábbi szabályokat követjük:

  1. Terheléstesztelő eszköz segítségével modellezzük az alap térforgalmat, és figyeljük a pod erőforrás- (memória és CPU) felhasználását.
  2. A pod kérelemét viszonylag alacsony értékre állítjuk (az erőforrás-korlát körülbelül 5-ször nagyobb a kérelemmel), és figyeljük. Amikor a kérelem túl alacsony szinten van, a folyamat nem tud elindulni, ami gyakran rejtélyes Go futási hibákat okoz.

Szeretném megjegyezni, hogy a magasabb erőforrás-korlátok bonyolítják a tervezést, mivel a podnak célzott csomópont szükséges elegendő elérhető erőforrással.

Képzeljen el egy helyzetet, amikor egy könnyű webszervere van, nagyon magas erőforrás-korláttal, például 4 GB memóriával. Valószínűleg ezt a folyamatot vízszintesen kell méretezni, és minden új modult egy olyan csomóponttal kell tervezni, amelyen legalább 4 GB elérhető memória van. Ha ilyen csomópont nem létezik, a klaszternek új csomópontot kell bevezetnie ennek a podnak a kezelésére, ami időt vehet igénybe. Fontos, hogy a lehető legkisebb eltérés legyen a kérelem és a korlát között az gyors és zökkenőmentes méretezés biztosítása érdekében.

Második lépés: A Liveness és Readiness tesztek beállítása

Ez egy másik finom téma, amely gyakran felmerül a Kubernetes közösségben. Fontos, hogy jól megértsük az élhetőségi (Liveness) és a készültségi (Readiness) teszteket, mivel ezek biztosítják a szoftver megbízható működését és minimalizálják a leállás idejét. Ugyanakkor súlyosan befolyásolhatják az alkalmazás teljesítményét, ha nem megfelelően vannak beállítva. Az alábbiakban rövid összefoglalást adunk mindkét próba lényegéről.

Liveness megmutatja, hogy a konténer működik-e. Ha hibát észlel, a kubelet megöli a konténert, és elindít egy újraindítási politikát. Ha a konténer nincs Liveness próbával felszerelve, akkor az alapértelmezett állapot a siker — erről van szó a a Kubernetes dokumentációjának.

Az élhetőségi próbáknak olcsóknak kell lenniük, vagyis nem szabad sok erőforrást fogyasztaniuk, mivel gyakran futnak és arról kell informálniuk a Kubernetest, hogy az alkalmazás fut.

Ha beállít egy paramétert, amely másodpercenként egyszer fut, akkor ez 1 kérdést jelent másodpercenként, így vegye figyelembe, hogy ennek a forgalomnak a kezeléséhez további erőforrásokra lesz szükség.

Cégünknél az élhetőségi tesztek ellenőrzik az alkalmazás alapvető összetevőit, még akkor is, ha az adatok (például távoli adatbázisból vagy gyorsítótárból) nem teljesen elérhetők.

A programokban beállítottuk a "működési" végpontot, amely egyszerűen 200-as válaszkódot ad vissza. Ez a folyamat futását és azt jelzi, hogy képes kezelni a kéréseket (de még nem a forgalmat).

Próba Readiness megmutatja, hogy a konténer készen áll-e a kérések kezelésére. Ha a készültségi próba hibát észlel, a végpontok vezérlője eltávolítja a pod IP-címét az összes, a podhoz tartozó szolgáltatás végpontjaiból. Ezt a Kubernetes dokumentációjában is említik.

A készültségi próbák több erőforrást fogyasztanak, mivel a háttérbe kell kerülniük úgy, hogy jelezzék az alkalmazás készségét a kérések fogadására.

A közösségben sok vita folyt arról, hogy közvetlenül a database-re kell-e hivatkozni. Figyelembe véve a költségeket (a ellenőrzések gyakran zajlanak, de szabályozhatók), úgy döntöttünk, hogy bizonyos alkalmazások esetén a forgalom szolgálatra való készültsége csak azután számít, hogy ellenőrizzük, visszakapunk-e adatokat a database-ből. Gondosan megtervezett készenléti próbák magasabb elérhetőséget biztosítottak, és megszüntették a leállásokat a telepítés során.

Ha úgy dönt, hogy a database-hez küld kérdést az alkalmazás készenlétének ellenőrzésére, győződjön meg róla, hogy ez a lehető legolcsóbb módon történik. Vegyünk egy ilyen lekérdezést:

SELECT small_item FROM table LIMIT 1

Íme egy példa, hogyan állítjuk be ezeket a két értéket Kubernetes alatt:

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

További konfigurációs paramétereket is hozzáadhatunk:

  • initialDelaySeconds — hány másodperc telik el a tároló elindítása és a próbák indítása között.
  • periodSeconds — várakozási intervallum a próbák indítása között.
  • timeoutSeconds — hány másodperc múlva számít a tároló hibásnak. Általános időtúllépés.
  • failureThreshold — hány próbához van szükség a tárolóra, mielőtt újraindító jelet küldenek.
  • successThreshold — hány sikeres próbához van szükség, mielőtt a tároló készenlét állapotba lép (hiba után, amikor a tároló újraindul vagy helyreáll).

Harmadik lépés: az alapértelmezett hálózati politikák beállítása a tárolóra

A Kubernetes-ben a „lapos” hálózati topológia miatt alapértelmezetten minden tároló közvetlenül kommunikál egymással. Bizonyos esetekben ez nem kívánatos.

A potenciális biztonsági probléma az, hogy egy támadó kihasználhat egyetlen sebezhető alkalmazást, hogy forgalmat irányítson az összes tárolóra a hálózatban. Mint sok más biztonsági területen, itt is érvényes a legkisebb jogosultság elve. Ideális esetben a hálózati politikáknak egyértelműen meg kell határozniuk, hogy mely kapcsolatok engedélyezettek a tárolók között és melyek nem.

Például itt van egy egyszerű politika, amely megtiltja az összes bejövő forgalmat egy adott névtér számára:

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

E beállítás vizualizációja:

Öt hiba az első alkalmazás Kubernetes alatt való telepítésekor
(https://miro.medium.com/max/875/1*-eiVw43azgzYzyN1th7cZg.gif)
Részletesebben itt.

Negyedik lépés: nem szabványos viselkedés hook-ok és init-tárolók segítségével

Az egyik legfontosabb feladatunk a Kubernetesben való telepítések biztosítása volt, a fejlesztők leállása nélkül. Ez nehéz, mert sokféle mód van az alkalmazások leállítására és az általuk használt erőforrások felszabadítására.

Különleges nehézségek merültek fel a Nginxkapcsán. Észrevettük, hogy ezeknek a podoknak a sorozatos telepítésekor az aktív kapcsolatok megszakadtak, mielőtt a telepítés sikeresen befejeződött volna.

Miután alaposan utánajártunk az interneten, kiderült, hogy a Kubernetes nem várja meg, amíg az Nginx kapcsolatok kimerülnek, mielőtt leállítaná a podot. A pre-stop hívással bevezettük ezt a funkciót, és teljesen megszabadultunk a leállásoktól:

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

Here is 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

Egy másik rendkívül hasznos paradigma az init-konténerek használata, amely lehetővé teszi a konkrét alkalmazások indításának kezelését. Ez különösen hasznos, ha van egy erőforrást igénylő adatbázis-migráló folyamat, amelyet az alkalmazás indítása előtt kell futtatni. Ehhez a folyamathoz beállíthat magasabb erőforrás-korlátot anélkül, hogy a fő alkalmazásra ilyen korlátot állítana.

Egy másik elterjedt sémát jelent az init-konténerben lévő titkokhoz való hozzáférés, amely ezeket az adatokat a fő modulnak biztosítja, megakadályozva ezzel a titkokhoz való jogosulatlan hozzáférést az alkalmazás fő moduljából.

Mint általában, egy idézet a dokumentációból: az init-konténerek biztonságosan futtatják a felhasználói kódokat vagy segédprogramokat, amelyek egyébként csökkentenék az alkalmazás konténerképének biztonságát. Azoknak az eszközöknek a külön tárolásával, amelyek nem szükségesek, korlátozza az alkalmazás konténerképének támadási felületét.

Ötödik lépés: a kernel konfigurálása

Végül egy fejlettebb technikáról fogunk beszélni.

A Kubernetes rendkívül rugalmas platform, amely lehetővé teszi a munkaterhelések futtatását úgy, ahogy szükségesnek tartja. Számos rendkívül igényes alkalmazásunk van, amelyek különösen sok erőforrást igényelnek. Kiterjedt terheléses tesztelés után megállapítottuk, hogy az egyik alkalmazás nehezen birkózik meg a várt forgalmi terheléssel, ha az alapértelmezett Kubernetes beállítások érvényben vannak.

A Kubernetes azonban lehetővé teszi privilegizált konténer indítását, amely csak egy adott podra módosítja a mag paramétereit. Ezt használtuk a maximális nyitott kapcsolatok számának megváltoztatásához:

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

Ez egy fejlettebb technika, amely gyakran nincs szükség. De ha az alkalmazása alig birkózik meg a nagy terheléssel, megpróbálhatja beállítani ezeket a paramétereket. További információ a folyamatról és a különböző értékek beállításáról - mint mindig az hivatalos dokumentációban.

Végül

Bár a Kubernetes kész megoldásnak tűnik, az alkalmazások folyamatos működéséhez néhány kulcsfontosságú lépést kell tenni.

A Kubernetesre való migráció során fontos követni a "terhelési teszt ciklust": elindítja az alkalmazást, terhelés alatt teszteli, figyelemmel kíséri a metrikákat és a viselkedést a skálázás során, majd az ezen adatok alapján beállítja a konfigurációt, végül újra megismétli ezt a ciklust.

Reálisan értékelje a várt forgalmat, és próbálja meg túllépni ezt a határt, hogy lássa, mely komponensek törnek elsőként. Ezzel az iteratív megközelítéssel a sikerhez elegendő lehet csak néhány a felsorolt ajánlások közül. Vagy mélyebb beállításokra lehet szükség.

Mindig tegye fel magának ezeket a kérdéseket:

  1. Mennyi erőforrást fogyasztanak az alkalmazások, és ez hogyan változik majd?
  2. Mik a valós skálázási követelmények? Mennyire forgalmat fog kezelni az alkalmazás átlagosan? És mi a helyzet a csúcsforgalommal?
  3. Milyen gyakran lesz szüksége a szolgáltatásnak horizontális skálázásra? Mennyi idő alatt kell új podokat üzembe helyezni a forgalom megfogadásához?
  4. Mennyire helyesen zárulnak le a podok? Van-e ennek egyáltalán szüksége? Meg lehet-e valósítani a telepítést leállás nélkül?
  5. Hogyan minimalizálható a biztonsági kockázat és korlátozható a károsodás bármely kompromittált pod által? Van-e néhány szolgáltatásnak jogosultsága vagy hozzáférése, amire nincs is szüksége?

A Kubernetes fantasztikus platformot biztosít, amely lehetővé teszi a legjobb gyakorlatok alkalmazását ezrek szolgáltatás telepítésére a klaszterben. Ugyanakkor minden alkalmazás más. Néha a bevezetéshez kicsit több munka szükséges.

Szerencsére a Kubernetes biztosítja a szükséges beállításokat az összes technikai cél eléréséhez. Az erőforrásigények és korlátok, a Liveness és Readiness próbalapok, az init konténerek, a hálózati politikák és a szokásos kernelbeállítások kombinációjával elérheti a magas teljesítményt a megbízhatóság és a gyors skálázhatóság mellett.

Mit érdemes még olvasni:

  1. A legjobb gyakorlatok és ajánlások konténerek és Kubernetes üzembe helyezéséhez termelési környezetekben.
  2. 90+ hasznos eszköz a Kuberneteshez: telepítés, kezelés, megfigyelés, biztonság és még sok más.
  3. Telegram csatornánk a Kubernetes körül.

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster