Elastic Stack: обзор и установка ELK

Thank you for reading this post, don't forget to subscribe!

10 часов дебаг­гин­га и попы­ток сде­лать и посмот­реть, что полу­чит­ся, сэко­но­мят вам 10 минут чте­ния доку­мен­та­ции“.

 

Elastic Stack: обзор компонентов

Elastic Stack, он же ELK (Elasticsearch + Logstash + Kibana) навер­но наи­бо­лее широ­ко­из­веcт­ная и самая исполь­зу­е­мая систе­ма для сбо­ра и ана­ли­за логов, мет­рик и дру­гих дан­ных о состо­я­нии систем – сер­ве­ров, кла­сте­ров, клаудов.

Состо­ит из трёх основ­ных компонентов:

  • Elasticsearch: база дан­ных с воз­мож­но­стя­ми быст­ро­го поис­ка исполь­зуя Elasticsearch Index
  • Logstash: систе­ма сбо­ра дан­ных из раз­ных источ­ни­ков, их транс­фор­ма­ции и пере­да­чи логов в Elasticsearch
  • Kibana: веб-интер­фейс для отоб­ра­же­ния дан­ных из базы Elasticsearch

Кро­ме того, для ELK (по при­выч­ке уже буду его назы­вать так) суще­ству­ет набор т.н. Beats – ути­лит для сбо­ра дан­ных. Сре­ди них, напри­мер, Filebeat – для сбо­ра дан­ных из фай­лов (логов), или Metricbeat для сбо­ра дан­ных о систе­ме – CPU, RAM и т.д.

Схе­ма рабо­ты сте­ка следующая:

  1. сер­вер гене­ри­ру­ет дан­ные, напри­мер логи
  2. дан­ные соби­ра­ют­ся локаль­ным Beat-при­ло­же­ни­ем, для логов это будет Filebeat (хотя это необя­за­тель­ный ком­по­нент, и логи мож­но соби­рать самим Logstash), и отправ­ля­ет их в Logstash или напря­мую в Elastisearch
  3. Logstash соби­ра­ет дан­ные из раз­лич­ных источ­ни­ков (полу­чая их от Beats или соби­рая напря­мую), при необ­хо­ди­мо­сти выпол­ня­ет транс­фор­ма­цию (добав­ле­ние-уда­ле­ние полей, тегов и т.д.), и отправ­ля­ет их в Elasticsearch
  4. Elasticsearch зани­ма­ет­ся хра­не­ни­ем дан­ных с воз­мож­но­стью быст­ро­го поиска
  5. Kibana предо­став­ля­ет веб-интер­фейс для рабо­ты с Elasticsearch (и мно­же­ство дру­гих инте­гра­ций, но тут мы их рас­смат­ри­вать не будем)

Создание ЕС2

Уста­нав­ли­вать будем на Ubuntu 20.04 на EC2 в AWS.

Под­ни­мем “голую систе­му” – без Docker и Kubernetes, настро­им всё пря­мо на хосте.

Исполь­зу­ем стан­дарт­ный под­ход – Elasticsearch для хра­не­ния, Filebeat для сбо­ра логов, Logstash для пере­да­чи в Elastic, Kibana для визуализации.

Пере­хо­дим в AWS Console > EC2 > Instances, запус­ка­ем новый, выби­ра­ем Ubuntu:

Тип инстан­са возь­мём c5.2xlarge – 4 ядра и 8 гиг памя­ти, т.к. Elasticsaerch – это Java с её любо­вью к памя­ти и CPU, а Logstash – JRuby, кото­рый тоже не слиш­ком эко­но­мит ресур­сы сервера:

Сеть остав­ля­ем по-умол­ча­нию (или выби­ра­ем отдель­ную VPC, если есть): сно­ва-таки – это тесто­вый инстанс, поэто­му нам тут сеть осо­бо роли не играет:

Попо­то­ме доба­вим Elastic IP, что бы не менял­ся при перезагрузке.

Диск с дефолт­ных 8 гиг уве­ли­чим до 50:

В SecurityGroup откры­ва­ем SSH и 5601 (порт Kibana) с ваше­го IP:

В более пол­но­цен­ном сета­пе у нас перед Kibana дол­жен быть NGINX или какой-то Ingress-кон­трол­лер в слу­чае Kubernetes, на кото­ром будет SSL. Сей­час запус­ка­ем “as is”.

Созда­ём новый ключ (hint: хоро­шая идея в име­ни клю­ча ука­зы­вать реги­он), сохра­ня­ем его:

Пере­хо­дим в Elastic IP addresses, полу­ча­ем адрес:

Под­клю­ча­ем его к наше­му инстансу:

На рабо­чей машине меня­ем пра­ва досту­па к клю­чу – остав­ля­ем доступ толь­ко сво­е­му пользователю:

chmod 600 ~/Temp/elk-test-eu-west-2.pem

 

Про­ве­ря­ем подключение:

ssh -i ~/Temp/elk-test-eu-west-2.pem ubuntu@18.135.74.203
ubuntu@ip-172-31-43-4:~$

 

Обнов­ля­ем систему:

ubuntu@ip-172-31-43-4:~$ sudo -s
root@ip-172-31-43-4:/home/ubuntu# apt update && apt -y upgrade

 

Ребу­та­ем­ся, что бы загру­зить новое ядро после апгрей­да системы:

root@ip-172-31-43-4:/home/ubuntu# reboot

 

Пере­хо­дим к уста­нов­ке ком­по­нен­тов ELK.

Установка Elastic Stack/ELK

Добав­ля­ем репо­зи­то­рий Elasticsearch:

Установка Elasticsearch

Уста­нав­ли­ва­ем пакет elasticsearch:

root@ip-172-31-43-4:/home/ubuntu# apt update && apt -y install elasticsearch

 

Файл настро­ек Ела­сти­ки – /etc/elasticsearch/elasticsearch.yml.

Добав­ля­ем в конец фай­ла  discovery.type: single-node – наш Elasticsearch будет рабо­тать в виде одной ноды, а не кластера.

При необ­хо­ди­мо­сти изме­не­ний пара­мет­ров JVM – редак­ти­ру­ем /etc/elasticsearch/jvm.options.

Как мини­мум, там мож­но ука­зать мини­мум и мак­си­мум памя­ти через опции -Xms и -Xmx, хотя он их зада­ёт авто­ма­ти­че­ски в зави­си­мо­сти от доступ­ной памя­ти на сервера.

Пока мож­но оста­вить по-умолчанию.

Настрой­ка аутен­ти­фи­ка­ции и поль­зо­ва­те­лей опи­са­на в Set up minimal security for Elasticsearch, мы сей­час этим зани­мать­ся не будем – хва­тит огра­ни­че­ний по IP, кото­рые мы зада­ли в SecurityGroup наше­го EC2.

Запус­ка­ем сер­вис, добав­ля­ем в автозагрузку:

root@ip-172-31-43-4:/home/ubuntu# systemctl start elasticsearch
root@ip-172-31-43-4:/home/ubuntu# systemctl enable elasticsearch

Про­ве­ря­ем доступ к Elasticseacrh API:

Логи доступ­ны в ката­ло­ге /var/log/elasticsearch, а дан­ные хра­нят­ся в /var/lib/elasticsearch.

Elasticsearch Index

Крат­ко рас­смот­рим что такое индек­сы в Elastiseacrh, и как с ними рабо­тать через API.

По сути, индекс в Ела­сти­ке мож­но пред­став­лять себе как базу дан­ных в СУБД типа MySQL, кото­рая хра­нит доку­мен­ты, а доку­мент в свою оче­редь пред­став­ля­ет собой JSON-объ­ект опре­де­лён­но­го типа.

Индек­сы состо­ят из shards – сег­мен­тов, кото­рые могут рас­по­ла­гать­ся на одной и более рабо­чих нод Ела­сти­ка, но шар­ди­ро­ва­ние и кла­сте­ри­за­цию рас­смот­рим в дру­гой раз.

Просмотр индексов

