Logt vandaag in Kubernetes in (en niet alleen): verwachtingen en realiteit

Logt vandaag in Kubernetes in (en niet alleen): verwachtingen en realiteit

Het is 2019 en we hebben nog steeds geen standaardoplossing voor logaggregatie in Kubernetes. In dit artikel willen we aan de hand van voorbeelden uit de praktijk onze zoekopdrachten, tegengekomen problemen en hun oplossingen delen.

Maar eerst maak ik een voorbehoud dat verschillende klanten heel verschillende dingen begrijpen door logbestanden te verzamelen:

  • iemand wil beveiligings- en auditlogboeken zien;
  • iemand - gecentraliseerde registratie van de gehele infrastructuur;
  • en voor sommigen is het voldoende om alleen applicatielogboeken te verzamelen, met uitzondering van bijvoorbeeld balancers.

Hieronder ziet u hieronder hoe we verschillende “verlanglijstjes” hebben geïmplementeerd en welke moeilijkheden we tegenkwamen.

Theorie: over logtools

Achtergrondinformatie over de componenten van een logsysteem

Houtkap heeft een lange weg afgelegd, waardoor er methodologieën zijn ontwikkeld voor het verzamelen en analyseren van logbestanden, die we vandaag de dag gebruiken. In de jaren vijftig introduceerde Fortran een analoog van standaard invoer-/uitvoerstromen, waardoor de programmeur zijn programma kon debuggen. Dit waren de eerste computerlogboeken die het leven van programmeurs uit die tijd gemakkelijker maakten. Tegenwoordig zien we daarin het eerste onderdeel van het houtkapsysteem: bron of “producent” van logbestanden.

De computerwetenschap stond niet stil: computernetwerken verschenen, de eerste clusters... Complexe systemen bestaande uit meerdere computers begonnen te werken. Nu werden systeembeheerders gedwongen logbestanden van verschillende machines te verzamelen, en in speciale gevallen konden ze OS-kernelberichten toevoegen voor het geval ze een systeemfout moesten onderzoeken. Om gecentraliseerde systemen voor het verzamelen van logboeken te beschrijven, werd het begin jaren 2000 gepubliceerd RFC 3164, die remote_syslog standaardiseerde. Dit is hoe een ander belangrijk onderdeel verscheen: logboekverzamelaar en hun opslag.

Met de toename van het volume aan logs en de wijdverbreide introductie van webtechnologieën, rees de vraag welke logs gemakkelijk aan gebruikers moesten worden getoond. Eenvoudige consoletools (awk/sed/grep) zijn vervangen door geavanceerdere log-kijkers - derde onderdeel.

Door de toename van het volume aan logs werd nog iets anders duidelijk: logs zijn nodig, maar niet allemaal. En verschillende logboeken vereisen verschillende niveaus van bewaring: sommige kunnen binnen een dag verloren gaan, terwijl andere vijf jaar moeten worden bewaard. Er werd dus een component voor het filteren en routeren van gegevensstromen aan het logsysteem toegevoegd, laten we het zo noemen filter.

Ook de opslag heeft een grote sprong gemaakt: van gewone bestanden naar relationele databases, en vervolgens naar documentgeoriënteerde opslag (bijvoorbeeld Elasticsearch). De opslag werd dus gescheiden van de collector.

Uiteindelijk is het concept van een logboek uitgegroeid tot een soort abstracte stroom van gebeurtenissen die we willen bewaren voor de geschiedenis. Of beter gezegd: als u een onderzoek moet uitvoeren of een analyserapport moet opstellen...

Hierdoor heeft de logverzameling zich in relatief korte tijd ontwikkeld tot een belangrijk subsysteem, dat met recht een van de subsecties binnen Big Data mag worden genoemd.

Logt vandaag in Kubernetes in (en niet alleen): verwachtingen en realiteit
Als gewone afdrukken ooit voldoende konden zijn voor een ‘logsysteem’, is de situatie nu veel veranderd.

Kubernetes en logboeken

Toen Kubernetes naar de infrastructuur kwam, ging het al bestaande probleem van het verzamelen van logs er ook niet omheen. In sommige opzichten werd het zelfs nog pijnlijker: het beheer van het infrastructuurplatform werd niet alleen vereenvoudigd, maar tegelijkertijd ook ingewikkeld. Veel oude services zijn begonnen met de migratie naar microservices. In de context van logs wordt dit weerspiegeld in het groeiende aantal logbronnen, hun speciale levenscyclus en de noodzaak om de relaties van alle systeemcomponenten te volgen via logs...

