Öt kihagyás az első alkalmazás Kubernetesen történő üzembe helyezésekor

Öt kihagyás az első alkalmazás Kubernetesen történő üzembe helyezésekorFail by Aris-Dreamer

Sokan azt hiszik, hogy elég áttelepíteni az alkalmazást a Kubernetesre (akár Helm segítségével, akár manuálisan), és boldogok lesznek. De ez nem ilyen egyszerű.

Csapat Mail.ru Cloud Solutions lefordította Julian Gindi DevOps mérnök cikkét. Megosztja, hogy cége milyen buktatókkal szembesült az átállási folyamat során, hogy Ön ne ugyanarra a gereblyére lépjen.

Első lépés: Pod-kérések és korlátok beállítása

Kezdjük azzal, hogy tiszta környezetet hozzunk létre, amelyben a hüvelyeink működni fognak. A Kubernetes nagyszerű munkát végez a pod-ok ütemezésében és a hibahelyzetek kezelésében. De kiderült, hogy az ütemező néha nem tud egy pod-ot elhelyezni, ha nehéz megbecsülni, hogy mennyi erőforrásra van szüksége a sikeres működéshez. Itt jönnek elő az erőforrások és korlátok iránti kérések. Sok vita folyik arról, hogy mi a legjobb megközelítés a kérések és korlátok meghatározásához. Néha tényleg úgy érzi, hogy ez inkább művészet, mint tudomány. Íme a mi megközelítésünk.

Pod kérések - Ez az ütemező által használt fő érték a pod optimális elhelyezéséhez.

Of Kubernetes dokumentáció: A szűrési lépés határozza meg a csomópontok készletét, ahol a pod ütemezhető. Például a PodFitsResources szűrő ellenőrzi, hogy egy csomópont rendelkezik-e elegendő erőforrással a pod specifikus erőforráskérelmeinek kielégítéséhez.

Alkalmazáskéréseket használunk, hogy ezek alapján meg lehessen becsülni, hány erőforrást tulajdonképpen Az alkalmazásnak szüksége van rá, hogy megfelelően működjön. Így az ütemező reálisan tudja elhelyezni a csomópontokat. Kezdetben margóval akartuk beállítani a kéréseket, hogy biztosítsuk, hogy minden egyes pod kellően nagy számú erőforrással rendelkezzen, de észrevettük, hogy az ütemezési idők jelentősen megnőttek, és egyes pod-ok soha nem lettek teljesen ütemezve, mintha nem érkezett volna hozzájuk erőforrás-kérés.

Ebben az esetben az ütemező gyakran kinyomta a sorba rendezéseket, és nem tudta újraütemezni őket, mert a vezérlősíknak fogalma sem volt, mennyi erőforrást igényel az alkalmazás, ami az ütemezési algoritmus kulcsfontosságú összetevője.

Pod-korlátok - ez egy világosabb határ a pod számára. Az erőforrások maximális mennyiségét jelenti, amelyet a fürt a tárolóhoz rendel.

Megint től hivatalos dokumentáció: Ha egy tárolóhoz 4 GiB-os memóriakorlát van beállítva, akkor a kubelet (és a tároló futási ideje) kényszeríti ezt. A futási környezet nem teszi lehetővé, hogy a tároló a megadott erőforráskorlátnál többet használjon. Például, amikor egy folyamat egy tárolóban a megengedettnél több memóriát próbál meg felhasználni, a rendszermag „memória hiánya” (OOM) hibával fejezi be a folyamatot.

Egy tároló mindig több erőforrást használhat fel, mint amennyit az erőforráskérésben megadtunk, de soha nem használhat többet a korlátban megadottnál. Ezt az értéket nehéz helyesen beállítani, de nagyon fontos.

Ideális esetben azt szeretnénk, ha a pod erőforrásigénye a folyamat életciklusa során változna anélkül, hogy zavarná a rendszer más folyamatait – ez a korlátok felállításának célja.

