A probléma rövid áttekintése
Egy nap, a k8s-fürt tervezett frissítése során felfedeztük, hogy szinte az összes POD-unk (1000-ből körülbelül 500) az új csomópontokon nem tudott elindulni, és a percek gyorsan órákká váltak. Aktívan keressük a kiváltó okot, de három óra elteltével a PODS-ek még mindig ContainerCreating
állapotban voltak.
Szerencsére ez nem a prod környezet volt, és a karbantartási időszakot a hétvégére ütemezték. Volt időnk nyomás nélkül kivizsgálni a kérdést.
Hol kezdje a kiváltó ok keresését? Szeretne többet megtudni az általunk talált megoldásról? Kapcsold be és élvezd!
További részletek a problémáról
A probléma az volt, hogy nagyszámú docker-képünk volt, amelyeket egyszerre kellett lehúzni és elindítani a fürt minden csomópontján. Ennek az az oka, hogy az egy csomóponton végzett többszöri, egyidejű dokkolókép-letöltés magas lemezkihasználáshoz és meghosszabbított hidegindítási időhöz vezethet.
A CD-feldolgozás időnként akár 3 órát is igénybe vesz a képek előhívásához. Ezúttal azonban ez teljesen elakadt, mert az EKS frissítés során (inline, amikor a fürt összes csomópontját cseréljük) túl magas volt a PODS mennyisége.
Minden alkalmazásunk a k8s-ban él ( EKS alapú). A DEV env költségeinek megtakarítása érdekében spot példányokat használunk.
A csomópontokhoz az AmazonLinux2 képet használjuk.
A fejlesztői környezetben számos szolgáltatási ág (FB) található, amelyeket folyamatosan telepítünk Kubernetes-fürtünkre. Minden FB-nek megvannak a saját alkalmazáskészletei, és minden alkalmazásnak megvannak a saját függőségei (egy képen belül).
Projektünkben közel 200 alkalmazás, és ez a szám növekszik. Mindegyik alkalmazás a 7 ~2 GB méretű docker alapkép egyikét használja. Az archivált kép maximális teljes mérete (az ECR -ben) körülbelül 3 GB.
Az összes képet az Amazon Elastic Container Registry (ECR) tárolja.
A csomópontokhoz az alapértelmezett gp3 EBS kötettípust használjuk.
Problémák
Meghosszabbított hidegindítási idő: Egy új képsor új indítása több mint 1 órát is igénybe vehet, különösen akkor, ha több képet húznak egyszerre egy csomóponton.
ErrImagePull hibák: Gyakori
ErrImagePull
vagy beragad aContainerCreating
állapotoknál, ami a képlehívással kapcsolatos problémákra utal.Magas lemezkihasználás: A lemezkihasználtság 100% közelében marad a képletöltési folyamat során, elsősorban a kibontáshoz szükséges intenzív lemez I/O miatt (pl. „unpigz”).
System DaemonSet problémák: Egyes rendszer DaemonSets (például
aws-node
vagyebs-csi-node
) "nem kész" állapotba került a lemeznyomás miatt, ami befolyásolja a csomópont készenlétét.Nincs képgyorsítótár a csomópontokon: Mivel spot példányokat használunk, nem használhatjuk a helyi lemezt a képek gyorsítótárazására.
Ez sok elakadt központi telepítést eredményez a szolgáltatási ágakon, különösen azért, mert a különböző FB-k eltérő alapképkészletekkel rendelkeznek.
Gyors vizsgálat után azt találtuk, hogy a fő probléma az unpigz
folyamat által a csomópontokra nehezedő lemeznyomás volt. Ez a folyamat felelős a docker képek kicsomagolásáért. A gp3 EBS kötettípus alapbeállításait nem változtattuk meg, mert esetünkben nem megfelelőek.
Gyorsjavítás a fürt helyreállításához
Első lépésként úgy döntöttünk, hogy csökkentjük a POD-ok számát a csomópontokon.
- Az új csomópontokat „Cordon” állapotba helyezzük
- Távolítson el minden elakadt PODS-t a lemeznyomás csökkentése érdekében
- Futtassa egyenként a POD-okat a csomópontok bemelegítéséhez
- Ezt követően a felmelegedett csomópontokat normál állapotba ("unCordon") mozgatjuk.
- Az összes beragadt állapotú csomópont eltávolítva
- Az összes PODS sikeresen elkezdte használni a Docker kép-gyorsítótárat
Eredeti CI/CD dizájn
A megoldás fő ötlete az, hogy a CD-folyamat megkezdése előtt felmelegítsük a csomópontokat a docker image (JS függőségi réteg) legnagyobb részével, amely az összes alkalmazásunk gyökérképeként használható. Legalább 7 fajta gyökérképünk van a JS-függőségekkel, amelyek az alkalmazás típusához kapcsolódnak. Tehát elemezzük az eredeti CI/CD dizájnt.
CI/CD folyamatunkban 3 pillérünk van:
Eredeti CI/CD csővezeték:
Az
Init
it lépésben: előkészítjük a környezetet/változókat, meghatározzuk az újraépítendő képek halmazát, stb...Az
Build
lépésben: megépítjük a képeket, és eltoljuk őket az ECR-hezA
Deploy
lépésnél: telepítjük a képeket a k8s-ba (frissítési telepítések stb.)
További részletek az eredeti CICD dizájnról:
- Szolgáltatási fiókjaink (FB) a
main
ágból kiágaztak. A CI folyamatban mindig elemezzük az FB-ben módosított képkészletet, és újraépítjük azokat. Amain
ág mindig stabil, a definíció szerint mindig az alapképek legfrissebb verziójának kell lennie. - Külön építjük fel a JS-függőségek docker-képeit (minden környezethez), és továbbítjuk az ECR-hez, hogy újra felhasználhassuk gyökér (alap) képként a Dockerfile-ban. Körülbelül 5–10 típusú JS-függőségi dokkolókép áll rendelkezésünkre.
- Az FB a k8s fürtbe kerül a külön névtérbe, de az FB közös csomópontjaiba. Az FB-n ~200 alkalmazás lehet, a képméret akár 3 GB is lehet.
- Rendelkezünk a fürt automatikus skálázó rendszerével, amely a terhelés vagy a függőben lévő PODS-ek alapján skálázza a fürt csomópontjait a megfelelő nodeSelectorral és toleranciával.
- A csomópontokhoz a spot példányokat használjuk.
A bemelegítési folyamat végrehajtása
A bemelegítési folyamatnak vannak követelményei.
Kötelező:
- Problémamegoldás : Megoldja és megoldja
ContainerCreating
problémákat. - Továbbfejlesztett teljesítmény : Jelentősen csökkenti az indítási időt az előmelegített alapképek (JS-függőségek) használatával.
Örülök, hogy vannak fejlesztések:
- Rugalmasság : Lehetővé teszi a csomópont típusának és élettartamának egyszerű megváltoztatását (pl. magas SLA vagy hosszabb élettartam).
- Átlátszóság : Világos mérőszámokat biztosít a használatról és a teljesítményről.
- Költséghatékonyság : Költséget takarít meg a VNG azonnali törlésével, miután a kapcsolódó szolgáltatási ágat törölték.
- Izoláció : Ez a megközelítés biztosítja, hogy más környezeteket ne érintsen.
Megoldás
A követelmények és megszorítások elemzése után úgy döntöttünk, hogy egy bemelegítő folyamatot hajtunk végre, amely előmelegíti a csomópontokat az alap JS gyorsítótár-képekkel. Ez a folyamat a CD-folyamat megkezdése előtt indul el, biztosítva, hogy a csomópontok készen álljanak az FB telepítésére, és maximális esélyünk legyen a gyorsítótár eléréséhez.
Ezt a fejlesztést nagy lépésekre bontjuk:
Hozza létre a csomópontok készletét (virtuális csomópontcsoport) minden egyes FB-nként
Adjon hozzá alapképeket az új csomópontok felhő-init parancsfájljához
Adjon hozzá egy telepítés előtti lépést a DaemonSet futtatásához az
initContainers
szakaszsal, hogy a CD-folyamat megkezdése előtt letöltse a szükséges dokkolóképeket a csomópontokra.
Egy frissített CI/CD folyamat így néz ki:
Frissített CI/CD folyamat:
- Init lépés
1.1. (új lépés) Telepítés megkezdése : Ha ez az FB első indítása, akkor hozzon létre egy új személyes csomópont-példánykészletet (a mi fogalmaink szerint ez Virtual Node Group vagy VNG), és töltse le az összes JS alapképet (5–10 kép). ) a főágról. Elég jogos megtenni, mert elágaztuk a FB-t a főfiókból. Fontos szempont, hogy ez nem blokkoló művelet. - Építési lépés
- Telepítés előtti lépés Töltse le a frissen elkészített JS-alapképeket az adott FB-címkével az ECR-ből.
3.1.(új lépés) Fontos tudnivalók : Ez egy blokkoló művelet, mert csökkenteni kell a lemeznyomást. Egyesével letöltjük az alapképeket minden kapcsolódó csomóponthoz.
Btw, köszönjük az „ init deploy” lépést, már megvannak az alap docker image-ek a főágból, vagyis nagy esélyünk van arra, hogy az első indításkor elérjük a gyorsítótárat. - ** Telepítés
** Ebben a lépésben nincs változás. De az előző lépésnek köszönhetően már minden nehéz docker képrétegünk van a szükséges csomópontokon.
Init telepítési lépés
Hozzon létre egy új csomópontkészletet minden egyes FB-hez API-híváson keresztül (a harmadik fél automatikus skálázó rendszeréhez) a CI-folyamatból.
Megoldott problémák:
Izoláció : Minden FB-nek saját csomópontkészlete van, biztosítva, hogy a környezetet ne befolyásolják más FB-k.
Rugalmasság : Könnyen megváltoztathatjuk a csomópont típusát és élettartamát.
Költséghatékonyság : Az FB törlése után azonnal törölhetjük a csomópontokat.
Átlátszóság : Könnyen nyomon követhetjük a csomópontok használatát és teljesítményét (minden csomóponton van egy FB-hez kapcsolódó tag).
A spot példányok hatékony használata : A spot példány már előre definiált alapképekkel indul, vagyis a spot csomópont indulása után már ott vannak az alapképek a csomóponton (a fő ágból).
Töltse le az összes JS-alapképet a fő ágból az új csomópontokba cloud-init
parancsfájl segítségével.
Amíg a képek letöltése folyamatban van a háttérben, a CD-folyamat gond nélkül folytathatja az új képek létrehozását. Sőt, ebből a csoportból a következő csomópontok (amelyeket az automatikus skálázási rendszer hoz létre) a frissített cloud-init
adatokkal jönnek létre, amelyek már rendelkeznek utasításokkal a képek letöltéséhez az indítás előtt.
Megoldott problémák:
Problémamegoldás : A lemeznyomás megszűnt, mert frissítettük a
cloud-init
szkriptet az alapképek letöltésének hozzáadásával a fő ágból. Ez lehetővé teszi, hogy az FB első indításakor elérjük a gyorsítótárat.A helyszíni példányok hatékony használata : A helyszíni példány frissített
cloud-init
adatokkal indul. Ez azt jelenti, hogy a spot csomópont indulása után már ott vannak az alapképek a csomóponton (a fő ágból).Továbbfejlesztett teljesítmény : A CD-folyamat gond nélkül folytathatja az új lemezképek létrehozását.
Ez a művelet körülbelül 17 másodpercet (API-hívást) adott a CI/CD folyamatunkhoz.
Ennek a műveletnek csak az első alkalommal van értelme, amikor elindítjuk az FB-t. Legközelebb a már meglévő csomópontokra telepítjük alkalmazásainkat, amelyek már rendelkeznek az előző telepítéskor szállított alapképekkel.
Telepítés előtti lépés
Erre a lépésre azért van szükségünk, mert az FB képek eltérnek a fő ágképektől. A CD-folyamat megkezdése előtt le kell töltenünk az FB alapképeket a csomópontokra. Ez segít csökkenteni a hosszabb hidegindítási időket és a magas lemezkihasználást, amely akkor fordulhat elő, ha több nehéz képet egyszerre húznak ki.
A bevezetés előtti lépés céljai
Lemeznyomás megelőzése : A docker legnehezebb képeinek szekvenciális letöltése. Az init-deploy lépés után már megvannak az alapképek a csomópontokon, ami azt jelenti, hogy nagy esélyünk van a találati gyorsítótárra.
A telepítési hatékonyság javítása : Győződjön meg róla, hogy a csomópontok előmelegítve vannak az alapvető docker-képekkel, ami gyorsabb (szinte azonnali) POD-indítási időt eredményez.
Stabilitás növelése : Csökkentse az
ErrImagePull
/ContainerCreating
hibák előfordulásának esélyét, és biztosítsa, hogy a rendszerdémonkészletek „kész” állapotban maradjanak.
Ebben a lépésben 10–15 percet adunk a CD-folyamathoz.
Telepítés előtti lépés részletei:
- A CD-n létrehozunk egy DaemonSet-et az
initContainers
szekcióval. - Az
initContainers
szakasz a fő tároló elindulása előtt lefut, biztosítva, hogy a szükséges képek letöltésre kerüljenek a fő tároló indulása előtt. - A CD-n folyamatosan ellenőrizzük a daemonSet állapotát. Ha a daemonSet „kész” állapotban van, akkor folytatjuk a telepítést. Ellenkező esetben megvárjuk, amíg a daemonSet készen áll.
Összehasonlítás
Az eredeti és frissített lépések összehasonlítása az előmelegítési folyamattal.
Lépés | Init telepítési lépés | Telepítés előtti lépés | Telepítés | Teljes idő | Diff |
---|---|---|---|---|---|
Előmelegítés nélkül | 0 | 0 | 11h 21s | 11h 21s | 0 |
Előmelegítéssel | 8 másodperc | 58 másodperc | 25 másodperc | 1h 31s | -9m 50s |
A lényeg, hogy a „Deploy” idő megváltozott (az első alkalmazás parancstól a podok futási állapotáig) 11 perc 21 másodpercről 25 másodpercre. A teljes idő 11 óra 21 másodpercről 1 óra 31 másodpercre változott.
Fontos szempont, hogy ha nincsenek alapképek a fő ágból, akkor a „Deploy” ideje megegyezik az eredeti időponttal, vagy kicsit több. De mindenesetre megoldottuk a lemeznyomással és a hidegindítási idővel kapcsolatos problémát.
Következtetés
A ContainerCreating
fő problémáját a bemelegítési folyamat megoldotta. Előnyként jelentősen csökkentettük a POD-ok hidegindítási idejét.
A lemeznyomás megszűnt, mert már megvannak az alapképek a csomópontokon. A rendszer démonSets „kész” és „egészséges” állapotban van (mivel nincs lemeznyomás), és nem találkoztunk ezzel a problémával kapcsolatos ErrImagePull
hibával.
Lehetséges megoldások és linkek
- Használjon igény szerinti példányokat a csomópontokhoz a helyszíni példányok helyett
Nem használhatjuk ezt a módot, mert ez nem tartozik a nem gyártási környezetekre szánt költségvetésünkbe. - Használja az Amazon EBS gp3 (vagy jobb) kötettípust a megnövelt IOPS-sel
Nem használhatjuk ezt a módot, mert ez a funkció nem gyártási környezetekre is kikerül a költségvetésünk keretéből. Ezenkívül az AWS régiónként határozza meg az IOPS-t a fiókjában. - Csökkentse a konténer indítási idejét az Amazon EKS rendszeren a Bottlerocket adatmennyiséggel
Tulajdonképpen nem tudunk ezen az úton haladni, mert túl nagy hatással van a termelésre és más környezetekre, de egyben jó megoldás a problémánkra. - A Kubernetes Cluster Autoscaler hibaelhárítása 1 órába telik a 600 sorba skálázáshoz
PS: Szeretnék köszönetet mondani a Justt nagyszerű technikai csapatának ( https://www.linkedin.com/company/justt-ai ) fáradhatatlan munkájukért és igazán kreatív hozzáállásukért minden problémához, amellyel szembesülnek. vel. Különösen Ronny Sharaby-nak, a kiváló vezetőnek, aki felelős a csapat által végzett nagyszerű munkáért. Alig várom, hogy egyre több nagyszerű példát láthassak arra vonatkozóan, hogy az Ön kreativitása hogyan hat a Justt termékre.