Vooruitkijkend kan ik zeggen dat er momenteel helaas geen gestandaardiseerde logoptie voor Kubernetes bestaat die gunstig afsteekt bij alle andere. De meest populaire schema's in de gemeenschap zijn als volgt:

  • iemand rolt de stapel uit SFAO (Elasticsearch, Fluentd, Kibana);
  • iemand probeert het onlangs uitgebrachte Loki of gebruikt Logboekoperator;
  • ons (en misschien niet alleen wij?..) Ik ben grotendeels tevreden met mijn eigen ontwikkeling - blokhut...

In de regel gebruiken we de volgende bundels in K8s-clusters (voor zelfgehoste oplossingen):

Ik zal echter niet stilstaan ​​bij instructies voor hun installatie en configuratie. In plaats daarvan zal ik me concentreren op hun tekortkomingen en op meer globale conclusies over de situatie met logboeken in het algemeen.

Oefen met logs in K8s

Logt vandaag in Kubernetes in (en niet alleen): verwachtingen en realiteit

“Dagelijkse logboeken”, hoeveel van jullie zijn er?..

Voor het gecentraliseerd verzamelen van logbestanden uit een vrij grote infrastructuur zijn aanzienlijke middelen nodig, die zullen worden besteed aan het verzamelen, opslaan en verwerken van logbestanden. Tijdens de uitvoering van verschillende projecten werden wij geconfronteerd met verschillende eisen en daaruit voortvloeiende operationele problemen.

Laten we ClickHouse proberen

Laten we eens kijken naar een gecentraliseerde opslag van een project met een applicatie die vrij actief logboeken genereert: meer dan 5000 regels per seconde. Laten we aan de slag gaan met zijn logbestanden en deze toevoegen aan ClickHouse.

Zodra maximale realtime vereist is, wordt de 4-core server met ClickHouse al overbelast op het schijfsubsysteem:

Logt vandaag in Kubernetes in (en niet alleen): verwachtingen en realiteit

Dit soort laden is te wijten aan het feit dat we zo snel mogelijk in ClickHouse proberen te schrijven. En de database reageert hierop met een verhoogde schijfbelasting, wat de volgende fouten kan veroorzaken:

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

Feit is dat MergeTree-tabellen in ClickHouse (ze bevatten loggegevens) hebben hun eigen problemen tijdens schrijfbewerkingen. De gegevens die erin worden ingevoegd, genereren een tijdelijke partitie, die vervolgens wordt samengevoegd met de hoofdtabel. Als gevolg hiervan blijkt de opname erg veeleisend te zijn voor de schijf, en is deze ook onderworpen aan de beperking waarover we hierboven bericht kregen: er kunnen niet meer dan 1 subpartities in 300 seconde worden samengevoegd (in feite zijn dit 300 inserts per seconde).

Om dit gedrag te voorkomen, moet naar ClickHouse schrijven in zo groot mogelijke stukken en niet vaker dan 1 keer per 2 seconden. Het schrijven in grote uitbarstingen suggereert echter dat we minder vaak in ClickHouse moeten schrijven. Dit kan op zijn beurt leiden tot een bufferoverloop en verlies van logbestanden. De oplossing is om de Fluentd-buffer te vergroten, maar dan zal het geheugengebruik ook toenemen.

Noot: Een ander problematisch aspect van onze oplossing met ClickHouse hield verband met het feit dat de partitie in ons geval (loghouse) wordt geïmplementeerd via externe tabellen die met elkaar zijn verbonden Tabel samenvoegen. Dit leidt ertoe dat bij het bemonsteren van grote tijdsintervallen overmatig RAM nodig is, aangezien de metatable alle partities doorloopt - zelfs de partities die duidelijk niet de benodigde gegevens bevatten. Nu kan deze aanpak echter veilig achterhaald worden verklaard voor de huidige versies van ClickHouse (c 18.16).

Als gevolg hiervan wordt duidelijk dat niet elk project over voldoende middelen beschikt om logboeken in realtime in ClickHouse te verzamelen (meer precies, de distributie ervan zal niet geschikt zijn). Bovendien zul je moeten gebruiken аккумулятор, waar we later op terugkomen. Het hierboven beschreven geval is reëel. En op dat moment waren we niet in staat een betrouwbare en stabiele oplossing aan te bieden die bij de klant zou passen en ons in staat zou stellen om met minimale vertraging logs te verzamelen...

Hoe zit het met Elasticsearch?

Het is bekend dat Elasticsearch zware werklasten aankan. Laten we het in hetzelfde project proberen. De belasting ziet er nu als volgt uit:

Logt vandaag in Kubernetes in (en niet alleen): verwachtingen en realiteit

Elasticsearch was in staat de datastroom te verwerken, maar bij het schrijven van dergelijke volumes wordt de CPU enorm gebruikt. Dit wordt besloten door het organiseren van een cluster. Technisch gezien is dit geen probleem, maar het blijkt dat we, alleen al om het logverzamelingssysteem te bedienen, al ongeveer 8 kernen gebruiken en een extra zwaarbelaste component in het systeem hebben...

Kort gezegd: deze optie kan gerechtvaardigd zijn, maar alleen als het project groot is en het management bereid is aanzienlijke middelen te besteden aan een gecentraliseerd logboekregistratiesysteem.

Dan rijst er een natuurlijke vraag:

Welke logboeken zijn echt nodig?

Logt vandaag in Kubernetes in (en niet alleen): verwachtingen en realiteit Laten we proberen de aanpak zelf te veranderen: logboeken moeten tegelijkertijd informatief zijn en geen dekking elk gebeurtenis in het systeem.

Laten we zeggen dat we een succesvolle online winkel hebben. Welke logboeken zijn belangrijk? Het is een geweldig idee om zoveel mogelijk informatie te verzamelen, bijvoorbeeld van een betalingsgateway. Maar niet alle logs van de image slicing-service in de productcatalogus zijn voor ons van cruciaal belang: alleen fouten en geavanceerde monitoring zijn voldoende (bijvoorbeeld het percentage van 500 fouten dat dit onderdeel genereert).

Wij zijn dus tot de conclusie gekomen dat gecentraliseerde registratie is niet altijd gerechtvaardigd. Heel vaak wil de klant alle logboeken op één plek verzamelen, hoewel in feite van het hele logboek slechts een voorwaardelijke 5% van de berichten nodig is die cruciaal zijn voor het bedrijf:

  • Soms is het voldoende om bijvoorbeeld alleen de grootte van het containerlogboek en de foutenverzamelaar (bijvoorbeeld Sentry) te configureren.
  • Vaak zijn een foutmelding en een groot lokaal logbestand al voldoende om incidenten te onderzoeken.
  • We hadden projecten die het deden met uitsluitend functionele tests en systemen voor het verzamelen van fouten. De ontwikkelaar had als zodanig geen logbestanden nodig: ze zagen alles vanaf foutsporen.

Illustratie uit het leven

Een ander verhaal kan als goed voorbeeld dienen. We kregen een verzoek van het securityteam van een van onze klanten die al gebruik maakte van een commerciële oplossing die lang vóór de introductie van Kubernetes was ontwikkeld.

Het was nodig om “vrienden te maken” van het gecentraliseerde systeem voor het verzamelen van logboeken met de bedrijfsprobleemdetectiesensor - QRadar. Dit systeem kan logbestanden ontvangen via het syslog-protocol en deze ophalen via FTP. Het was echter niet meteen mogelijk om het te integreren met de remote_syslog-plug-in voor fluent (zoals later bleek, we zijn niet alleen). Problemen met het opzetten van QRadar bleken aan de kant van het beveiligingsteam van de klant te liggen.

Als gevolg hiervan werd een deel van de bedrijfskritische logs geüpload naar FTP QRadar, en het andere deel werd via externe syslog rechtstreeks vanaf de knooppunten omgeleid. Hiervoor hebben we zelfs geschreven eenvoudige grafiek - misschien helpt het iemand een soortgelijk probleem op te lossen... Dankzij het resulterende schema ontving en analyseerde de klant zelf kritische logs (met behulp van zijn favoriete tools), en konden we de kosten van het logsysteem verlagen, waardoor alleen de kosten werden bespaard vorige maand.

Een ander voorbeeld is heel indicatief voor wat u niet moet doen. Eén van onze opdrachtgevers voor verwerking elke gebeurtenissen afkomstig van de gebruiker, gemaakt van meerdere regels ongestructureerde uitvoer informatie in log. Zoals je misschien wel vermoedt, waren dergelijke logboeken uiterst onhandig om te lezen en op te slaan.

Criteria voor logboeken

Dergelijke voorbeelden leiden tot de conclusie dat u naast het kiezen van een systeem voor het verzamelen van boomstammen dat ook moet doen ontwerp ook de logs zelf! Wat zijn hier de eisen?

  • Logboeken moeten een machinaal leesbare indeling hebben (bijvoorbeeld JSON).
  • Logboeken moeten compact zijn en de mogelijkheid hebben om de mate van loggen te wijzigen om mogelijke problemen op te lossen. Tegelijkertijd moet u in productieomgevingen systemen gebruiken met een logniveau zoals waarschuwing of Fout.
  • Logboeken moeten worden genormaliseerd, dat wil zeggen dat in een logobject alle regels hetzelfde veldtype moeten hebben.