Для про­смот­ра индек­сов вызы­ва­ем GET _cat/indices?v:

root@ip-172-31-43-4:/home/ubuntu# curl localhost:9200/_cat/indices?v
health status index            uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   .geoip_databases 2E8sIYX0RaiqyZWzPHYHfQ   1   0         42            0     40.4mb         40.4mb

 

Сей­час у нас тут толь­ко один слу­жеб­ный (точ­ка в нача­ле име­ни) индекс .geoip_databases, содер­жа­щий спи­сок бло­ков IP и свя­зан­ных с ними реги­о­нов – это дефолт­ный индекс, с кото­рым идёт Elastiseacrh. Его потом мож­но будет при­ме­нить напри­мер для добав­ле­ния реги­о­на юзе­ра в NGINX Access Logs.

Создание индекса

Доба­вим новый пустой индекс:

про­ве­рим

example_index – наш новый индекс появился.

И сам индекс:

Создание документа в индексе

Доба­вим документ:

 

И про­ве­рим всё содер­жи­мое индекса:

И исполь­зуя его ID – полу­чим содержимое:

Поиск в индексе

Или поищем его в этом индек­се по полю name и части содер­жи­мо­го – сло­ву “doc“:

Удаление индекса

Пере­да­ём DELETE и имя имя индек­са, кото­рый хотим удалить:

Окей – тут потро­га­ли, уви­де­ли, что есть внут­ри – идём даль­ше, пере­хо­дим к уста­нов­ке Logstash.

Установка Logstash

Уста­нав­ли­ва­ем Logstash – он есть в репо­зи­то­рии, кото­рый добав­ля­ли в начале:

root@ip-172-31-43-4:/home/ubuntu# apt -y install logstash

 

Запус­ка­ем:

root@ip-172-31-43-4:/home/ubuntu# systemctl start logstash
root@ip-172-31-43-4:/home/ubuntu# systemctl enable logstash
Created symlink /etc/systemd/system/multi-user.target.wants/logstash.service → /etc/systemd/system/logstash.service.

 

Общий файл настро­ек Logstash – /etc/logstash/logstash.yml, а для наших кон­фи­гов – исполь­у­зем /etc/logstash/conf.d/.

Свой output (stdout) он пишет в файл /var/logs/syslog.

Работа с Logstash pipelines

См. How Logstash Works.

Pipelines в Logstash опи­сы­ва­ют цепоч­ку Input > Filter > Output.

В Input может быть, к при­ме­ру, filestdin или beats.

Logstash Input и Output

Что бы уви­деть, как вооб­ще рабо­та­ет Logstash – сна­ча­ла созда­дим пай­плайн, кото­рый через stdin при­ни­ма­ет дан­ные, и выво­дит их через stdout.

Самый про­стой спо­соб про­те­сти­ро­вать это – запу­стить logstash, и ука­зать ему пара­мет­ры пря­мо в команд­ной стро­ке через опцию -e:

Logstash Filter: grok

Очень базо­вый при­мер рабо­ты с филь­тра­ми на при­ме­ре филь­тра grok.

Созда­ём файл logstash-test.conf:

Тут в filter мы исполь­зу­ем grok, кото­рый ищет сов­па­де­ние в тек­сте сооб­ще­ния. Для поис­ка grok исполь­зу­ет пат­тер­ны с регу­ляр­ны­ми выра­же­ни­я­ми, в нашем при­ме­ре пат­терн GREEDYDATA  соот­вет­ству­ет регу­ляр­ке .*, т.е. любые символы.

Запу­стим ещё раз, но теперь вме­сто -e исполь­зу­ем -f и пере­да­ём имя фай­ла настроек:

Теперь попро­бу­ем выпол­нить транс­фор­ма­цию доку­мен­та – доба­вим тег “Example”, и два поля: в одном будет про­сто текст “Example value“, во вто­ром – под­ста­вим вре­мя, когда полу­че­но сообщение:

Запус­ка­ем:

Logstash Input: file

