Loggar in Kubernetes (och inte bara) idag: förväntningar och verklighet

Loggar in Kubernetes (och inte bara) idag: förväntningar och verklighet

Det är 2019 och vi har fortfarande ingen standardlösning för loggaggregation i Kubernetes. I den här artikeln vill vi, med hjälp av exempel från verklig praxis, dela våra sökningar, problem som stött på och deras lösningar.

Men först ska jag göra en reservation för att olika kunder förstår väldigt olika saker genom att samla in loggar:

  • någon vill se säkerhets- och revisionsloggar;
  • någon - centraliserad loggning av hela infrastrukturen;
  • och för vissa räcker det att bara samla in applikationsloggar, exklusive till exempel balanserare.

Nedan följer klippet nedan om hur vi implementerade olika "önskelistor" och vilka svårigheter vi stötte på.

Teori: om loggningsverktyg

Bakgrund om komponenterna i ett loggningssystem

Loggningen har kommit långt, vilket har lett till att metoder för att samla in och analysera stockar har utvecklats, vilket är vad vi använder idag. Tillbaka på 1950-talet introducerade Fortran en analog av standard input/output-strömmar, vilket hjälpte programmeraren att felsöka sitt program. Dessa var de första datorloggarna som gjorde livet lättare för dåtidens programmerare. Idag ser vi i dem den första komponenten i loggningssystemet - källa eller "producent" av stockar.

Datavetenskapen stod inte stilla: datornätverk dök upp, de första klustren... Komplexa system bestående av flera datorer började fungera. Nu var systemadministratörer tvungna att samla in loggar från flera maskiner, och i speciella fall kunde de lägga till OS-kärnmeddelanden ifall de behövde undersöka ett systemfel. För att beskriva centraliserade logginsamlingssystem publicerades den i början av 2000-talet RFC 3164, som standardiserade remote_syslog. Så här såg en annan viktig komponent ut: stocksamlare och deras förvaring.

Med ökningen av volymen av loggar och det utbredda införandet av webbteknologier uppstod frågan om vilka loggar som behöver visas bekvämt för användarna. Enkla konsolverktyg (awk/sed/grep) har ersatts av mer avancerade logga tittare - tredje komponenten.

På grund av ökningen av volymen stockar blev något annat klart: stockar behövs, men inte alla. Och olika stockar kräver olika konserveringsnivåer: vissa kan gå förlorade på en dag, medan andra måste lagras i 5 år. Så en komponent för filtrering och dirigering av dataflöden lades till i loggningssystemet - låt oss kalla det filtrera.

Lagring har också gjort ett stort steg: från vanliga filer till relationsdatabaser och sedan till dokumentorienterad lagring (till exempel Elasticsearch). Så förrådet separerades från samlaren.

I slutändan har själva begreppet stock expanderat till en sorts abstrakt ström av händelser som vi vill bevara för historien. Eller snarare, om du behöver göra en utredning eller göra en analysrapport...

Som ett resultat av detta har logginsamlingen på relativt kort tid utvecklats till ett viktigt delsystem, som med rätta kan kallas en av undersektionerna i Big Data.

Loggar in Kubernetes (och inte bara) idag: förväntningar och verklighet
Om det en gång i tiden kunde räcka med vanliga utskrifter för ett "loggningssystem" så har situationen förändrats mycket.

Kubernetes och loggar

När Kubernetes kom till infrastrukturen gick det redan existerande problemet med att samla in stockar inte heller förbi det. På vissa sätt blev det ännu mer smärtsamt: hanteringen av infrastrukturplattformen var inte bara förenklad, utan också komplicerad på samma gång. Många gamla tjänster har börjat migrera till mikrotjänster. När det gäller loggar återspeglas detta i det växande antalet loggkällor, deras speciella livscykel och behovet av att spåra relationerna mellan alla systemkomponenter genom loggar...

När jag blickar framåt kan jag konstatera att det nu tyvärr inte finns något standardiserat loggningsalternativ för Kubernetes som skulle kunna jämföras med alla andra. De mest populära systemen i samhället är följande:

  • någon rullar ut stapeln SFAO (Elasticsearch, Fluentd, Kibana);
  • någon provar den nyligen släppta Loke eller användningsområden Loggningsoperatör;
  • oss (och kanske inte bara vi?..) Jag är i stort sett nöjd med min egen utveckling - timmerhus.

Som regel använder vi följande buntar i K8s-kluster (för lösningar med egen värd):

Jag kommer dock inte att uppehålla mig vid instruktioner för deras installation och konfiguration. Istället kommer jag att fokusera på deras brister och mer globala slutsatser om situationen med stockar i allmänhet.

Träna med stockar i K8s

Loggar in Kubernetes (och inte bara) idag: förväntningar och verklighet

"Vardagsloggar", hur många är ni där?..

Centraliserad insamling av stockar från en ganska stor infrastruktur kräver avsevärda resurser, som kommer att läggas på att samla in, lagra och bearbeta stockar. Under driften av olika projekt ställdes vi inför olika krav och operativa problem som härrörde från dem.

Låt oss prova ClickHouse

Låt oss titta på en centraliserad lagring i ett projekt med en applikation som genererar loggar ganska aktivt: mer än 5000 rader per sekund. Låt oss börja arbeta med hans loggar och lägga till dem i ClickHouse.

Så fort maximal realtid krävs kommer den 4-kärniga servern med ClickHouse redan att vara överbelastad på diskundersystemet:

Loggar in Kubernetes (och inte bara) idag: förväntningar och verklighet

Denna typ av laddning beror på att vi försöker skriva i ClickHouse så snabbt som möjligt. Och databasen reagerar på detta med ökad diskbelastning, vilket kan orsaka följande fel:

DB::Exception: Too many parts (300). Merges are processing significantly slower than inserts

Faktum är att MergeTree-tabeller i ClickHouse (de innehåller loggdata) har sina egna svårigheter under skrivoperationer. Datan som infogas i dem genererar en temporär partition, som sedan slås samman med huvudtabellen. Som ett resultat visar sig inspelningen vara mycket krävande på disken, och den är också föremål för begränsningen som vi fick meddelande om ovan: inte mer än 1 underpartitioner kan slås samman på 300 sekund (det är faktiskt 300 inlägg per sekund).

För att undvika detta beteende, ska skriva till ClickHouse i så stora bitar som möjligt och inte mer än 1 gång varannan sekund. Men att skriva i stora skurar tyder på att vi borde skriva mer sällan i ClickHouse. Detta kan i sin tur leda till buffertspill och förlust av stockar. Lösningen är att öka Fluentd-bufferten, men då kommer även minnesförbrukningen att öka.

Notera: En annan problematisk aspekt av vår lösning med ClickHouse var relaterad till det faktum att partitionering i vårt fall (logghus) implementeras genom externa tabeller anslutna Slå samman tabell. Detta leder till det faktum att vid sampling av stora tidsintervall krävs för mycket RAM, eftersom den metatable itererar genom alla partitioner - även de som uppenbarligen inte innehåller nödvändiga data. Men nu kan detta tillvägagångssätt säkert förklaras föråldrat för nuvarande versioner av ClickHouse (ca 18.16).

Som ett resultat blir det tydligt att inte alla projekt har tillräckligt med resurser för att samla in loggar i realtid i ClickHouse (mer exakt, deras distribution kommer inte att vara lämplig). Dessutom måste du använda batteri, som vi återkommer till senare. Fallet som beskrivs ovan är verkligt. Och på den tiden kunde vi inte erbjuda en pålitlig och stabil lösning som skulle passa kunden och göra det möjligt för oss att samla in stockar med minimal fördröjning...

Hur är det med Elasticsearch?

Elasticsearch är känt för att hantera tunga arbetsbelastningar. Låt oss prova det i samma projekt. Nu ser belastningen ut så här:

Loggar in Kubernetes (och inte bara) idag: förväntningar och verklighet

Elasticsearch kunde smälta dataströmmen, men att skriva sådana volymer till den använder mycket CPU. Detta bestäms genom att organisera ett kluster. Tekniskt sett är detta inget problem, men det visar sig att bara för att driva loginsamlingssystemet använder vi redan cirka 8 kärnor och har en extra högt belastad komponent i systemet...

Sammanfattning: detta alternativ kan motiveras, men bara om projektet är stort och dess ledning är redo att spendera betydande resurser på ett centraliserat loggningssystem.

Då uppstår en naturlig fråga:

Vilka stockar behövs egentligen?

Loggar in Kubernetes (och inte bara) idag: förväntningar och verklighet Låt oss försöka ändra själva tillvägagångssättet: loggar ska samtidigt vara informativa och inte täcka varje händelse i systemet.

Låt oss säga att vi har en framgångsrik webbutik. Vilka loggar är viktiga? Att samla in så mycket information som möjligt, till exempel från en betalningsgateway, är en utmärkt idé. Men inte alla loggar från tjänsten för bildskärning i produktkatalogen är kritiska för oss: endast fel och avancerad övervakning räcker (till exempel procentandelen av 500 fel som denna komponent genererar).

Så vi har kommit fram till att centraliserad loggning är inte alltid motiverad. Mycket ofta vill kunden samla alla loggarna på ett ställe, även om det i själva verket bara krävs 5 % av de meddelanden som är kritiska för verksamheten från hela loggen:

  • Ibland räcker det med att konfigurera till exempel bara storleken på behållarloggen och felsamlaren (till exempel Sentry).
  • Ett felmeddelande och en stor lokal logg i sig kan ofta räcka för att undersöka incidenter.
  • Vi hade projekt som klarade oss med uteslutande funktionstester och felinsamlingssystem. Utvecklaren behövde inte loggar som sådana - de såg allt från felspår.

Illustration från livet

En annan historia kan tjäna som ett bra exempel. Vi fick en förfrågan från säkerhetsteamet till en av våra kunder som redan använde en kommersiell lösning som utvecklades långt före introduktionen av Kubernetes.

Det var nödvändigt att "bli vänner" med det centraliserade logginsamlingssystemet med företagets problemdetekteringssensor - QRadar. Detta system kan ta emot loggar via syslog-protokollet och hämta dem från FTP. Det var dock inte omedelbart möjligt att integrera det med plugin-programmet remote_syslog för fluentd (som det blev, vi är inte ensamma). Problem med att sätta upp QRadar visade sig ligga på sidan av kundens säkerhetsteam.

Som ett resultat laddades en del av de affärskritiska loggarna upp till FTP QRadar, och den andra delen omdirigerades via fjärrsyslog direkt från noderna. För detta skrev vi till och med enkelt diagram - kanske kommer det att hjälpa någon att lösa ett liknande problem... Tack vare det resulterande schemat tog klienten själv emot och analyserade kritiska loggar (med hjälp av sina favoritverktyg), och vi kunde minska kostnaderna för loggningssystemet, vilket bara sparade förra månaden.

Ett annat exempel är ganska vägledande för vad man inte ska göra. En av våra kunder för bearbetning av varje händelser som kommer från användaren, gjorde multiline ostrukturerad produktion information i loggen. Som du kanske kan gissa var sådana loggar extremt obekväma att både läsa och lagra.

Kriterier för stockar

Sådana exempel leder till slutsatsen att du förutom att välja ett stockinsamlingssystem behöver göra det designar också stockarna själva! Vilka är kraven här?

  • Loggar måste vara i maskinläsbart format (till exempel JSON).
  • Loggar bör vara kompakta och med möjlighet att ändra graden av loggning för att felsöka eventuella problem. Samtidigt bör man i produktionsmiljöer köra system med en loggningsnivå som Varning eller Fel.
  • Loggar måste normaliseras, det vill säga i ett loggobjekt måste alla linjer ha samma fälttyp.

Ostrukturerade loggar kan leda till problem med att lasta in stockar i lager och att bearbetningen av dem stoppas helt. Som en illustration, här är ett exempel med fel 400, som många definitivt har stött på i flytande loggar:

2019-10-29 13:10:43 +0000 [warn]: dump an error event: error_class=Fluent::Plugin::ElasticsearchErrorHandler::ElasticsearchError error="400 - Rejected by Elasticsearch"

Felet innebär att du skickar ett fält vars typ är instabil till indexet med en färdig mappning. Det enklaste exemplet är ett fält i nginx-loggen med en variabel $upstream_status. Den kan innehålla antingen ett nummer eller 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"}

Loggarna visar att server 10.100.0.10 svarade med ett 404-fel och begäran skickades till en annan innehållslagring. Som ett resultat blev värdet i loggarna så här:

"upstream_response_time": "0.001, 0.007"

Denna situation är så vanlig att den till och med förtjänar en separat referenser i dokumentation.

Hur är det med tillförlitlighet?

Det finns tillfällen då alla stockar utan undantag är viktiga. Och med detta har de typiska loginsamlingsscheman för K8:or som föreslagits/diskuterats ovan problem.

Till exempel kan fluentd inte samla stockar från kortlivade behållare. I ett av våra projekt levde databasmigreringsbehållaren i mindre än 4 sekunder och raderades sedan - enligt motsvarande anteckning:

"helm.sh/hook-delete-policy": hook-succeeded

På grund av detta inkluderades inte migreringskörningsloggen i lagringen. Politik kan hjälpa till i det här fallet. before-hook-creation.

Ett annat exempel är Docker-loggrotation. Låt oss säga att det finns ett program som aktivt skriver till loggar. Under normala förhållanden lyckas vi bearbeta alla loggar, men så fort ett problem dyker upp - till exempel som beskrivits ovan med ett felaktigt format - avbryts behandlingen, och Docker roterar filen. Resultatet är att affärskritiska loggar kan gå förlorade.

Det är därför det är viktigt att separera loggströmmar, inbäddning skickar de mest värdefulla direkt till applikationen för att säkerställa deras säkerhet. Dessutom skulle det inte vara överflödigt att skapa några "ackumulator" av stockar, som kan överleva kortvarig otillgänglighet samtidigt som viktiga meddelanden sparas.

Slutligen får vi inte glömma det Det är viktigt att övervaka alla delsystem ordentligt. Annars är det lätt att hamna i en situation där flytande är i ett tillstånd CrashLoopBackOff och skickar ingenting, och detta lovar förlust av viktig information.

Resultat

I den här artikeln tittar vi inte på SaaS-lösningar som Datadog. Många av problemen som beskrivs här har redan lösts på ett eller annat sätt av kommersiella företag som är specialiserade på att samla in stockar, men alla kan inte använda SaaS av olika anledningar (de viktigaste är kostnader och överensstämmelse med 152-FZ).

Centraliserad logginsamling ser till en början ut som en enkel uppgift, men det är det inte alls. Det är viktigt att komma ihåg att:

  • Endast kritiska komponenter behöver loggas i detalj, medan övervakning och felinsamling kan konfigureras för andra system.
  • Loggar i produktionen bör hållas minimala för att inte lägga till onödig belastning.
  • Loggar måste vara maskinläsbara, normaliserade och ha ett strikt format.
  • Verkligen kritiska loggar bör skickas i en separat ström, som bör separeras från de viktigaste.
  • Det är värt att överväga en stockackumulator, som kan rädda dig från skurar av hög belastning och göra belastningen på lagringen mer enhetlig.

Loggar in Kubernetes (och inte bara) idag: förväntningar och verklighet
Dessa enkla regler, om de tillämpas överallt, skulle tillåta de kretsar som beskrivs ovan att fungera - även om de saknar viktiga komponenter (batteriet). Om du inte följer sådana principer kommer uppgiften lätt att leda dig och infrastrukturen till en annan högt belastad (och samtidigt ineffektiv) komponent i systemet.

PS

Läs även på vår blogg:

Källa: will.com

Lägg en kommentar