Sajnos nem tudok konkrét utasítást adni, hogy milyen értékeket állítsunk be, de mi magunk betartjuk az alábbi szabályokat:

  1. Egy terheléstesztelő eszköz segítségével szimuláljuk a forgalom alapszintjét, és figyeljük a pod erőforrások (memória és processzor) használatát.
  2. A pod kéréseket tetszőlegesen alacsony értékre állítjuk (a kérések értékének kb. 5-szöröse erőforráskorláttal), és megfigyeljük. Ha túl alacsony a kérések száma, a folyamat nem indul el, ami gyakran rejtélyes Go futásidejű hibákat okoz.

Vegye figyelembe, hogy a magasabb erőforráskorlátok megnehezítik az ütemezést, mivel a pod-nak olyan célcsomópontra van szüksége, amely elegendő erőforrással rendelkezik.

Képzeljen el egy olyan helyzetet, amikor egy könnyű webszerver nagyon magas erőforrás-korláttal, mondjuk 4 GB memóriával. Ezt a folyamatot valószínűleg vízszintesen kell skálázni, és minden új modult legalább 4 GB szabad memóriával rendelkező csomóponton kell ütemezni. Ha nem létezik ilyen csomópont, a fürtnek új csomópontot kell bevezetnie a pod feldolgozásához, ami eltarthat egy ideig. A gyors és zökkenőmentes méretezés érdekében fontos, hogy az erőforráskérések és -korlátok közötti különbséget a lehető legkisebbre csökkentsük.

Második lépés: Élesség és készenléti tesztek beállítása

Ez egy másik finom téma, amelyet gyakran vitatnak meg a Kubernetes közösségben. Fontos, hogy jól ismerjük az Életesség- és Készenléti teszteket, mivel ezek biztosítják a szoftver zökkenőmentes működését és minimalizálják az állásidőt. Azonban, ha nem megfelelően konfigurálják, komoly teljesítménycsökkenést okozhatnak az alkalmazásban. Az alábbiakban összefoglaljuk, milyen mindkét minta.

Életképesség megmutatja, hogy a tároló fut-e. Ha ez meghiúsul, a kubelet megsemmisíti a tárolót, és engedélyezi az újraindítási házirendet. Ha a konténer nincs felszerelve Liveness szondával, akkor az alapértelmezett állapot sikeres lesz - ez áll benne Kubernetes dokumentáció.

A Liveness szondáknak olcsónak kell lenniük, vagyis nem szabad sok erőforrást fogyasztaniuk, mert gyakran futnak, és tájékoztatniuk kell a Kuberneteset, hogy az alkalmazás fut.

Ha beállítja a másodpercenkénti futást, akkor másodpercenként 1 kérést ad hozzá, ezért ügyeljen arra, hogy a forgalom kezeléséhez további erőforrásokra lesz szükség.

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

Az alkalmazásokat "egészségügyi" végponttal konfiguráltuk, amely egyszerűen 200-as válaszkódot ad vissza. Ez azt jelzi, hogy a folyamat fut, és képes a kérések (de még nem a forgalom) feldolgozására.

teszt Készenlét jelzi, hogy a tároló készen áll-e a kérések kiszolgálására. Ha a készenléti vizsgálat meghiúsul, a végpontvezérlő eltávolítja a pod IP-címét a pod-nak megfelelő összes szolgáltatás végpontjáról. Ez a Kubernetes dokumentációjában is szerepel.

A készenléti próbák több erőforrást fogyasztanak, mert azokat úgy kell elküldeni a háttérrendszernek, hogy jelezze, hogy az alkalmazás készen áll a kérések fogadására.

Sok vita folyik a közösségben arról, hogy közvetlenül hozzá kell-e férni az adatbázishoz. Tekintettel a többletköltségre (az ellenőrzéseket gyakran hajtják végre, de módosíthatók), úgy döntöttünk, hogy egyes alkalmazásoknál a forgalom kiszolgálására való készséget csak az adatbázisból való rekordok visszaküldése után számolja a rendszer. A jól megtervezett készenléti próbák magasabb szintű rendelkezésre állást biztosítottak, és kiküszöbölték a leállásokat a telepítés során.

