Логі ў Kubernetes (і не толькі) сёння: чаканні і рэальнасць

Логі ў Kubernetes (і не толькі) сёння: чаканні і рэальнасць

Ішоў 2019 год, а ў нас усё яшчэ няма стандартнага рашэння для агрэгацыі логаў у Kubernetes. У гэтым артыкуле мы хацелі б, выкарыстоўваючы прыклады з рэальнай практыкі, падзяліцца сваімі пошукамі, праблемамі і іх рашэннямі.

Аднак для пачатку абмоўлюся, што розныя заказчыкі пад зборам логаў разумеюць вельмі рознае:

  • хтосьці хоча бачыць security-і audit-лагі;
  • хтосьці - цэнтралізаванае лагіраванне ўсёй інфраструктуры;
  • а камусьці дастаткова збіраць толькі логі прыкладання, выключыўшы, напрыклад, балансавальнікі.

Пра тое, як мы рэалізоўвалі розныя «хатэлкі» і з якімі цяжкасцямі сутыкнуліся, - пад катам.

Тэорыя: пра прылады для логаў

Перадгісторыя аб кампанентах сістэмы лагавання

Лагіраванне прайшло доўгі шлях, у выніку якога выпрацаваліся метадалогіі збору і аналізу логаў, што мы і ўжываем сёння. Яшчэ ў 1950-х гадах у Fortran з'явіўся аналаг стандартных патокаў уводу-вываду, якія дапамагалі праграмісту ў адладцы яго праграмы. Гэта былі першыя кампутарныя логі, якія палягчалі жыццё праграмістам тых часоў. На сёння мы ў іх бачым першы кампанент сістэмы лагавання. крыніца або "вытворца" (producer) логаў.

Кампутарная навука не стаяла на месцы: з'явіліся кампутарныя сеткі, першыя кластары… Пачалі працаваць складаныя сістэмы, якія складаюцца з некалькіх кампутараў. Зараз сістэмныя адміністратары змушаныя былі збіраць логі з некалькіх машын, а ў адмысловых выпадках маглі дадаваць і паведамленні ядра АС на выпадак, калі запатрабуецца расследаваць сістэмны збой. Каб апісаць сістэмы цэнтралізаванага збору логаў, у пачатку 2000-х выходзіць RFC 3164, Які стандартызаваў remote_syslog. Так з'явіўся яшчэ адзін важны кампанент: калектар (зборшчык) логаў і іх сховішча.

З павелічэннем аб'ёму логаў і паўсюдным укараненнем вэб-тэхналогій паўстала пытанне аб тым, што логі трэба зручна паказаць карыстачам. На змену простым кансольным прыладам (awk/sed/grep) дашлі больш прасунутыя праглядальнікі логаў - Трэці кампанент.

У сувязі з павелічэннем аб'ёму логаў стала зразумела і іншае: логі патрэбныя, але не ўсё. А яшчэ розныя логі патрабуюць рознага ўзроўню захаванасці: адны можна страціць праз дзень, а іншыя - трэба захоўваць 5 гадоў. Так у сістэму лагавання дадаўся кампанент фільтрацыі і маршрутызацыі патокаў дадзеных - назавем яго фільтрам.

Сховішчы таксама зрабілі сур'ёзны скок: са звычайных файлаў перайшлі на рэляцыйныя базы дадзеных, а затым і на дакументаарыентаваныя сховішчы (напрыклад, Elasticsearch). Так ад калектара аддзялілася сховішча.

У рэшце рэшт само паняцце лога пашырылася да нейкага абстрактнага патоку падзей, якія мы хочам захоўваць для гісторыі. А дакладней - на той выпадак, калі спатрэбіцца правесці расследаванне або скласці аналітычны справаздачу ...

У выніку, за параўнальна невялікі прамежак часу, збор логаў развіўся ў важную падсістэму, якую па праве можна назваць адным з падраздзелаў у Big Data.

Логі ў Kubernetes (і не толькі) сёння: чаканні і рэальнасць
Калі калісьці звычайных print'аў магло быць дастаткова для "сістэмы лагавання", то зараз сітуацыя моцна змянілася.

Kubernetes і логі

Калі ў інфраструктуру прыйшоў Kubernetes, існавалая і без таго праблема збору логаў не абыйшла бокам і яго. У некаторым сэнсе яна стала нават больш балючай: кіраванне інфраструктурнай платформай было не толькі спрошчана, але і адначасова ўскладнена. Многія старыя сэрвісы пачалі міграцыю на мікрасэрвісныя рэйкі. У кантэксце логаў гэта выявілася ў якая расце ліку крыніц логаў, іх адмысловым жыццёвым цыкле, і неабходнасці адсочваць праз логі ўзаемасувязі ўсіх кампанентаў сістэмы…

