
Ă
r 2019 hade vi fortfarande ingen standardlösning för aggregering av loggar i Kubernetes. I den hÀr artikeln vill vi, med exempel frÄn verklig praktik, dela med oss av vÄra sökningar, mötta problem och deras lösningar.
Men först bör jag nÀmna att olika kunder har mycket olika uppfattningar om vad logginsamlingsprocessen innebÀr:
- nÄgra vill se sÀkerhets- och revisionsloggar;
- nÄgra vill ha centraliserad loggning av hela infrastrukturen;
- och vissa nöjer sig med att enbart samla in applikationsloggar, medan de exempelvis exkluderar belastningsutjÀmnare.
Om hur vi implementerade olika "önskemĂ„l" och vilka svĂ„righeter vi stötte pĂ„ â lĂ€s vidare.
Teori: om verktyg för loggar
Bakgrund om komponenterna i loggningssystemet
Loggning har genomgĂ„tt en lĂ„ng resa, vilket har lett till att metoder för insamling och analys av loggar har utvecklats, och dessa tillĂ€mpas idag. Redan pĂ„ 1950-talet dök det upp en motsvarighet till standard strömmar för in- och utmatning i Fortran, som hjĂ€lpte programmerare med felsökning av sina program. Det var de första datorloggarna som underlĂ€ttade livet för programmerarna och pĂ„ den tiden. Idag ser vi den första komponenten i loggningssystemet â kĂ€llan eller "producenten" (producer) av loggar.
Datavetenskapen har inte stÄtt stilla: datanÀtverk, de första klustren... Komplexa system bestÄende av flera datorer började arbeta. Nu var systemadministratörer tvungna att samla in loggar frÄn flera maskiner, och i sÀrskilda fall kunde de Àven inkludera meddelanden frÄn operativsystemets kÀrna ifall det skulle behövas för att undersöka systemfel. För att beskriva system för centraliserad logginsamling publicerades i början av 2000-talet , vilket standardiserade remote_syslog. SÄ en annan viktig komponent dök upp: loggkollektorn och deras lagring.
Med ökningen av loggvolymer och den allmĂ€nna implementeringen av webteknologier, blev frĂ„gan om hur loggarna skulle visas för anvĂ€ndare aktuell. IstĂ€llet för enkla konsolverktyg (awk/sed/grep) kom mer avancerade loggvisare â den tredje komponenten.
Med det ökade loggvolymen stod det klart att loggar Ă€r nödvĂ€ndiga, men inte alla. Dessutom krĂ€ver olika loggar olika nivĂ„er av bevarande: vissa kan förloras efter en dag, medan andra mĂ„ste förvaras i fem Ă„r. SĂ„ en filtrerings- och dataroutingkomponent lades till loggsystemet â lĂ„t oss kalla den filtern.
Lagringslösningarna har ocksÄ gjort ett stort steg: frÄn vanliga filer till relationsdatabaser och sedan till dokumentorienterade lagringslösningar (t.ex. Elasticsearch). SÄ lagringen separerades frÄn insamlaren.
I slutĂ€ndan har sjĂ€lva begreppet logg vidgats till nĂ„gon form av abstrakt ström av hĂ€ndelser som vi vill bevara för historiken. Mer specifikt â för det fall det behövs att genomföra en utredning eller sammanstĂ€lla en analysrapport...
Som ett resultat har insamling av loggar pÄ relativt kort tid utvecklats till ett viktigt delsystem som med rÀtta kan kallas en av underavdelningarna inom Big Data.

Om vanliga printar en gÄng kunde vara tillrÀckligt för ett "loggsystem", sÄ har situationen nu förÀndrats avsevÀrt.
Kubernetes och loggar
NÀr Kubernetes kom in i infrastrukturen pÄverkades inte den befintliga logginsamlingen, utan situationen blev faktiskt mer komplex: hanteringen av infrastrukturplattformen blev bÄde förenklad och komplicerad. MÄnga gamla tjÀnster började migrera till mikrotjÀnstbaserat arbete. I loggsammanhang ledde detta till ett vÀxande antal loggkÀllor, deras sÀrskilda livscykel och behovet av att spÄra relationerna mellan alla systemkomponenter genom loggar...
För att gÄ framÄt kan jag konstatera att det tyvÀrr inte finns nÄgon standardiserad loggningslösning för Kubernetes som sÀrskilt skiljer sig frÄn alla andra. De mest populÀra scheman i gemenskapen kan sammanfattas som följer:
- nÄgon distribuerar en stack EFK (Elasticsearch, Fluentd, Kibana);
- nĂ„gon â försöker den nyligen slĂ€ppta eller anvĂ€nder ;
- vi (och kanske inte bara vi? ..) i stor utstrĂ€ckning Ă€r nöjda med vĂ„r egen utveckling â âŠ
Som regel anvÀnder vi sÄdana kombinationer i K8s-kluster (för sjÀlvhostade lösningar):
- ;
- .
Men jag kommer inte att stanna vid instruktionerna för installation och konfiguration. IstÀllet kommer jag att fokusera pÄ deras nackdelar och mer övergripande slutsatser om loggsituationen i helhet.
Praktik med loggar i K8s