Ongestructureerde logboeken kunnen leiden tot problemen bij het laden van logboeken in de opslag en een volledige stopzetting van de verwerking ervan. Ter illustratie is hier een voorbeeld met fout 400, die velen zeker zijn tegengekomen in vloeiende logs:

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

De fout betekent dat u een veld waarvan het type instabiel is naar de index stuurt met een kant-en-klare mapping. Het eenvoudigste voorbeeld is een veld in het nginx-logboek met een variabele $upstream_status. Het kan een getal of een string bevatten. Bijvoorbeeld:

{ "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"}

Uit de logboeken blijkt dat server 10.100.0.10 reageerde met een 404-fout en dat het verzoek naar een andere inhoudsopslag werd verzonden. Als gevolg hiervan werd de waarde in de logboeken als volgt:

"upstream_response_time": "0.001, 0.007"

Deze situatie komt zo vaak voor dat het zelfs een aparte verdient verwijzingen in documentatie.

Hoe zit het met de betrouwbaarheid?

Er zijn momenten waarop alle logboeken, zonder uitzondering, van vitaal belang zijn. En hiermee hebben de typische schema's voor het verzamelen van logbestanden voor K8's die hierboven zijn voorgesteld/besproken problemen.

Vloeiend kan bijvoorbeeld geen boomstammen verzamelen uit containers met een korte levensduur. In een van onze projecten leefde de databasemigratiecontainer minder dan 4 seconden en werd vervolgens verwijderd - volgens de bijbehorende annotatie:

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

Hierdoor werd het migratie-uitvoeringslogboek niet opgenomen in de opslag. De politiek kan in dit geval helpen. before-hook-creation.

Een ander voorbeeld is Docker-logboekrotatie. Laten we zeggen dat er een toepassing is die actief naar logboeken schrijft. Onder normale omstandigheden slagen we erin om alle logs te verwerken, maar zodra er een probleem optreedt (bijvoorbeeld zoals hierboven beschreven met een onjuist formaat) stopt de verwerking en roteert Docker het bestand. Het gevolg is dat bedrijfskritische logbestanden verloren kunnen gaan.

Het is precies dat het is belangrijk om logstromen te scheiden, waarbij de meest waardevolle bestanden rechtstreeks naar de applicatie worden verzonden om hun veiligheid te garanderen. Bovendien zou het niet overbodig zijn om er enkele te creëren “accumulator” van logboeken, die een korte onbeschikbaarheid van de opslag kan overleven terwijl kritieke berichten worden opgeslagen.

Tenslotte mogen we dat niet vergeten Het is belangrijk om elk subsysteem goed te monitoren. Anders kun je gemakkelijk in een situatie terechtkomen waarin vloeiend zich in een staat bevindt CrashLoopBackOff en verzendt niets, en dit belooft het verlies van belangrijke informatie.

Bevindingen

In dit artikel kijken we niet naar SaaS-oplossingen zoals Datadog. Veel van de hier beschreven problemen zijn op de een of andere manier al opgelost door commerciële bedrijven die gespecialiseerd zijn in het verzamelen van logs, maar om verschillende redenen kan niet iedereen SaaS gebruiken (de belangrijkste zijn kosten en naleving van 152-FZ).

Gecentraliseerde logboekverzameling lijkt op het eerste gezicht een eenvoudige taak, maar dat is het helemaal niet. Het is belangrijk om te onthouden dat:

  • Alleen kritische componenten hoeven gedetailleerd te worden vastgelegd, terwijl monitoring en foutverzameling voor andere systemen kunnen worden geconfigureerd.
  • Logboeken tijdens de productie moeten minimaal worden gehouden om geen onnodige belasting toe te voegen.
  • Logboeken moeten machineleesbaar en genormaliseerd zijn en een strikt formaat hebben.
  • Echt kritische logboeken moeten in een aparte stroom worden verzonden, die gescheiden moet worden van de belangrijkste.
  • Het is de moeite waard om een ​​​​houtaccumulator te overwegen, die u kan behoeden voor uitbarstingen van hoge belasting en de belasting van de opslag uniformer kan maken.

Logt vandaag in Kubernetes in (en niet alleen): verwachtingen en realiteit
Als deze eenvoudige regels overal zouden worden toegepast, zouden de hierboven beschreven circuits kunnen werken, ook al ontbreken er belangrijke componenten (de batterij). Als u zich niet aan dergelijke principes houdt, zal de taak u en de infrastructuur gemakkelijk naar een ander zwaarbelast (en tegelijkertijd ineffectief) onderdeel van het systeem leiden.

PS

Lees ook op onze blog:

Bron: www.habr.com

Voeg een reactie