Тут тоже всё вро­де ясно-понят­но – попро­бу­ем что-то поин­те­рес­нее, напри­мер – читать дан­ные из фай­ла /var/log/syslog.

Для нача­ла посмот­рим содер­жи­мое файла:

root@ip-172-31-43-4:/home/ubuntu# tail -1 /var/log/syslog
Jan 22 11:41:49 ip-172-31-43-4 logstash[8099]: [2022-01-22T11:41:49,476][INFO ][logstash.agent           ] Successfully started Logstash API endpoint {:port=>9601, :ssl_enabled=>false}

 

Что у нас тут есть:

  1. дата и вре­мя – Jan 22 11:41:49
  2. хост – ip-172-31-43-4
  3. имя про­грам­мы – logstash
  4. PID про­цес­са – 8099
  5. и само сообщение

В филь­тре исполь­зу­ем тот же grok, кото­ро­му в усло­вии match зада­дим пат­тер­ны – вме­сто GREEDYDATA, кото­рый зано­сит всё в поле my_message исполь­зу­ем SYSLOGTIMESTAMP, кото­рый сра­бо­та­ет на зна­че­ние Jan 21 14:06:23, и это зна­че­ние будет добав­ле­но в поле syslog_timestamp, затем SYSLOGHOSTDATAPOSINT и остав­шу­ю­ся часть сооб­ще­ния полу­ча­ем с помо­щью GREEDYDATA, кото­рую сохар­ним в поле syslog_message.

Кро­ме того, доба­вим два поля – received_at и received_from, в кото­рые вне­сём дан­ные полу­чен­ные в macth, а затем для при­ме­ра воз­мож­но­стей уда­лим ори­ги­наль­ное поле message, так как само сооб­ще­ние мы уже сохра­ни­ли в поле syslog_message:

Запус­ка­ем:

Окей, всё это отлич­но – а как на счёт Elastisearch?

Logstash output: elasticsearch

Теперь попро­бу­ем запи­сать эти дан­ные в Elastisearch:

Запус­ка­ем, и про­ве­ря­ем индек­сы Elastic – Logstash дол­жен создать свой индекс:

logstash-2022.01.22-000001 – “Ага, вот эти ребя­та!” (с)

Поищем – что там есть, напри­мер – долж­ны быть запи­си из фай­ла /var/log/syslog о про­цес­се logstash:

Yay! It works!

Идём даль­ше.

Установка Filebeat

Уста­нав­ли­ва­ем пакет:

root@ip-172-31-43-4:/home/ubuntu# apt -y install filebeat

Файл настро­ек – /etc/filebeat/filebeat.yml.

По-умол­ча­нию Filebeat будет слать дан­ные напря­мую в Elastisearch:

Обнов­ля­ем его кон­фиг – вклю­чим сбор логов из /var/log/syslog, и вме­сто запи­си в Elastic отпра­вим дан­ные в Logstash.

Добав­ля­ем наблю­де­ние за лога­ми, не забы­ва­ем ука­зать enabled: true:

Ком­мен­ти­ру­ем блок output.elasticsearch, рас­ко­мен­ти­ру­ем output.logstash:


Для Logstash созда­дим файл /etc/logstash/conf.d/beats.conf:

В пара­мет­рах elasticsearch ука­зы­ва­ем его хост и имя для индек­са, в кото­рый будем писать данные.

Запус­ка­ем Logstash:

root@ip-172-31-43-4:/home/ubuntu# systemctl start logstash

 

Про­ве­ря­ем /var/log/syslog:

Jan 22 12:10:34 ip-172-31-43-4 logstash[12406]: [2022-01-22T12:10:34,054][INFO ][org.logstash.beats.Server][main][e3ccc6e9edc43cf62f935b6b4b9cf44b76d887bb01e30240cbc15ab5103fe4b6] Starting server on port: 5044

 

Запус­ка­ем Filebeat:

root@ip-172-31-43-4:/home/ubuntu# systemctl start filebeat

 

Про­ве­ря­ем индек­сы Еластики:

filebeat-7.16.3-2022.01.22 – есть новый индекс.

