Naplózás a Kubernetesben (és nem csak) ma: elvárások és valóság
2019 van, és még mindig nincs szabványos megoldásunk a naplóösszesítéshez a Kubernetesben. Ebben a cikkben valós gyakorlatból vett példákon keresztül szeretnénk megosztani kereséseinket, felmerült problémáinkat és azok megoldásait.
Először azonban leszögezem, hogy a különböző ügyfelek nagyon különböző dolgokat értenek a naplók gyűjtésével:
valaki biztonsági és ellenőrzési naplókat szeretne látni;
valaki - a teljes infrastruktúra központosított naplózása;
és egyesek számára elegendő csak az alkalmazásnaplókat gyűjteni, kivéve például az egyensúlyozókat.
Az alábbiakban bemutatjuk, hogyan valósítottuk meg a különféle „kívánságlistákat”, és milyen nehézségekbe ütköztünk.
Elmélet: a naplózó eszközökről
A naplózó rendszer összetevőinek háttere
A naplózás nagy utat tett meg, melynek eredményeként a naplók gyűjtésének és elemzésének módszertanát fejlesztették ki, amit ma is használunk. Még az 1950-es években a Fortran bevezette a szabványos bemeneti/kimeneti adatfolyamok analógját, ami segített a programozónak a program hibakeresésében. Ezek voltak az első számítógépes naplók, amelyek megkönnyítették az akkori programozók életét. Ma bennük látjuk a naplózási rendszer első összetevőjét - a rönkök forrása vagy „előállítója”..
A számítástechnika nem állt meg: megjelentek a számítógépes hálózatok, az első klaszterek... Több számítógépből álló összetett rendszerek kezdtek működni. Mostantól a rendszergazdák kénytelenek voltak több gépről naplót gyűjteni, és speciális esetekben OS kernel üzeneteket is hozzáadhattak, ha rendszerhibát kellett kivizsgálniuk. A központosított naplógyűjtő rendszerek leírására a 2000-es évek elején megjelent RFC 3164, amely szabványosította a remote_syslogot. Így jelent meg egy másik fontos komponens: rönkgyűjtő és tárolásuk.
A naplók mennyiségének növekedésével és a webes technológiák széles körű bevezetésével felmerült a kérdés, hogy milyen naplókat kell kényelmesen megjeleníteni a felhasználóknak. Az egyszerű konzoleszközöket (awk/sed/grep) fejlettebbek váltották fel naplónézők - harmadik komponens.
A rönk mennyiségének növekedése miatt más is világossá vált: rönk kell, de nem mindegyik. A különböző rönkök pedig eltérő megőrzési szintet igényelnek: egyesek egy nap alatt elveszhetnek, míg másokat 5 évig kell tárolni. Tehát az adatfolyamok szűrésére és irányítására szolgáló komponens hozzáadásra került a naplózó rendszerhez - nevezzük így szűrő.
A tárolás is nagy ugrást hajtott végre: a normál fájloktól a relációs adatbázisokig, majd a dokumentum-orientált tárolásig (például Elasticsearch). Így a tárolót leválasztották a kollektorról.
Végül a rönk fogalma egyfajta absztrakt eseményfolyammá bővült, amelyet meg akarunk őrizni a történelem számára. Vagy inkább arra az esetre, ha vizsgálatot kell végeznie, vagy elemző jelentést kell készítenie...
Ennek eredményeként viszonylag rövid idő alatt a naplógyűjtés egy fontos alrendszerré fejlődött, amelyet joggal nevezhetünk a Big Data egyik alszekciójának.
Ha régen a közönséges nyomatok is elegendőek voltak egy „naplózó rendszerhez”, most a helyzet sokat változott.
Kubernetes és naplók
Amikor a Kubernetes az infrastruktúrához került, a naplógyűjtés már meglévő problémája sem kerülte meg. Bizonyos szempontból ez még fájdalmasabbá vált: az infrastruktúra platform menedzselése nemcsak leegyszerűsödött, de egyben bonyolult is lett. Sok régi szolgáltatás megkezdte a mikroszolgáltatásokba való átállást. A naplókkal összefüggésben ez megmutatkozik a naplóforrások növekvő számában, speciális életciklusában, valamint az összes rendszerelem kapcsolatának naplókon keresztüli nyomon követésében...
A jövőre nézve kijelenthetem, hogy jelenleg sajnos nincs olyan szabványos naplózási lehetőség a Kubernetes számára, amely az összes többihez képest kedvező lenne. A közösségben a legnépszerűbb programok a következők:
valaki kitekeri a köteget EFK (Elasticsearch, Fluentd, Kibana);
Mindazonáltal nem foglalkozom a telepítési és konfigurációs utasításokkal. Ehelyett az ő hiányosságaikra és általában a rönkök helyzetére vonatkozó globálisabb következtetésekre fogok összpontosítani.
Gyakorolj rönkökkel K8-ban
„Mindennapi naplók”, hányan vagytok?...
A naplók központosított gyűjtése egy meglehetősen nagy infrastruktúrából jelentős erőforrásokat igényel, amelyeket a naplók gyűjtésére, tárolására és feldolgozására fordítanak. A különböző projektek működése során különféle követelményekkel és az azokból adódó működési problémákkal szembesültünk.
Próbáljuk ki a ClickHouse-t
Nézzünk meg egy központi tárhelyet egy projekten egy olyan alkalmazással, amely meglehetősen aktívan generál naplókat: több mint 5000 sor másodpercenként. Kezdjünk el dolgozni a naplóival, és adjuk hozzá őket a ClickHouse-hoz.
Amint a maximális valós időre van szükség, a ClickHouse-szal rendelkező 4 magos szerver már túlterhelődik a lemez alrendszerén:
Ez a fajta betöltés annak köszönhető, hogy a lehető leggyorsabban igyekszünk a ClickHouse-ban írni. És erre az adatbázis megnövekedett lemezterheléssel reagál, ami a következő hibákat okozhatja:
DB::Exception: Too many parts (300). Merges are processing significantly slower than inserts
Tény az, hogy a MergeTree táblák a ClickHouse-ban (naplóadatokat tartalmaznak) saját nehézségeik vannak az írási műveletek során. A beléjük szúrt adatok egy ideiglenes partíciót generálnak, amelyet aztán egyesítenek a főtáblával. Ennek eredményeként a rögzítés nagyon megterhelőnek bizonyul a lemezen, és vonatkozik rá az a korlátozás is, amelyről fentebb kaptunk értesítést: legfeljebb 1 alpartíció egyesíthető 300 másodperc alatt (ez valójában 300 beillesztés). másodpercenként).
Ennek a viselkedésnek a elkerülése érdekében írjon a ClickHouse-nak lehetőleg nagyobb darabokban és legfeljebb 1 másodpercenként 2 alkalommal. A nagy sorozatokban történő írás azonban azt sugallja, hogy a ClickHouse-ban ritkábban írjunk. Ez viszont puffer túlcsorduláshoz és a naplók elvesztéséhez vezethet. A megoldás a Fluentd puffer növelése, de akkor a memóriafelhasználás is megnő.
Megjegyzés: A ClickHouse megoldásunk másik problémás aspektusa az volt, hogy a particionálás esetünkben (rönkház) külső táblákon keresztül valósul meg. Egyesítés táblázat. Ez oda vezet, hogy nagy időintervallumok mintavételezésekor túlzott RAM-ra van szükség, mivel a metatábla minden partíción keresztül iterál - még azokon is, amelyek nyilvánvalóan nem tartalmazzák a szükséges adatokat. Most azonban ez a megközelítés biztonságosan elavulttá nyilvánítható a ClickHouse jelenlegi verzióinál (c 18.16).
Ennek eredményeként világossá válik, hogy nem minden projekt rendelkezik elegendő erőforrással a naplók valós időben történő összegyűjtésére a ClickHouse-ban (pontosabban, hogy elosztásuk nem lesz megfelelő). Ezenkívül használnia kell аккумулятор, amelyre később visszatérünk. A fent leírt eset valós. És akkor még nem tudtunk olyan megbízható és stabil megoldást kínálni, amely megfelelne az ügyfélnek, és minimális késéssel gyűjthetnénk össze a rönköket...
Mi a helyzet az Elasticsearch-vel?
Az Elasticsearch köztudottan nagy munkaterhelést is képes kezelni. Próbáljuk meg ugyanabban a projektben. Most a terhelés így néz ki:
Az Elasticsearch meg tudta emészteni az adatfolyamot, azonban az ilyen kötetek ráírása nagymértékben igénybe veszi a CPU-t. Ezt egy klaszter szervezésével döntik el. Technikailag ez nem probléma, de kiderült, hogy csak a naplógyűjtő rendszer működtetéséhez már körülbelül 8 magot használunk, és van egy további nagy terhelésű komponens a rendszerben...
A lényeg: ez a lehetőség indokolt lehet, de csak akkor, ha a projekt nagy és a vezetése kész jelentős erőforrásokat fordítani egy központi naplózási rendszerre.
Ekkor felvetődik egy természetes kérdés:
Milyen naplókra van szükség valójában?
Próbáljuk megváltoztatni magát a megközelítést: a naplóknak egyszerre kell informatívnak lenniük, és nem fedniük kell minden esemény a rendszerben.
Tegyük fel, hogy van egy sikeres webáruházunk. Milyen naplók fontosak? Nagyon jó ötlet a lehető legtöbb információt összegyűjteni, például egy fizetési átjáróról. A termékkatalógusban szereplő képszeletelő szolgáltatásból származó összes napló azonban nem kritikus számunkra: csak a hibák és a fejlett megfigyelés elegendő (például az 500 hiba százalékos aránya, amelyet ez az összetevő generál).
Tehát arra a következtetésre jutottunk a központosított fakitermelés nem mindig indokolt. Nagyon gyakran az ügyfél az összes naplót egy helyen szeretné összegyűjteni, bár valójában a teljes naplóból a vállalkozás számára kritikus üzeneteknek csak feltételes 5%-ára van szükség:
Néha elég, ha mondjuk csak a konténernapló és a hibagyűjtő méretét állítjuk be (például Sentry).
Egy hibaértesítés és egy nagy helyi napló gyakran elegendő lehet az incidensek kivizsgálásához.
Voltak olyan projektjeink, amelyek kizárólag funkcionális teszteket és hibagyűjtő rendszereket alkalmaztak. A fejlesztőnek nem volt szüksége a naplókra – a hibanyomokból mindent láttak.
Illusztráció az életből
Egy másik történet jó példa lehet. Egy ügyfelünk biztonsági csapatától kérést kaptunk, aki már jóval a Kubernetes bevezetése előtt kifejlesztett kereskedelmi megoldást használt.
Szükséges volt „megbarátkozni” a központi naplógyűjtő rendszerrel a vállalati problémaérzékelő érzékelővel - QRadar. Ez a rendszer a syslog protokollon keresztül tud naplókat fogadni és lekérni az FTP-ről. Azonban nem lehetett azonnal integrálni a fluentd remote_syslog beépülő moduljával (mint kiderült, nem vagyunk egyedül). Kiderült, hogy a QRadar beállításával kapcsolatos problémák az ügyfél biztonsági csapatának oldalán vannak.
Ennek eredményeként az üzleti szempontból kritikus naplók egy része felkerült az FTP QRadar-ra, a másik része pedig távoli rendszernaplón keresztül került átirányításra közvetlenül a csomópontokból. Erre még írtunk is egyszerű diagram - talán segít valakinek megoldani egy hasonló problémát... Az így létrejött sémának köszönhetően a kliens maga is megkapta és elemezte a kritikus naplókat (kedvenc eszközeivel), és ezzel csökkenteni tudtuk a naplózó rendszer költségeit, így csak a múlt hónap.
Egy másik példa jól mutatja, mit ne tegyünk. Egyik ügyfelünk feldolgozásra mindegyikből a felhasználótól érkező, többsoros események strukturálatlan kimenet információ a naplóban. Ahogy sejteni lehetett, az ilyen naplók olvasása és tárolása egyaránt rendkívül kényelmetlen volt.
A rönkök kritériumai
Az ilyen példák arra a következtetésre vezetnek, hogy a naplógyűjtő rendszer kiválasztása mellett szükség van maguk a rönkök is megtervezhetők! Milyen követelmények vannak itt?
A naplóknak géppel olvasható formátumban kell lenniük (például JSON).
A naplóknak kompaktnak kell lenniük, és módosítani kell a naplózás mértékét a lehetséges problémák hibakeresése érdekében. Ugyanakkor éles környezetekben olyan naplózási szintű rendszereket kell futtatni, mint pl figyelmeztetés vagy hiba.
A naplókat normalizálni kell, vagyis egy naplóobjektumban minden sornak azonos mezőtípussal kell rendelkeznie.
A strukturálatlan naplók problémákat okozhatnak a naplók tárolóba való betöltésekor, és feldolgozásuk teljes leállását okozhatják. Illusztrációként álljon itt egy példa a 400-as hibával, amellyel sokan biztosan találkoztak a fluentd naplókban:
2019-10-29 13:10:43 +0000 [warn]: dump an error event: error_class=Fluent::Plugin::ElasticsearchErrorHandler::ElasticsearchError error="400 - Rejected by Elasticsearch"
A hiba azt jelenti, hogy instabil típusú mezőt küld az indexnek egy kész leképezéssel. A legegyszerűbb példa egy mező az nginx naplójában egy változóval $upstream_status. Tartalmazhat számot vagy karakterláncot is. Például:
A naplók azt mutatják, hogy a 10.100.0.10 szerver 404-es hibával válaszolt, és a kérést egy másik tartalomtárolóra küldték. Ennek eredményeként a naplókban szereplő érték a következő lett:
Vannak esetek, amikor kivétel nélkül minden napló létfontosságú. És ezzel a fent javasolt/tárgyalt K8-as tipikus rönkgyűjtési sémák problémái vannak.
Például a fluentd nem tud rönköket gyűjteni rövid élettartamú konténerekből. Az egyik projektünkben az adatbázis-migrációs tároló 4 másodpercnél rövidebb ideig élt, majd törölték - a megfelelő megjegyzés szerint:
"helm.sh/hook-delete-policy": hook-succeeded
Emiatt az áttelepítési végrehajtási napló nem szerepelt a tárolóban. Ebben az esetben a politika segíthet. before-hook-creation.
Egy másik példa a Docker-naplóforgatás. Tegyük fel, hogy van egy alkalmazás, amely aktívan ír a naplókba. Normál körülmények között sikerül az összes naplót feldolgoznunk, de amint probléma jelentkezik - például a fentebb leírtak szerint hibás formátum esetén - a feldolgozás leáll, és a Docker elforgatja a fájlt. Ennek eredményeként az üzleti szempontból kritikus naplók elveszhetnek.
Ezért fontos a naplófolyamok elkülönítése, beágyazva a legértékesebbeket közvetlenül az alkalmazásba küldve biztonságuk érdekében. Ezenkívül nem lenne felesleges néhányat létrehozni rönk „akkumulátora”., amely túléli a rövid tárolási hiányt, miközben elmenti a kritikus üzeneteket.
Végül nem szabad elfelejtenünk Fontos minden alrendszer megfelelő felügyelete. Ellenkező esetben könnyen belefuthatunk olyan helyzetbe, amelyben a fluentd állapotban van CrashLoopBackOff és nem küld semmit, és ez fontos információk elvesztésével kecsegtet.
Álláspontja
Ebben a cikkben nem olyan SaaS-megoldásokat vizsgálunk, mint a Datadog. Az itt leírt problémák közül sokat már megoldottak ilyen vagy olyan módon a naplók gyűjtésére szakosodott kereskedelmi cégek, de különböző okok miatt nem mindenki tudja használni a SaaS-t (a legfontosabbak a költségek és a 152-FZ-nek való megfelelés).
A központosított naplógyűjtés elsőre egyszerű feladatnak tűnik, de egyáltalán nem az. Fontos megjegyezni, hogy:
Csak a kritikus összetevőket kell részletesen naplózni, míg a megfigyelést és a hibagyűjtést más rendszerekre is be lehet állítani.
A gyártás során a naplókat minimálisra kell csökkenteni, nehogy felesleges terhelést okozzon.
A naplóknak géppel olvashatónak, normalizáltnak és szigorú formátumúnak kell lenniük.
Az igazán kritikus naplókat külön folyamban kell küldeni, amelyet el kell különíteni a főbbektől.
Érdemes megfontolni a rönktárolót, amely megkíméli Önt a nagy terhelés kitöréseitől, és egyenletesebbé teszi a tároló terhelését.
Ezek az egyszerű szabályok, ha mindenhol alkalmazzák, lehetővé teszik a fent leírt áramkörök működését - még akkor is, ha hiányoznak belőlük fontos alkatrészek (az akkumulátor). Ha nem tartja be ezeket az elveket, a feladat könnyen átvezeti Önt és az infrastruktúrát a rendszer egy másik nagyon terhelt (és egyben nem hatékony) összetevőjéhez.