Logger inn Kubernetes (og ikke bare) i dag: forventninger og virkelighet

Logger inn Kubernetes (og ikke bare) i dag: forventninger og virkelighet

Det er 2019, og vi har fortsatt ikke en standardløsning for loggaggregering i Kubernetes. I denne artikkelen vil vi, ved å bruke eksempler fra virkelig praksis, dele søkene våre, problemene vi har møtt og deres løsninger.

Men først vil jeg ta forbehold om at forskjellige kunder forstår veldig forskjellige ting ved å samle logger:

  • noen vil se sikkerhets- og revisjonslogger;
  • noen - sentralisert logging av hele infrastrukturen;
  • og for noen er det nok å bare samle applikasjonslogger, unntatt for eksempel balansere.

Nedenfor er snittet nedenfor om hvordan vi implementerte ulike "ønskelister" og hvilke vanskeligheter vi møtte.

Teori: om loggingsverktøy

Bakgrunn om komponentene i et loggsystem

Logging har kommet langt, som følge av at det er utviklet metodikk for innsamling og analyse av logger, som er det vi bruker i dag. Tilbake på 1950-tallet introduserte Fortran en analog av standard input/output-strømmer, som hjalp programmereren med å feilsøke programmet sitt. Dette var de første dataloggene som gjorde livet enklere for programmerere på den tiden. I dag ser vi i dem den første komponenten i loggingssystemet - kilde eller "produsent" av logger.

Datavitenskapen sto ikke stille: datanettverk dukket opp, de første klyngene... Komplekse systemer bestående av flere datamaskiner begynte å fungere. Nå ble systemadministratorer tvunget til å samle logger fra flere maskiner, og i spesielle tilfeller kunne de legge til OS-kjernemeldinger i tilfelle de trengte å undersøke en systemfeil. For å beskrive sentraliserte logginnsamlingssystemer ble den publisert på begynnelsen av 2000-tallet RFC 3164, som standardiserte remote_syslog. Slik så en annen viktig komponent ut: tømmerstokksamler og deres oppbevaring.

Med økningen i volumet av logger og den utbredte introduksjonen av nettteknologier, oppsto spørsmålet om hvilke logger som enkelt må vises til brukerne. Enkle konsollverktøy (awk/sed/grep) er erstattet av mer avanserte loggseere - tredje komponent.

På grunn av økningen i volumet av tømmerstokker, ble noe annet klart: tømmerstokker er nødvendig, men ikke alle. Og forskjellige tømmerstokker krever forskjellige nivåer av bevaring: noen kan gå tapt på en dag, mens andre må lagres i 5 år. Så en komponent for filtrering og ruting av datastrømmer ble lagt til loggingssystemet - la oss kalle det filter.

Lagring har også tatt et stort sprang: fra vanlige filer til relasjonsdatabaser, og deretter til dokumentorientert lagring (for eksempel Elasticsearch). Så lageret ble skilt fra samleren.

Til syvende og sist har selve konseptet med en tømmerstokk utvidet seg til en slags abstrakt strøm av hendelser som vi ønsker å bevare for historien. Eller rettere sagt, i tilfelle du trenger å gjennomføre en undersøkelse eller utarbeide en analytisk rapport...

Som et resultat av dette har logginnsamling på relativt kort tid utviklet seg til et viktig delsystem, som med rette kan kalles en av underseksjonene i Big Data.

Logger inn Kubernetes (og ikke bare) i dag: forventninger og virkelighet
Hvis vanlige utskrifter en gang kunne være nok for et "loggingssystem", nå har situasjonen endret seg mye.

Kubernetes og logger

Da Kubernetes kom til infrastrukturen, gikk det allerede eksisterende problemet med innsamling av logger heller ikke utenom det. På noen måter ble det enda mer smertefullt: administrasjon av infrastrukturplattformen ble ikke bare forenklet, men også komplisert på samme tid. Mange gamle tjenester har begynt å migrere til mikrotjenester. I sammenheng med logger gjenspeiles dette i det økende antallet loggkilder, deres spesielle livssyklus og behovet for å spore relasjonene til alle systemkomponenter gjennom logger...