Установка Kibana

Уста­нав­ли­ва­ем:

root@ip-172-31-43-4:/home/ubuntu# apt -y install kibana

 

Редак­ти­ру­ем файл /etc/kibana/kibana.yml, зада­ём server.host==0.0.0.0, что бы Kibana была доступ­на из мира.

Запус­ка­ем:

root@ip-172-31-43-4:/home/ubuntu# systemctl start kibana
root@ip-172-31-43-4:/home/ubuntu# systemctl enable kibana

 

Про­ве­ря­ем в браузере:

Ста­тус – /status:

Кди­ка­ем Explore on my own, пере­хо­дим в Management > Stack management:

Пере­хо­дим в Index patterns, созда­ём новый индекс для Kibana исполь­зуя мас­ку filebeat-* – спра­ва видим, что Киба­на уже нашла все индек­сы в Elastiseacrh:

И видим все поля, про­ин­дек­си­ро­ван­ные Кибаной:

Пере­хо­дим в Observability – Logs:

И видим наш /var/log/syslog:

Logstash, Filebeat и NGINX: пример настройки

Ну и давай­те сде­ла­ем что-то при­бли­жён­ное к реальности:

  1. уста­но­вим NGINX
  2. настро­им Filebeat на сбор его логов
  3. настро­им Logstash на их при­ём и отправ­ку в Elastic
  4. и посмот­рим, что мы уви­дим в Kibana

Уста­нав­ли­ва­ем NGINX:

root@ip-172-31-43-4:/home/ubuntu# apt -y install nginx

 

Его фай­лы логов:

root@ip-172-31-43-4:/home/ubuntu# ll /var/log/nginx/
access.log  error.log

 

Про­ве­ря­ем его работу:

root@ip-172-31-43-4:/home/ubuntu# curl localhost:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>

 

И access.log:

root@ip-172-31-43-4:/home/ubuntu# tail -1 /var/log/nginx/access.log
127.0.0.1 - - [26/Jan/2022:11:33:21 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0"

 

Okay.

Настройка Filebeat Inputs

Доку­мен­та­ция – Configure inputs и Configure general settings.

Редак­ти­ру­ем блок filebeat.inputs, к сбо­ру дан­ных из /var/log/syslog доба­вим ещё два инпу­та – для access и error логов NGINX:

Тут мы исполь­зу­ем тип инпу­та log, и добав­ля­ем поле type: nginx_access/nginx_error.

Настройка Logstash

Уда­лим ста­рый кон­фиг и пишем новый, и обнов­ля­ем /etc/logstash/conf.d/beats.conf:

В нём описываем:

  1. input на порт 5044 для filebeat
  2. два filter:
    1. пер­вый про­ве­ря­ет поле type, если оно == syslog, то пар­сит дан­ные, а раз­де­ля­ет их по полям лога /var/log/syslog
    2. вто­рой про­ве­ря­ет поле type, если оно == nginx_access, то пар­сит содер­жи­мое, и раз­но­сит дан­ные по полям access-лога NGINX
  3. outout исполь­зу­ет два усло­вия if, и в зави­си­мо­сти от типа дан­ных отправ­ля­ет доку­мен­ты в индекс logstash-%{+YYYY.MM.dd} или nginx-%{+YYYY.MM.dd}

Пере­за­пус­ка­ем Logstash и Filebeat:

root@ip-172-31-43-4:/home/ubuntu# systemctl restart logstash
root@ip-172-31-43-4:/home/ubuntu# systemctl restart filebeat

 

Запу­стим curl на посто­ян­ные запро­сы к NGINX, что бы сге­не­рить access-логи:

ubuntu@ip-172-31-43-4:~$ watch -n 1 curl -I localhost

 

Про­ве­ря­ем индексы:

Ага, индекс появился.

Идём в Kibana, к уже име­ю­ще­му­ся nginx-* добав­ля­ем logstash-*:

Пере­хо­дим в Analitycs > Discover, выби­ра­ем индекс, смот­рим данные:

И ана­ло­гич­но – логи NGINX: