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!
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.
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 a ContainerCreating
á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
vagy ebs-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.
Első lépésként úgy döntöttünk, hogy csökkentjük a POD-ok számát a csomópontokon.
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-hez
A 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:
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. A main
ág mindig stabil, a definíció szerint mindig az alapképek legfrissebb verziójának kell lennie.A bemelegítési folyamatnak vannak követelményei.
Kötelező:
ContainerCreating
problémákat.Örülök, hogy vannak fejlesztések:
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.
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.
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:
initContainers
szekcióval.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.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.
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.
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.