Når jeg ser fremover, kan jeg slå fast at nå, dessverre, er det ikke noe standardisert loggingsalternativ for Kubernetes som kan sammenlignes med alle andre. De mest populære ordningene i samfunnet er som følger:

  • noen ruller ut stabelen EFK (Elasticsearch, Fluentd, Kibana);
  • noen prøver den nylig utgitte Loki eller bruker Loggingsoperatør;
  • oss (og kanskje ikke bare oss?..) Jeg er stort sett fornøyd med min egen utvikling - tre hus...

Som regel bruker vi følgende bunter i K8s-klynger (for selvhostede løsninger):

Jeg vil imidlertid ikke dvele ved instruksjoner for installasjon og konfigurasjon. I stedet vil jeg fokusere på deres mangler og mer globale konklusjoner om situasjonen med logger generelt.

Øv med logger i K8s

Logger inn Kubernetes (og ikke bare) i dag: forventninger og virkelighet

"Hverdagslogger", hvor mange av dere er der?..

Sentralisert innsamling av logger fra en ganske stor infrastruktur krever betydelige ressurser, som vil bli brukt på innsamling, lagring og behandling av logger. Under driften av ulike prosjekter ble vi møtt med ulike krav og driftsproblemer som følge av disse.

La oss prøve ClickHouse

La oss se på en sentralisert lagring på et prosjekt med en applikasjon som genererer logger ganske aktivt: mer enn 5000 linjer per sekund. La oss begynne å jobbe med loggene hans og legge dem til ClickHouse.

Så snart maksimal sanntid kreves, vil 4-kjerneserveren med ClickHouse allerede være overbelastet på diskundersystemet:

Logger inn Kubernetes (og ikke bare) i dag: forventninger og virkelighet

Denne typen lasting skyldes at vi prøver å skrive i ClickHouse så raskt som mulig. Og databasen reagerer på dette med økt diskbelastning, noe som kan forårsake følgende feil:

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

Faktum er at MergeTree-tabeller i ClickHouse (de inneholder loggdata) har sine egne problemer under skriveoperasjoner. Dataene som er satt inn i dem genererer en midlertidig partisjon, som deretter slås sammen med hovedtabellen. Som et resultat viser opptaket seg å være svært krevende på disken, og det er også underlagt begrensningen som vi fikk melding om ovenfor: ikke mer enn 1 underpartisjoner kan slås sammen på 300 sekund (faktisk er dette 300 innlegg per sekund).

For å unngå denne oppførselen, skal skrive til ClickHouse i så store biter som mulig og ikke mer enn 1 gang hvert 2. sekund. Men å skrive i store serier antyder at vi bør skrive sjeldnere i ClickHouse. Dette kan igjen føre til bufferoverløp og tap av tømmerstokker. Løsningen er å øke Fluentd-bufferen, men da vil også minneforbruket øke.

Note: Et annet problematisk aspekt ved løsningen vår med ClickHouse var relatert til det faktum at partisjonering i vårt tilfelle (logghus) er implementert gjennom eksterne tabeller koblet til Slå sammen tabell. Dette fører til det faktum at ved sampling av store tidsintervaller kreves overdreven RAM, siden metatablen itererer gjennom alle partisjoner - også de som åpenbart ikke inneholder de nødvendige dataene. Men nå kan denne tilnærmingen trygt erklæres foreldet for gjeldende versjoner av ClickHouse (ca 18.16).

Som et resultat blir det klart at ikke alle prosjekter har nok ressurser til å samle logger i sanntid i ClickHouse (mer presist, deres distribusjon vil ikke være hensiktsmessig). I tillegg må du bruke batteri, som vi kommer tilbake til senere. Saken beskrevet ovenfor er reell. Og på den tiden var vi ikke i stand til å tilby en pålitelig og stabil løsning som passet kunden og lar oss samle inn logger med minimal forsinkelse...

Hva med Elasticsearch?

Elasticsearch er kjent for å håndtere store arbeidsbelastninger. La oss prøve det i samme prosjekt. Nå ser belastningen slik ut:

Logger inn Kubernetes (og ikke bare) i dag: forventninger og virkelighet

Elasticsearch var i stand til å fordøye datastrømmen, men å skrive slike volumer til den bruker CPU i stor grad. Dette bestemmes ved å organisere en klynge. Teknisk sett er dette ikke noe problem, men det viser seg at bare for å betjene logginnsamlingssystemet bruker vi allerede ca 8 kjerner og har en ekstra høyt belastet komponent i systemet...

Bunnlinjen: dette alternativet kan rettferdiggjøres, men bare hvis prosjektet er stort og ledelsen er klar til å bruke betydelige ressurser på et sentralisert loggingssystem.

Da oppstår et naturlig spørsmål:

Hvilke logger trengs egentlig?

Logger inn Kubernetes (og ikke bare) i dag: forventninger og virkelighet La oss prøve å endre selve tilnærmingen: logger skal samtidig være informative og ikke dekke Hver hendelse i systemet.

La oss si at vi har en vellykket nettbutikk. Hvilke logger er viktige? Å samle så mye informasjon som mulig, for eksempel fra en betalingsgateway, er en god idé. Men ikke alle loggene fra bildeskjæringstjenesten i produktkatalogen er kritiske for oss: bare feil og avansert overvåking er nok (for eksempel prosentandelen av 500 feil som denne komponenten genererer).

Så vi har kommet til den konklusjonen sentralisert logging er ikke alltid berettiget. Svært ofte ønsker klienten å samle alle loggene på ett sted, selv om det faktisk bare kreves en betinget 5% av meldingene som er kritiske for virksomheten fra hele loggen:

  • Noen ganger er det nok å konfigurere, for eksempel, bare størrelsen på beholderloggen og feilsamleren (for eksempel Sentry).
  • En feilmelding og en stor lokal logg i seg selv kan ofte være nok til å undersøke hendelser.
  • Vi hadde prosjekter som klarte seg med utelukkende funksjonstester og feiloppsamlingssystemer. Utvikleren trengte ikke logger som sådan - de så alt fra feilspor.

Illustrasjon fra livet

En annen historie kan tjene som et godt eksempel. Vi mottok en forespørsel fra sikkerhetsteamet til en av våre kunder som allerede brukte en kommersiell løsning som ble utviklet lenge før introduksjonen av Kubernetes.

Det var nødvendig å "bli venner" med det sentraliserte logginnsamlingssystemet med bedriftens problemdeteksjonssensor - QRadar. Dette systemet kan motta logger via syslog-protokollen og hente dem fra FTP. Det var imidlertid ikke umiddelbart mulig å integrere den med remote_syslog-pluginen for fluentd (som det viste seg, vi er ikke alene). Problemer med å sette opp QRadar viste seg å være på siden av klientens sikkerhetsteam.

Som et resultat ble en del av de forretningskritiske loggene lastet opp til FTP QRadar, og den andre delen ble omdirigert via ekstern syslog direkte fra nodene. For dette skrev vi til og med enkelt diagram - kanskje det vil hjelpe noen med å løse et lignende problem... Takket være det resulterende opplegget mottok og analyserte klienten selv kritiske logger (ved hjelp av favorittverktøyene hans), og vi var i stand til å redusere kostnadene for loggingssystemet, og sparte bare forrige måned.

Et annet eksempel er ganske veiledende for hva man ikke skal gjøre. En av våre kunder for behandling av hver hendelser som kommer fra brukeren, laget multiline ustrukturert produksjon informasjon i loggen. Som du kanskje gjetter, var slike logger ekstremt upraktiske å både lese og lagre.

Kriterier for logger

Slike eksempler fører til konklusjonen at i tillegg til å velge et logginnsamlingssystem, må du også designe stokkene selv! Hva er kravene her?

  • Logger må være i maskinlesbart format (for eksempel JSON).
  • Logger skal være kompakte og med mulighet for å endre loggingsgrad for å feilsøke mulige problemer. Samtidig bør du i produksjonsmiljøer kjøre systemer med et loggingsnivå som Advarsel eller Feil.
  • Logger skal normaliseres, det vil si at i et loggobjekt må alle linjer ha samme felttype.

