
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 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 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 : 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:
- 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.
- 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 .
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:

(https://miro.medium.com/max/875/1*-eiVw43azgzYzyN1th7cZg.gif)
Részletesebben .
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 kapcsá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 .
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:
- Mennyi erőforrást fogyasztanak az alkalmazások, és ez hogyan változik majd?
- 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?
- 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?
- 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?
- 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:
- .
- .
- .
Forrás: habr.com