Забягаючы наперад, магу канстатаваць, што цяпер, нажаль, няма стандартызаванага варыянту лагавання для Kubernetes, які б выгодна адрозніваўся ад усіх астатніх. Найбольш папулярныя ў супольнасці схемы зводзяцца да наступных:

  • хтосьці разгортвае стэк ЭФК (Elasticsearch, Fluentd, Kibana);
  • хтосьці - спрабуе нядаўна выпушчаны Локі або выкарыстоўвае Logging operator;
  • нас (а магчыма, і не толькі нас?..) шмат у чым задавальняе ўласная распрацоўка loghouse...

Як правіла, мы выкарыстоўваем такія звязкі ў K8s-кластарах (для self-hosted-рашэнняў):

Аднак не буду спыняцца на інструкцыях па іх усталёўцы і канфігурацыі. Замест гэтага, сфакусуюся на іх недахопах і больш глабальных высновах па сітуацыі з логамі ў цэлым.

Практыка з логамі ў K8s

Логі ў Kubernetes (і не толькі) сёння: чаканні і рэальнасць

"Паўсядзённыя логі", колькі ж вас?

Цэнтралізаваны збор логаў з дастаткова вялікай інфраструктуры патрабуе немалых рэсурсаў, якія пойдуць на збор, захоўванне і апрацоўку логаў. Падчас эксплуатацый розных праектаў мы сутыкнуліся з рознымі патрабаваннямі і якія ўзнікаюць з-за іх праблемамі ў эксплуатацыі.

Паспрабуем ClickHouse

Давайце разгледзім цэнтралізаванае сховішча на праекце з дадаткам, якое даволі актыўна генеруе логі: больш за 5000 радкоў у секунду. Пачнём працу з яго логамі, складаючы іх у ClickHouse.

Як толькі запатрабуецца максімальны realtime, 4-ядзерны сервер з ClickHouse ужо будзе перагружаны па дыскавай падсістэме:

Логі ў Kubernetes (і не толькі) сёння: чаканні і рэальнасць

Падобны тып загрузкі злучаны з тым, што мы спрабуем максімальна хутка пісаць у ClickHouse. І на гэта БД рэагуе падвышанай дыскавай нагрузкай, з-за чаго можа выдаваць такія памылкі:

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

Справа ў тым, што MergeTree-табліцы у ClickHouse (у іх ляжаць дадзеныя логаў) маюць свае складанасці пры аперацыях запісу. Устаўляемыя ў іх дадзеныя генеруюць часавую партыцыю, якая потым зліваецца з асноўнай табліцай. У выніку, запіс атрымліваецца вельмі патрабавальным да дыска, а таксама на яго распаўсюджваецца абмежаванне, апавяшчэнне аб якім мы і атрымалі вышэй: у 1 секунду могуць злівацца не больш за 300 субпартыцый (фактычна гэта 300 insert'аў у секунду).

Каб пазбегнуць падобных паводзін, варта пісаць у ClickHouse як мага больш вялікімі кавалкамі і не часцей за 1 раз у 2 секунды. Аднак запіс вялікімі пачкамі мяркуе, што мы павінны радзей пісаць у ClickHouse. Гэта, у сваю чаргу, можа прывесці да перапаўнення буфера і да страты логаў. Рашэнне - павялічыць буфер Fluentd, але тады павялічыцца і спажыванне памяці.

Заўвага: Іншы праблемны бок нашага рашэння з ClickHouse быў звязаны з тым, што партыцыраванне ў нашым выпадку (loghouse) рэалізавана праз знешнія табліцы, звязаныя. Merge-табліцай. Гэта прыводзіць да таго, што пры выбарцы вялікіх часавых інтэрвалаў патрабуецца залішняя аператыўная памяць, паколькі метатабліца перабірае ўсе партіціі - нават тыя, якія загадзя не ўтрымліваюць патрэбныя дадзеныя. Зрэшты, зараз такі падыход можна смела абвясціць састарэлым для актуальных версій ClickHouse (c 18.16).

У выніку, становіцца зразумела, што для збору логаў у рэальным часе ў ClickHouse хопіць рэсурсаў далёка не кожнага праекта (дакладней, іх размеркаванне не будзе мэтазгодным). Акрамя таго, спатрэбіцца выкарыстоўваць акумулятар, да якога мы яшчэ вернемся. Апісваны вышэй выпадак - рэальны. І на той момант мы не змаглі прапанаваць надзейнае і стабільнае рашэнне, якое б уладкоўвала замоўца і дазволіла б збіраць логі з мінімальнай затрымкай…

А Elasticsearch?

Вядома, што Elasticsearch спраўляецца з вялікімі нагрузкамі. Паспрабуем яго ў тым жа праекце. Цяпер нагрузка выглядае наступным чынам:

Логі ў Kubernetes (і не толькі) сёння: чаканні і рэальнасць

Elasticsearch змог пераварыць струмень дадзеных, аднак запіс падобных аб'ёмаў у яго моцна ўтылізуе CPU. Гэта вырашаецца арганізацыяй кластара. Чыста тэхнічна гэта не праблема, аднак атрымаецца, што толькі для працы сістэмы збору логаў мы ўжо выкарыстаем каля 8 ядраў і маем дадатковы высоканагружаны кампанент у сістэме…

Вынік: такі варыянт можа быць апраўданы, але толькі ў тым выпадку, калі праект вялікі і яго кіраўніцтва гатова выдаткаваць заўважныя рэсурсы на сістэму цэнтралізаванага лагіравання.

Тады ўзнікае заканамернае пытанне:

Якія логі сапраўды патрэбны?

Логі ў Kubernetes (і не толькі) сёння: чаканні і рэальнасць Паспрабуем змяніць сам падыход: логі павінны адначасова і быць інфарматыўнымі, і не пакрываць кожнае падзея ў сістэме.

Дапушчальны, у нас ёсць паспяховы інтэрнэт-крама. Якія логі важныя? Збіраць максімум інфармацыі, напрыклад, з плацежнага шлюза - выдатная ідэя. А вось ад сэрвісу нарэзкі малюнкаў у каталогу прадуктаў нам крытычныя не ўсе логі: хопіць толькі памылак і пашыранага маніторынгу (напрыклад, на працэнт 500-х памылак, якія генеруе гэты кампанент).

Вось мы і дашлі да таго, што цэнтралізаванае лагіраванне апраўдана далёка не заўсёды. Вельмі часта кліент жадае сабраць усе логі ў адным месцы, хоць насамрэч з усяго лога патрабуецца толькі ўмоўныя 5% паведамленняў, якія крытычныя для бізнэсу:

  • Часам дастаткова наладзіць, скажам, толькі памер лога кантэйнера і зборшчык памылак (напрыклад, Sentry).
  • Для расследавання інцыдэнтаў часта можа хапіць абвесткі аб памылцы і ўласна вялікага лакальнага лога.
  • У нас былі праекты, якія і зусім абыходзіліся выключна функцыянальнымі тэстамі і сістэмамі збору памылак. Распрацоўніку не патрабаваліся логі як такія - яны ўсё бачылі па трэйс памылак.

Ілюстрацыя з жыцця

Добрым прыкладам можа паслужыць іншая гісторыя. Да нас прыйшоў запыт ад каманды бяспечнікаў аднаго з кліентаў, у якога ўжо выкарыстоўвалася камерцыйнае рашэнне, што было распрацавана задаўга да ўкаранення Kubernetes.

Спатрэбілася «здружыць» сістэму цэнтралізаванага збору логаў з карпаратыўным сэнсарам выяўлення праблем – QRadar. Гэтая сістэма ўмее прымаць логі па пратаколе syslog, забіраць з FTP. Аднак інтэграваць яе з убудовай remote_syslog для fluentd адразу не атрымалася (як выявілася, мы не адны такія). Праблемы з наладай QRadar апынуліся на баку каманды бяспечнікаў кліента.

У выніку, частка логаў, крытычных для бізнэсу, выгружалася на FTP QRadar, а іншая частка – перанакіроўвалася праз remote syslog напроста з вузлоў. Дзеля гэтага мы нават напісалі просты chart - Магчыма, ён дапаможа камусьці вырашыць аналагічную задачу ... Дзякуючы атрыманай схеме, сам кліент атрымліваў і аналізаваў крытычныя логі (з дапамогай свайго каханага інструментара), а мы змаглі знізіць выдаткі на сістэму лагавання, захоўваючы толькі апошні месяц.

Яшчэ адзін прыклад даволі паказальны ў тым, як рабіць не трэба. Адзін з нашых кліентаў на апрацоўку кожнага падзеі, які паступае ад карыстальніка, рабіў шматрадковы неструктураваная выснова інфармацыі ў лог. Як лёгка здагадацца, падобныя логі было вельмі няёмка і чытаць, і захоўваць.

Крытэрыі для логаў

Падобныя прыклады падводзяць да высновы, што акрамя выбару сістэмы збору логаў трэба. спраектаваць яшчэ і самі логі! Якія тут патрабаванні?

  • Логі павінны быць у машыначытальным фармаце (напрыклад, JSON).
  • Логі павінны быць кампактнымі і з магчымасцю змены ступені лагавання, каб адладзіць магчымыя праблемы. Пры гэтым у production-акружэннях варта запускаць сістэмы з узроўнем лагавання накшталт папярэджанне або памылка.
  • Логі павінны быць нармалізаванымі, гэта значыць у аб'екце лога ўсе радкі павінны мець аднолькавы тып поля.

Неструктураваныя логі могуць прывесці да праблем з загрузкай логаў у сховішча і поўным прыпынкам іх апрацоўкі. У якасці ілюстрацыі – прыклад з памылкай 400, з якой многія сапраўды сутыкаліся ў логах fluentd:

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

Памылка азначае, што вы адпраўляеце ў індэкс з гатовым mapping’ам поле, тып якога нестабільны. Найпросты прыклад - поле ў логу nginx з зменнай $upstream_status. У ім можа быць як лік, так і радок. Напрыклад:

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

У логах відаць, што сервер 10.100.0.10 адказаў 404-й памылкай і запыт сышоў на іншае сховішча кантэнту. У выніку, у логах значэнне стала вось такім:

"upstream_response_time": "0.001, 0.007"

Дадзеная сітуацыя настолькі распаўсюджаная, што ганаравалася нават асобнага. згадкі ў дакументацыі.

А што з надзейнасцю?

Бываюць выпадкі, калі жыццёва неабходны ўсе логі без выключэння. І з гэтым у тыпавых схем збору логаў для K8s, прапанаваных/разгляданых вышэй, маюцца праблемы.

Напрыклад, fluentd не можа сабраць логі з кароткажывучых кантэйнераў. У адным з нашых праектаў кантэйнер з міграцыяй баз дадзеных жыў менш за 4 секунды, а затым выдаляўся — згодна з адпаведнай анатацыяй:

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

З-за гэтага лог выканання міграцыі не пападаў у сховішча. Дапамагчы ў дадзеным выпадку можа палітыка before-hook-creation.

Іншы прыклад – ратацыя логаў Docker. Дапусцім, ёсць дадатак, якое актыўна піша ў логі. У звычайных умовах мы паспяваем апрацаваць усе логі, але як толькі з'яўляецца праблема - напрыклад, як была апісана вышэй з няправільным фарматам, - апрацоўка спыняецца, а Docker раціруе файл. Вынік - могуць быць страчаныя крытычныя для бізнесу логі.

Менавіта таму важна падзяляць патокі логаў, убудоўваючы адпраўку найбольш каштоўных напрамую ў дадатак, каб забяспечыць іх захаванасць. Акрамя таго, не будзе лішнім стварэнне нейкага "акумулятара" логаў, які зможа перажыць кароткую недаступнасць сховішчы пры захаванні крытычных паведамленняў.

Урэшце, не трэба забываць, што любую падсістэму важна якасна маніторыць. Інакш лёгка сутыкнуцца з сітуацыяй, у якой fluentd знаходзіцца ў стане CrashLoopBackOff і нічога не адпраўляе, а гэта абяцае стратай важнай інфармацыі.

Высновы

У дадзеным артыкуле мы не разглядаем SaaS-рашэнні накшталт Datadog. Многія з апісаных тут праблем так ці інакш ужо вырашаны камерцыйнымі кампаніямі, якія спецыялізуюцца на зборы логаў, але не ўсе могуць выкарыстоўваць SaaS па розных прычынах. (асноўныя - гэта кошт і захаванне 152-ФЗ).

Цэнтралізаваны збор логаў спачатку выглядае простай задачай, але зусім такой не з'яўляецца. Важна памятаць, што:

  • Лагаваць падрабязна варта толькі крытычныя кампаненты, а для астатніх сістэм можна наладзіць маніторынг і збор памылак.
  • Логі ў production варта рабіць мінімальнымі, каб не даваць лішнюю нагрузку.
  • Логі павінны быць машыначытальнымі, нармалізаванымі, мець строгі фармат.
  • Сапраўды крытычныя логі варта адпраўляць асобным струменем, які павінен быць аддзелены ад асноўных.
  • Варта прадумаць акумулятар логаў, які можа выратаваць ад усплёскаў высокай нагрузкі і зробіць нагрузку на сховішча больш раўнамернай.

Логі ў Kubernetes (і не толькі) сёння: чаканні і рэальнасць
Гэтыя простыя правілы, калі іх ужываць усюды, дазволілі б працаваць і апісаным вышэй схемам – нават нягледзячы на ​​тое, што ў іх бракуе важных кампанентаў (акумулятара). Калі ж не прытрымлівацца такіх прынцыпаў, задача з лёгкасцю прывядзе вас і інфраструктуру да яшчэ аднаго высоканагружанага (і ў той жа час малаэфектыўнага) кампанента сістэмы.

PS

Чытайце таксама ў нашым блогу:

Крыніца: habr.com

Дадаць каментар