Ha úgy dönt, hogy lekérdezi az adatbázist, hogy tesztelje az alkalmazás készenlétét, ügyeljen arra, hogy az a lehető legolcsóbb legyen. Vegyük ezt a kérést:

SELECT small_item FROM table LIMIT 1

Íme egy példa arra, hogyan konfiguráljuk ezt a két értéket a Kubernetesben:

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

Hozzáadhat néhány további konfigurációs lehetőséget:

  • initialDelaySeconds — hány másodperc telik el a tartály elindítása és a mintavétel kezdete között.
  • periodSeconds — várakozási idő a mintafuttatások között.
  • timeoutSeconds — az a másodperc, amely után az egység vészhelyzetnek minősül. Rendszeres időkorlát.
  • failureThreshold — a teszthibák száma, mielőtt újraindítási jelet küldenek a podra.
  • successThreshold — a sikeres szondák száma, mielőtt a pod kész állapotba kerül (hiba után, amikor a pod elindul vagy helyreáll).

Harmadik lépés: alapértelmezett hálózati házirendek beállítása a podhoz

A Kubernetes „lapos” hálózati topográfiával rendelkezik; alapértelmezés szerint az összes pod közvetlenül kommunikál egymással. Egyes esetekben ez nem kívánatos.

Lehetséges biztonsági probléma, hogy a támadó egyetlen sebezhető alkalmazással forgalmat küldhet a hálózat összes podjára. Mint a biztonság számos területén, itt is a legkisebb kiváltság elve érvényesül. Ideális esetben a hálózati házirendeknek kifejezetten meg kell határozniuk, hogy a podok között mely kapcsolatok engedélyezettek és melyek nem.

Például az alábbiakban egy egyszerű házirendet mutatunk be, amely megtagadja az összes bejövő forgalmat egy adott névtérben:

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

Ennek a konfigurációnak a megjelenítése:

Öt kihagyás az első alkalmazás Kubernetesen történő üzembe helyezésekor
(https://miro.medium.com/max/875/1*-eiVw43azgzYzyN1th7cZg.gif)
További részletek itt.

Negyedik lépés: egyéni viselkedés hook-ok és init-tárolók használatával

Egyik fő célunk az volt, hogy a Kubernetes telepítését leállás nélkül biztosítsuk a fejlesztők számára. Ez nehéz, mert számos lehetőség kínálkozik az alkalmazások leállítására és az általuk használt erőforrások felszabadítására.

Különös nehézségek adódtak nginx. Észrevettük, hogy amikor ezeket a podokat egymás után telepítették, az aktív kapcsolatok megszakadtak a sikeres befejezés előtt.

Kiterjedt online kutatás után kiderült, hogy a Kubernetes nem várja meg, hogy az Nginx-kapcsolatok kimerüljenek a pod leállítása előtt. Egy pre-stop horog segítségével a következő funkciókat valósítottuk meg, és teljesen megszabadultunk az állásidőtől:

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

De 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 bizonyos alkalmazások indításának kezelésére. Ez különösen akkor hasznos, ha erőforrás-igényes adatbázis-áttelepítési folyamata van, amelynek le kell futnia az alkalmazás indítása előtt. Magasabb erőforrás-korlátot is megadhat ehhez a folyamathoz anélkül, hogy a fő alkalmazáshoz ilyen korlátot állítana be.

Egy másik elterjedt séma a titkok elérése egy olyan indítótárolóban, amely a fő modul számára biztosítja a hitelesítési adatokat, ami megakadályozza, hogy magából a fő alkalmazásmodulból származó titkok illetéktelenül hozzáférjenek.

Szokás szerint idézzen a dokumentációból: Az Init tárolók biztonságosan futtatnak egyéni kódot vagy segédprogramokat, amelyek egyébként csökkentenék az alkalmazástároló lemezképének biztonságát. A szükségtelen eszközök elkülönítésével korlátozza az alkalmazástároló képének támadási felületét.

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

Végül beszéljünk egy fejlettebb technikáról.

A Kubernetes egy rendkívül rugalmas platform, amely lehetővé teszi a munkaterhelések tetszés szerinti futtatását. Számos nagy teljesítményű alkalmazásunk van, amelyek rendkívül erőforrás-igényesek. Kiterjedt terhelési tesztelés után felfedeztük, hogy az egyik alkalmazás nehezen kezelte a várható forgalmi terhelést, amikor a Kubernetes alapértelmezett beállításai érvényben voltak.

A Kubernetes azonban lehetővé teszi olyan privilegizált tároló futtatását, amely csak egy adott pod esetében módosítja a kernelparamétereket. A nyitott kapcsolatok maximális számának módosításához a következőket használtuk:

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

Ez egy fejlettebb technika, amelyre gyakran nincs szükség. De ha az alkalmazás nehezen tud megbirkózni a nagy terhelésekkel, megpróbálhatja módosítani ezen beállítások némelyikét. További részletek erről a folyamatról és a különböző értékek beállításáról - mint mindig a hivatalos dokumentációban.

Összefoglalva

Bár a Kubernetes kész megoldásnak tűnhet, néhány kulcsfontosságú lépést meg kell tennie az alkalmazások zökkenőmentes működéséhez.

A Kubernetes-migráció során fontos betartani a „terhelési tesztelési ciklust”: indítsa el az alkalmazást, töltse le, figyelje meg a mutatókat és a méretezési viselkedést, állítsa be a konfigurációt ezen adatok alapján, majd ismételje meg a ciklust.

Legyen reális a várható forgalommal kapcsolatban, és próbáljon túllépni azon, hogy megtudja, mely összetevők törnek el először. Ezzel az iteratív megközelítéssel a felsorolt ​​ajánlások közül csak néhány elég lehet a sikerhez. Vagy mélyebb testreszabást igényelhet.

Mindig tedd fel magadnak ezeket a kérdéseket:

  1. Hány erőforrást fogyasztanak az alkalmazások, és hogyan változik ez a mennyiség?
  2. Mik a valós méretezési követelmények? Átlagosan mekkora forgalmat bonyolít le az alkalmazás? Mi a helyzet a csúcsforgalommal?
  3. Milyen gyakran kell a szolgáltatást vízszintesen méretezni? Milyen gyorsan kell az új podkat online hozni a forgalom fogadásához?
  4. Hogyan kapcsolnak le helyesen a hüvelyek? Szükséges ez egyáltalán? Elérhető-e leállás nélkül a telepítés?
  5. Hogyan csökkentheti minimálisra a biztonsági kockázatokat, és korlátozhatja a kompromittált tokok okozta károkat? Vannak olyan szolgáltatások, amelyek nem igényelnek engedélyeket vagy hozzáférést?

A Kubernetes egy hihetetlen platformot biztosít, amely lehetővé teszi a bevált gyakorlatok kihasználását több ezer szolgáltatás fürtben történő telepítéséhez. Azonban minden alkalmazás más. Néha a megvalósítás egy kicsit több munkát igényel.

Szerencsére a Kubernetes biztosítja az összes technikai cél eléréséhez szükséges konfigurációt. Az erőforráskérések és -korlátok, az Életképesség és a Készenlét próbák, az init-tárolók, a hálózati házirendek és az egyéni kernelhangolás kombinációjával nagy teljesítményt érhet el, hibatűréssel és gyors skálázhatósággal együtt.

Mit kell még olvasni:

  1. Bevált gyakorlatok és bevált gyakorlatok a konténerek és a Kubernetes üzemeltetéséhez gyártási környezetben.
  2. 90+ hasznos eszköz a Kuberneteshez: telepítés, kezelés, megfigyelés, biztonság és egyebek.
  3. A Kubernetes körüli csatornánk a Telegramban.

Forrás: will.com

Hozzászólás