"Vardagliga loggar", hur mÄnga av er finns det?..
Centraliserad insamling av loggar frÄn en tillrÀckligt stor infrastruktur krÀver betydande resurser som gÄr Ät till insamling, lagring och bearbetning av loggar. Under driften av olika projekt har vi stött pÄ olika krav och de problem som uppstÄtt till följd av detta.
LÄt oss prova ClickHouse
LÄt oss titta pÄ ett centraliserat förrÄd i ett projekt med en applikation som genererar loggar ganska aktivt: mer Àn 5000 rader per sekund. Vi börjar arbeta med dess loggar genom att lagra dem i ClickHouse.
SÄ snart max realtid krÀvs, kommer en 4-kÀrnig server med ClickHouse redan att vara överbelastad pÄ disksystemet:

Denna typ av belastning Àr kopplad till att vi försöker skriva sÄ snabbt som möjligt till ClickHouse. Och databasen reagerar pÄ detta med ökad diskbelastning, vilket kan leda till följande fel:
DB::Exception: För mÄnga delar (300). Sammanfogningar bearbetas mycket lÄngsammare Àn insÀttningar
Det handlar om att i ClickHouse (som innehÄller loggdata) har sina egna svÄrigheter vid skrivoperationer. De insatta uppgifterna genererar en temporÀr partition som sedan slÄs samman med huvudtabellen. Som ett resultat blir inskrivningen mycket krÀvande för disken, och det finns Àven en begrÀnsning, vars meddelande vi fick tidigare: inte fler Àn 300 subpartitioner kan slÄs samman per sekund (detta motsvarar faktiskt 300 insÀttningar per sekund).
För att undvika ett sÄdant beteende, i sÄ stora block som möjligt och inte oftare Àn 1 gÄng var 2:a sekund. Men att skriva i stora block innebÀr att vi mÄste skriva mer sÀllan till ClickHouse. Detta, i sin tur, kan leda till att bufferten fylls och loggar gÄr förlorade. Lösningen Àr att öka bufferten för Fluentd, men dÄ ökar ocksÄ minnesanvÀndningen.
AnmĂ€rkning: En annan problematisk aspekt av vĂ„r lösning med ClickHouse var kopplad till att partitioneringen i vĂ„rt fall (loghouse) genomfördes via externa tabeller som Ă€r kopplade . Detta leder till att nĂ€r man hĂ€mtar stora tidsintervall krĂ€vs det för mycket RAM-minne, eftersom metadatabasen genomsöker alla partitioner â Ă€ven de som uppenbarligen inte innehĂ„ller nödvĂ€ndiga data. Men nu kan man tryggt kalla denna metod för förĂ„ldrad för de aktuella versionerna av ClickHouse (c ).
Som ett resultat blir det tydligt att resurserna för realtidsloggning i ClickHouse inte Ă€r tillrĂ€ckliga för alla projekt (nĂ€rmare bestĂ€mt, deras fördelning Ă€r inte rimlig). Dessutom krĂ€vs det att man anvĂ€nder en mellanlagring, vilket vi Ă„terkommer till. Det beskrivna fallet Ă€r verkligt. Och vid den tidpunkten kunde vi inte erbjuda en pĂ„litlig och stabil lösning som skulle tillfredsstĂ€lla kunden och möjliggöra insamling av loggar med minimal fördröjningâŠ
Och Elasticsearch?
Det Àr kÀnt att Elasticsearch klarar av stora belastningar. LÄt oss prova det i samma projekt. Nu ser belastningen ut pÄ följande sÀtt:

Elasticsearch kunde bearbeta datastreamen, men att skriva sĂ„dana volymer till det anvĂ€nder mycket CPU. Detta löses genom att organisera en kluster. Rent tekniskt Ă€r detta inget problem, men det visar sig att bara för att loggsystemet ska fungera anvĂ€nder vi redan cirka 8 kĂ€rnor och har en ytterligare högbelastad komponent i systemetâŠ
Slutsats: en sÄdan variant kan vara berÀttigad, men endast om projektet Àr stort och dess ledning Àr beredd att spendera betydande resurser pÄ ett system för centraliserad loggning.
DÄ uppstÄr en rimlig frÄga:
Vilka loggar Àr faktiskt nödvÀndiga?
LÄt oss försöka Àndra sjÀlva tillvÀgagÄngssÀttet: loggarna bör vara bÄde informativa och inte tÀcka varje hÀndelse i systemet.
Anta att vi har en framgĂ„ngsrik e-handelsbutik. Vilka loggar Ă€r viktiga? Att samla in maximal information, till exempel frĂ„n betalningsgatewayen â en utmĂ€rkt idĂ©. Men för tjĂ€nsten som beskĂ€r bilder i produktkatalogen Ă€r vi inte intresserade av alla loggar: det rĂ€cker med fel och utökad övervakning (till exempel procentandelen 500-fel som denna komponent genererar).
HÀr har vi kommit fram till att centraliserad loggning Àr inte alltid berÀttigad. Mycket ofta vill kunden samla alla loggar pÄ ett stÀlle, Àven om det i verkligheten bara krÀvs omkring 5 % av meddelandena frÄn hela loggen, som Àr kritiska för verksamheten:
- Ibland rÀcker det med att stÀlla in, lÄt oss sÀga, bara storleken pÄ loggen för containern och felhanteraren (till exempel Sentry).
- För incidentutredningar kan det ofta rÀcka med felmeddelanden och sjÀlva den stora lokala loggen.
- Vi har haft projekt som helt och hÄllet klarade sig med enbart funktionella tester och system för insamling av fel. Utvecklaren behövde inte loggar som sÄdana - de sÄg allt genom felspÄren.
En illustration frÄn verkligheten
Ett bra exempel kan vara en annan historia. Vi fick en förfrÄgan frÄn sÀkerhetsteamet hos en av vÄra kunder, som redan anvÀnde en kommersiell lösning som utvecklades lÄngt före implementeringen av Kubernetes.
Det krÀvdes att "vÀnja" det centrala logginsamlingssystemet med företagets sensor för problemidentifiering - QRadar. Detta system kan ta emot loggar via syslog-protokollet och hÀmta via FTP. Emellertid gick det inte att integrera det med remote_syslog-plugin för fluentd direkt. (som det visade sig, )). Problem med instÀllningen av QRadar visade sig pÄ kundens sÀkerhetsteams sida.
Som ett resultat exporterades en del loggar som var kritiska för verksamheten till FTP QRadar, medan en annan del dirigerades direkt frĂ„n noderna via remote syslog. För detta skrev vi till och med en â kanske det hjĂ€lper nĂ„gon att lösa ett liknande problem... Tack vare den skapade schemat fick kunden tag pĂ„ och analyserade kritiska loggar (med hjĂ€lp av sitt favoritverktyg), medan vi kunde sĂ€nka kostnaderna för loggningssystemet genom att endast behĂ„lla den senaste mĂ„naden.
Ett annat exempel Àr ganska talande för hur man inte bör göra. En av vÄra kunder Ästadkom att hantera varje hÀndelser frÄn anvÀndaren genom att göra en fler-radig ostrukturerad utskrift av information i loggen. Som man lÀtt kan gissa, var sÄdana loggar extremt svÄra att lÀsa och lagra.
Kriterier för loggar
SÄdana exempel leder fram till slutsatsen att förutom valet av logginsamlingssystem mÄste man Àven utforma loggarna sjÀlva! Vilka krav finns hÀr?
- Loggarna mÄste vara i maskinlÀsbart format (till exempel, JSON).
- Loggarna mÄste vara kompakta och kunna Àndra loggningsgraden för att debugga eventuella problem. Dessutom bör system köra med en loggningsnivÄ som Varning eller Error.
- Loggar mÄste vara normaliserade, vilket innebÀr att i loggobjektet ska alla rader ha samma fÀlttyp.
Ostrukturerade loggar kan leda till problem med att ladda loggar till lagring och kan fullstÀndigt stoppa deras behandling. HÀr Àr ett exempel med felkod 400, som mÄnga sÀkert har stött pÄ i fluentd-loggar:
2019-10-29 13:10:43 +0000 [warn]: dump a error event: error_class=Fluent::Plugin::ElasticsearchErrorHandler::ElasticsearchError error="400 - Rejected by Elasticsearch"
Felet innebÀr att du skickar ett fÀlt till indexet med en fÀrdig mapping vars typ Àr instabil. Det enklaste exemplet Àr ett fÀlt i nginx-loggen med en variabel $upstream_status. I det kan det vara bÄde ett nummer och en strÀng. Till exempel:
{ "ip": "1.2.3.4", "http_user": "-", "request_id": "17ee8a579e833b5ab9843a0aca10b941", "time": "29/Oct/2019:16:18:57 +0300", "method": "GET", "uri": "\/staffs\/265.png", "protocol": "HTTP\/1.1", "status": "200", "body_size": "906", "referrer": "https:\/\/example.com\/staff", "user_agent": "Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/78.0.3904.70 Safari\/537.36", "request_time": "0.001", "cache_status": "-", "upstream_response_time": "0.001, 0.007", "upstream_addr": "127.0.0.1:9000", "upstream_status": "200", "upstream_response_length": "906", "location": "staff"}
{ "ip": "1.2.3.4", "http_user": "-", "request_id": "47fe42807f2a7d8d5467511d7d553a1b", "time": "29/Oct/2019:16:18:57 +0300", "method": "GET", "uri": "\/staff", "protocol": "HTTP\/1.1", "status": "200", "body_size": "2984", "referrer": "-", "user_agent": "Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/78.0.3904.70 Safari\/537.36", "request_time": "0.010", "cache_status": "-", "upstream_response_time": "0.001, 0.007", "upstream_addr": "10.100.0.10:9000, 10.100.0.11:9000", "upstream_status": "404, 200", "upstream_response_length": "0, 2984", "location": "staff"}
I loggarna syns det att servern 10.100.0.10 svarade med felkod 404 och att begÀran gick till ett annat lagringsutrymme. Resultatet blev att vÀrdet i loggarna sÄg ut sÄ hÀr:
"upstream_response_time": "0.001, 0.007"
Denna situation Àr sÄ vanlig att den till och med fÄtt ett eget .
Och hur Àr det med tillförlitlighet?
Det finns fall dÄ alla loggar utan undantag Àr livsviktiga. Och det Àr hÀr de typiska loggsamlingsscheman för K8s, som nÀmndes tidigare, har problem.
Till exempel kan fluentd inte samla loggar frĂ„n kortlivade containrar. I ett av vĂ„ra projekt levde containern för databasflyttningar i mindre Ă€n 4 sekunder och raderades sedan â enligt den motsvarande anteckningen:
"helm.sh/hook-delete-policy": hook-succeeded
DÀrför hamnade inte loggen för flyttningen i lagringen. I det hÀr fallet kan policyn before-hook-creation.
Ett annat exempel Ă€r loggrotation i Docker. Anta att det finns en applikation som aktivt skriver loggar. Under normala förhĂ„llanden lyckas vi bearbeta alla loggar, men sĂ„ snart ett problem uppstĂ„r â som den obenĂ€mnda med felaktigt format â stoppas bearbetningen och Docker roterar filen. Resultatet blir att kritiska loggar för verksamheten kan gĂ„ förlorade.
Det Àr dÀrför det Àr viktigt att separera loggströmmar, genom att integrera sÀndning av de mest vÀrdefulla loggarna direkt i applikationen för att sÀkerstÀlla deras bevarande. Dessutom kan det vara bra att skapa en sorts »ackumulator« för loggar, som kan överleva kortvarig otillgÀnglighet av lagringen samtidigt som kritiska meddelanden bevaras.
Till sist fÄr man inte glömma att det Àr viktigt att noggrant övervaka varje subsystem. Annars Àr det lÀtt att hamna i en situation dÀr fluentd befinner sig i tillstÄndet CrashLoopBackOff och inte skickar nÄgot, vilket kan leda till förlust av viktig information.
Slutsatser
I den hÀr artikeln diskuterar vi inte SaaS-lösningar som Datadog. MÄnga av de problem som beskrivs hÀr har redan lösts av kommersiella företag som specialiserar sig pÄ att samla loggar, men alla kan inte anvÀnda SaaS av olika skÀl (de huvudsakliga Àr kostnad och efterlevnad av 152-FZ).
Centraliserad logginsamling verkar först som en enkel uppgift, men sÄ Àr det inte. Det Àr viktigt att komma ihÄg att:
- Det Àr vÀrt att detaljerat logga endast kritiska komponenter, medan över andra system kan övervakning och felinsamling konfigureras.
- Loggar i produktion bör hÄllas minimala för att inte ge onödig belastning.
- Loggar ska vara maskinlÀsbara, normaliserade och ha ett strikt format.
- Verkligt kritiska loggar bör skickas i en separat ström, som ska vara Ätskild frÄn de huvudsakliga.
- Det Àr vÀrt att tÀnka pÄ en loggackumulator som kan rÀdda frÄn toppar av hög belastning och göra belastningen pÄ lagringen mer jÀmn.

Dessa enkla regler, om de tillĂ€mpas överallt, skulle möjliggöra att de ovan beskrivna scheman fungerar â Ă€ven om det saknas viktiga komponenter (ackumulator). Om man inte följer sĂ„dana principer kan uppgiften enkelt leda dig och infrastrukturen till en annan högbelastad (och samtidigt ineffektiv) systemkomponent.
P.S.
LÀs Àven i vÄr blogg:
- «»;
- «»;
- «».
KĂ€lla: habr.com