Ustrukturerte logger kan føre til problemer med lasting av logger til lagring og fullstendig stopp i behandlingen. Som en illustrasjon, her er et eksempel med feil 400, som mange definitivt har støtt på i flytende logger:

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

Feilen betyr at du sender et felt hvis type er ustabil til indeksen med en ferdig tilordning. Det enkleste eksemplet er et felt i nginx-loggen med en variabel $upstream_status. Den kan inneholde enten et tall eller en streng. For eksempel:

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

Loggene viser at server 10.100.0.10 svarte med en 404-feil og forespørselen ble sendt til en annen innholdslagring. Som et resultat ble verdien i loggene slik:

"upstream_response_time": "0.001, 0.007"

Denne situasjonen er så vanlig at den til og med fortjener en separat referanser i dokumentasjon.

Hva med pålitelighet?

Det er tider når alle logger uten unntak er viktige. Og med dette har de typiske logginnsamlingsordningene for K8-er foreslått/diskutert ovenfor problemer.

For eksempel kan ikke fluentd samle tømmerstokker fra kortlivede beholdere. I et av våre prosjekter levde databasemigreringsbeholderen i mindre enn 4 sekunder og ble deretter slettet - i henhold til den tilsvarende merknaden:

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

På grunn av dette ble ikke utførelsesloggen for migrering inkludert i lagringen. Politikk kan hjelpe i dette tilfellet. before-hook-creation.

Et annet eksempel er Docker-loggrotasjon. La oss si at det er en applikasjon som aktivt skriver til logger. Under normale forhold klarer vi å behandle alle loggene, men så snart et problem dukker opp – for eksempel som beskrevet ovenfor med feil format – stopper behandlingen, og Docker roterer filen. Resultatet er at forretningskritiske logger kan gå tapt.

Det er derfor det er viktig å skille loggstrømmer, innebygging sender de mest verdifulle direkte inn i applikasjonen for å sikre deres sikkerhet. I tillegg ville det ikke være overflødig å lage noen "akkumulator" av logger, som kan overleve kortvarig utilgjengelighet av lagring mens de lagrer kritiske meldinger.

Til slutt må vi ikke glemme det Det er viktig å overvåke ethvert delsystem riktig. Ellers er det lett å havne i en situasjon der flytende er i en tilstand CrashLoopBackOff og sender ikke noe, og dette lover tap av viktig informasjon.

Funn

I denne artikkelen ser vi ikke på SaaS-løsninger som Datadog. Mange av problemene beskrevet her er allerede løst på en eller annen måte av kommersielle selskaper som spesialiserer seg på innsamling av logger, men ikke alle kan bruke SaaS av ulike årsaker (de viktigste er kostnader og samsvar med 152-FZ).

Sentralisert logginnsamling ser først ut som en enkel oppgave, men det er den ikke i det hele tatt. Det er viktig å huske at:

  • Kun kritiske komponenter må logges i detalj, mens overvåking og feilinnsamling kan konfigureres for andre systemer.
  • Logger i produksjonen bør holdes minimale for ikke å legge til unødvendig belastning.
  • Logger må være maskinlesbare, normaliserte og ha et strengt format.
  • Virkelig kritiske logger bør sendes i en egen strøm, som bør skilles fra de viktigste.
  • Det er verdt å vurdere en tømmerakkumulator, som kan redde deg fra utbrudd av høy belastning og gjøre belastningen på lageret mer jevn.

Logger inn Kubernetes (og ikke bare) i dag: forventninger og virkelighet
Disse enkle reglene, hvis de brukes overalt, ville tillate kretsene beskrevet ovenfor å fungere - selv om de mangler viktige komponenter (batteriet). Hvis du ikke følger slike prinsipper, vil oppgaven lett føre deg og infrastrukturen til en annen høyt belastet (og samtidig ineffektiv) komponent i systemet.

PS

Les også på bloggen vår:

Kilde: www.habr.com

Legg til en kommentar