Последний раз ELK трогал (oh, my!) 7 лет тому, см. ELK: установка Elasticsearch+Logstash+Kibana на CentOS. Сейчас активно используем Logz.io, но расходы всё растут, и понемногу начинаем смотреть в сторону self-hosted ELK для запуска в Kubernetes, а потому надо поднять такой себе Proof of concept, дабы вспомнить с чем его едят и как настраивают.
Собственно, в этом посте посмотрим из чего состоит Elastic Stack, как его установить на Ubuntu 20.04, настроить сбор логов с Filebeat, их обработку с Logstash, и что у них вообще под капотом и как всё это работает.
Основная цель — как раз больше копнуть в настройку и взаимодействие компонентов, а не выполнить тонкую «production-ready» настройку, поэтому не будем углубляться например в авторизацию Kibana, но повспоминаем что такое grok, индексы Elasticsearch и вот это вот всё.
Still, как обычно — будет много ссылок на документацию, в которой можно найти ответы на остальные вопросы.
И помните: «10 часов дебаггинга и попыток сделать и посмотреть, что получится, сэкономят вам 10 минут чтения документации«.
Содержание
Elastic Stack: обзор компонентов
Elastic Stack, он же ELK (Elasticsearch + Logstash + Kibana) наверно наиболее широкоизвеcтная и самая используемая система для сбора и анализа логов, метрик и других данных о состоянии систем — серверов, кластеров, клаудов.
Состоит из трёх основных компонентов:
- Elasticsearch: база данных с возможностями быстрого поиска используя Elasticsearch Index
- Logstash: система сбора данных из разных источников, их трансформации и передачи логов в Elasticsearch
- Kibana: веб-интерфейс для отображения данных из базы Elasticsearch
Кроме того, для ELK (по привычке уже буду его называть так) существует набор т.н. Beats — утилит для сбора данных. Среди них, например, Filebeat — для сбора данных из файлов (логов), или Metricbeat для сбора данных о системе — CPU, RAM и т.д. См. также Logz.io: сбор логов из Kubernetes – fluentd vs filebeat.
Схема работы стека следующая:
- сервер генерирует данные, например логи
- данные собираются локальным Beat-приложением, для логов это будет Filebeat (хотя это необязательный компонент, и логи можно собирать самим Logstash), и отправляет их в Logstash или напрямую в Elastisearch
- Logstash собирает данные из различных источников (получая их от Beats или собирая напрямую), при необходимости выполняет трансформацию (добавление-удаление полей, тегов и т.д.), и отправляет их в Elasticsearch
- Elasticsearch занимается хранением данных с возможностью быстрого поиска
- 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, получаем адрес:
Подключаем его к нашему инстансу:
На рабочей машине меняем права доступа к ключу — оставляем доступ только своему пользователю:
[simterm]
$ chmod 600 ~/Temp/elk-test-eu-west-2.pem
[/simterm]
Проверяем подключение:
[simterm]
$ ssh -i ~/Temp/elk-test-eu-west-2.pem [email protected] ... ubuntu@ip-172-31-43-4:~$
[/simterm]
Обновляем систему:
[simterm]
ubuntu@ip-172-31-43-4:~$ sudo -s root@ip-172-31-43-4:/home/ubuntu# apt update && apt -y upgrade
[/simterm]
Ребутаемся, что бы загрузить новое ядро после апгрейда системы:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# reboot
[/simterm]
Переходим к установке компонентов ELK.
Установка Elastic Stack/ELK
Добавляем репозиторий Elasticsearch:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add - OK root@ip-172-31-43-4:/home/ubuntu# apt -y install apt-transport-https root@ip-172-31-43-4:/home/ubuntu# sh -c 'echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" > /etc/apt/sources.list.d/elastic-7.x.list'
[/simterm]
Установка Elasticsearch
Устанавливаем пакет elasticsearch:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# apt update && apt -y install elasticsearch
[/simterm]
Файл настроек Еластики — /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.
Запускаем сервис, добавляем в автозагрузку:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# systemctl start elasticsearch root@ip-172-31-43-4:/home/ubuntu# systemctl enable elasticsearch
[/simterm]
Проверяем доступ к Elasticseacrh API:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# curl -X GET "localhost:9200"
{
"name" : "ip-172-31-43-4",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "8kVCdVRySfKutRjPkkVr5w",
"version" : {
"number" : "7.16.3",
"build_flavor" : "default",
"build_type" : "deb",
"build_hash" : "4e6e4eab2297e949ec994e688dad46290d018022",
"build_date" : "2022-01-06T23:43:02.825887787Z",
"build_snapshot" : false,
"lucene_version" : "8.10.1",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
[/simterm]
Логи доступны в каталоге /var/log/elasticsearch, а данные хранятся в /var/lib/elasticsearch.
Elasticsearch Index
Кратко рассмотрим что такое индексы в Elastiseacrh, и как с ними работать через API.
По сути, индекс в Еластике можно представлять себе как базу данных в СУБД типа MySQL, которая хранит документы, а документ в свою очередь представляет собой JSON-объект определённого типа.
Индексы состоят из shards — сегментов, которые могут располагаться на одной и более рабочих нод Еластика, но шардирование и кластеризацию рассмотрим в другой раз.
Просмотр индексов
Для просмотра индексов вызываем GET _cat/indices?v:
[simterm]
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
[/simterm]
Сейчас у нас тут только один служебный (точка в начале имени) индекс .geoip_databases, содержащий список блоков IP и связанных с ними регионов — это дефолтный индекс, с которым идёт Elastiseacrh. Его потом можно будет применить например для добавления региона юзера в NGINX Access Logs.
Создание индекса
Добавим новый пустой индекс:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# curl -X PUT localhost:9200/example_index?pretty
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "example_index"
}
[/simterm]
Проверим:
[simterm]
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 yellow open example_index akWscE7MQKy_fceS9ZMGGA 1 1 0 0 226b 226b
[/simterm]
example_index — наш новый индекс появился.
И сам индекс:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# curl localhost:9200/example_index?pretty
{
"example_index" : {
"aliases" : { },
"mappings" : { },
"settings" : {
"index" : {
"routing" : {
"allocation" : {
"include" : {
"_tier_preference" : "data_content"
}
}
},
"number_of_shards" : "1",
"provided_name" : "example_index",
"creation_date" : "1642848658111",
"number_of_replicas" : "1",
"uuid" : "akWscE7MQKy_fceS9ZMGGA",
"version" : {
"created" : "7160399"
}
}
}
}
}
[/simterm]
Создание документа в индексе
Добавим документ:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# curl -H 'Content-Type: application/json' -X POST localhost:9200/example_index/document1?pretty -d '{ "name": "Just an example doc" }'
{
"_index" : "example_index",
"_type" : "document1",
"_id" : "rhF0gX4Bbs_W8ADHlfFY",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 2,
"_primary_term" : 1
}
[/simterm]
И проверим всё содержимое индекса:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# curl localhost:9200/example_index/_search?pretty
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "example_index",
"_type" : "document1",
"_id" : "qxFzgX4Bbs_W8ADHTfGi",
"_score" : 1.0,
"_source" : {
"name" : "Just an example doc"
}
},
{
"_index" : "example_index",
"_type" : "document1",
"_id" : "rhF0gX4Bbs_W8ADHlfFY",
"_score" : 1.0,
"_source" : {
"name" : "Just an example doc"
}
}
]
}
}
[/simterm]
И используя его ID — получим содержимое:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# curl -X GET 'localhost:9200/example_index/document1/qxFzgX4Bbs_W8ADHTfGi?pretty'
{
"_index" : "example_index",
"_type" : "document1",
"_id" : "qxFzgX4Bbs_W8ADHTfGi",
"_version" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"found" : true,
"_source" : {
"name" : "Just an example doc"
}
}
[/simterm]
Поиск в индексе
Или поищем его в этом индексе по полю name и части содержимого — слову «doc«:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# curl -H 'Content-Type: application/json' -X GET 'localhost:9200/example_index/_search?pretty' -d '{ "query": { "match": { "name": "doc" } } }'
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 0.18232156,
"hits" : [
{
"_index" : "example_index",
"_type" : "document1",
"_id" : "qxFzgX4Bbs_W8ADHTfGi",
"_score" : 0.18232156,
"_source" : {
"name" : "Just an example doc"
}
},
{
"_index" : "example_index",
"_type" : "document1",
"_id" : "rhF0gX4Bbs_W8ADHlfFY",
"_score" : 0.18232156,
"_source" : {
"name" : "Just an example doc"
}
}
]
}
}
[/simterm]
Удаление индекса
Передаём DELETE и имя имя индекса, который хотим удалить:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# curl -X DELETE localhost:9200/example_index
{"acknowledged":true}
[/simterm]
Окей — тут потрогали, увидели, что есть внутри — идём дальше, переходим к установке Logstash.
Установка Logstash
Устанавливаем Logstash — он есть в репозитории, который добавляли в начале:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# apt -y install logstash
[/simterm]
Запускаем:
[simterm]
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.
[/simterm]
Общий файл настроек 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 может быть, к примеру, file, stdin или beats.
Logstash Input и Output
Что бы увидеть, как вообще работает Logstash — сначала создадим пайплайн, который через stdin принимает данные, и выводит их через stdout.
Самый простой способ протестировать это — запустить logstash, и указать ему параметры прямо в командной строке через опцию -e:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# /usr/share/logstash/bin/logstash -e 'input { stdin { } } output { stdout {} }'
...
The stdin plugin is now waiting for input:
Hello, World!
{
"message" => "Hello, World!",
"@version" => "1",
"@timestamp" => 2022-01-22T11:30:33.971Z,
"host" => "ip-172-31-43-4"
}
[/simterm]
Logstash Filter: grok
Очень базовый пример работы с фильтрами на примере фильтра grok.
Создаём файл logstash-test.conf:
input { stdin { } }
filter {
grok {
match => { "message" => "%{GREEDYDATA}" }
}
}
output {
stdout { }
}
Тут в filter мы используем grok, который ищет совпадение в тексте сообщения. Для поиска grok использует паттерны с регулярными выражениями, в нашем примере паттерн GREEDYDATA соответствует регулярке .*, т.е. любые символы.
Запустим ещё раз, но теперь вместо -e используем -f и передаём имя файла настроек:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# /usr/share/logstash/bin/logstash -f logstash-test.conf
...
The stdin plugin is now waiting for input:
Hello, Grok!
{
"message" => "Hello, Grok!",
"@timestamp" => 2022-01-22T11:33:49.797Z,
"@version" => "1",
"host" => "ip-172-31-43-4"
}
[/simterm]
Теперь попробуем выполнить трансформацию документа — добавим тег “Example”, и два поля: в одном будет просто текст «Example value«, во втором – подставим время, когда получено сообщение:
input { stdin { } }
filter {
grok {
match => { "message" => "%{GREEDYDATA:my_message}" }
add_tag => ["Example"]
add_field => [ "example_field", "Example value" ]
add_field => [ "received_at", "%{@timestamp}" ]
}
}
output {
stdout { }
}
Запускаем:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# /usr/share/logstash/bin/logstash -f logstash-test.conf
...
Hello again, Grok!
{
"message" => "Hello again, Grok!",
"host" => "ip-172-31-43-4",
"tags" => [
[0] "Example"
],
"received_at" => "2022-01-22T11:36:46.893Z",
"my_message" => "Hello again, Grok!",
"@timestamp" => 2022-01-22T11:36:46.893Z,
"example_field" => "Example value",
"@version" => "1"
}
[/simterm]
Logstash Input: file
Тут тоже всё вроде ясно-понятно — попробуем что-то поинтереснее, например — читать данные из файла /var/log/syslog.
Для начала посмотрим содержимое файла:
[simterm]
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}
[/simterm]
Что у нас тут есть:
- дата и время —
Jan 22 11:41:49 - хост —
ip-172-31-43-4 - имя программы —
logstash - PID процесса —
8099 - и само сообщение
В фильтре используем тот же grok, которому в условии match зададим паттерны — вместо GREEDYDATA, который заносит всё в поле my_message используем SYSLOGTIMESTAMP, который сработает на значение Jan 21 14:06:23, и это значение будет добавлено в поле syslog_timestamp, затем SYSLOGHOST, DATA, POSINT и оставшуюся часть сообщения получаем с помощью GREEDYDATA, которую сохарним в поле syslog_message.
Кроме того, добавим два поля — received_at и received_from, в которые внесём данные полученные в macth, а затем для примера возможностей удалим оригинальное поле message, так как само сообщение мы уже сохранили в поле syslog_message:
input {
file {
path => "/var/log/syslog"
}
}
filter {
grok {
match => { "message" => "%{SYSLOGTIMESTAMP:syslog_timestamp} %{SYSLOGHOST:syslog_hostname} %{DATA:syslog_program}(?:\[%{POSINT:syslog_pid}\])?: %{GREEDYDATA:syslog_message}" }
add_field => [ "received_at", "%{@timestamp}" ]
add_field => [ "received_from", "%{host}" ]
remove_field => "message"
}
}
output {
stdout { }
}
Запускаем:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# /usr/share/logstash/bin/logstash -f logstash-test.conf
...
{
"host" => "ip-172-31-43-4",
"path" => "/var/log/syslog",
"received_at" => "2022-01-22T11:48:27.582Z",
"syslog_message" => "#011at usr.share.logstash.lib.bootstrap.environment.<main>(/usr/share/logstash/lib/bootstrap/environment.rb:94) ~[?:?]",
"syslog_timestamp" => "Jan 22 11:48:27",
"syslog_program" => "logstash",
"syslog_hostname" => "ip-172-31-43-4",
"@timestamp" => 2022-01-22T11:48:27.582Z,
"syslog_pid" => "9655",
"@version" => "1",
"received_from" => "ip-172-31-43-4"
}
...
[/simterm]
Окей, всё это отлично – а как на счёт Elastisearch?
Logstash output: elasticsearch
Теперь попробуем записать эти данные в Elastisearch:
input {
file {
path => "/var/log/syslog"
}
}
filter {
grok {
match => { "message" => "%{SYSLOGTIMESTAMP:syslog_timestamp} %{SYSLOGHOST:syslog_hostname} %{DATA:syslog_program}(?:\[%{POSINT:syslog_pid}\])?: %{GREEDYDATA:syslog_message}" }
add_field => [ "received_at", "%{@timestamp}" ]
add_field => [ "received_from", "%{host}" ]
remove_field => "message"
}
}
output {
elasticsearch {
hosts => ["localhost:9200"]
}
stdout { }
}
Запускаем, и проверяем индексы Elastic — Logstash должен создать свой индекс:
[simterm]
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 yellow open logstash-2022.01.22-000001 ekf_ntRxRiitIRcmYI2TOg 1 1 0 0 226b 226b yellow open example_index akWscE7MQKy_fceS9ZMGGA 1 1 2 1 8.1kb 8.1kb
[/simterm]
logstash-2022.01.22-000001 — «Ага, вот эти ребята!» (с)
Поищем — что там есть, например — должны быть записи из файла /var/log/syslog о процессе logstash:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# curl -H 'Content-Type: application/json' localhost:9200/logstash-2022.01.22-000001/_search?pretty -d '{ "query": { "match": { "syslog_program": "logstash" } } }'
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 36,
"relation" : "eq"
},
"max_score" : 0.33451337,
"hits" : [
{
"_index" : "logstash-2022.01.22-000001",
"_type" : "_doc",
"_id" : "9BGogX4Bbs_W8ADHCvJl",
"_score" : 0.33451337,
"_source" : {
"syslog_program" : "logstash",
"received_from" : "ip-172-31-43-4",
"syslog_timestamp" : "Jan 22 11:57:18",
"syslog_hostname" : "ip-172-31-43-4",
"syslog_message" : "[2022-01-22T11:57:18,474][INFO ][logstash.runner ] Starting Logstash {\"logstash.version\"=>\"7.16.3\", \"jruby.version\"=>\"jruby 9.2.20.1 (2.5.8) 2021-11-30 2a2962fbd1 OpenJDK 64-Bit Server VM 11.0.13+8 on 11.0.13+8 +indy +jit [linux-x86_64]\"}",
"host" : "ip-172-31-43-4",
"@timestamp" : "2022-01-22T11:59:40.444Z",
"path" : "/var/log/syslog",
"@version" : "1",
"syslog_pid" : "11873",
"received_at" : "2022-01-22T11:59:40.444Z"
}
},
...
[/simterm]
Yay! It works!
Идём дальше.
Установка Filebeat
Устанавливаем пакет:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# apt -y install filebeat
[/simterm]
Файл настроек – /etc/filebeat/filebeat.yml.
По-умолчанию Filebeat будет слать данные напрямую в Elastisearch:
... # ================================== Outputs =================================== # Configure what output to use when sending the data collected by the beat. # ---------------------------- Elasticsearch Output ---------------------------- output.elasticsearch: # Array of hosts to connect to. hosts: ["localhost:9200"] # Protocol - either `http` (default) or `https`. #protocol: "https" # Authentication credentials - either API key or username/password. #api_key: "id:api_key" #username: "elastic" #password: "changeme" ...
Обновляем его конфиг — включим сбор логов из /var/log/syslog, и вместо записи в Elastic отправим данные в Logstash.
Добавляем наблюдение за логами, не забываем указать enabled: true:
...
filebeat.inputs:
...
- type: filestream
...
enabled: true
...
paths:
- /var/log/syslog
...
Комментируем блок output.elasticsearch, раскоментируем output.logstash:
... # ---------------------------- Elasticsearch Output ---------------------------- #output.elasticsearch: # Array of hosts to connect to. # hosts: ["localhost:9200"] ... # ------------------------------ Logstash Output ------------------------------- output.logstash: ... hosts: ["localhost:5044"] ...
Для Logstash создадим файл /etc/logstash/conf.d/beats.conf:
input {
beats {
port => 5044
}
}
output {
elasticsearch {
hosts => ["http://localhost:9200"]
index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
}
}
В параметрах elasticsearch указываем его хост и имя для индекса, в который будем писать данные.
Запускаем Logstash:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# systemctl start logstash
[/simterm]
Проверяем /var/log/syslog:
[simterm]
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
[/simterm]
Запускаем Filebeat:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# systemctl start filebeat
[/simterm]
Проверяем индексы Еластики:
[simterm]
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 yellow open filebeat-7.16.3-2022.01.22 fTUTzKmKTXisHUlfNbobPw 1 1 7084 0 14.3mb 14.3mb yellow open logstash-2022.01.22-000001 ekf_ntRxRiitIRcmYI2TOg 1 1 50 0 62.8kb 62.8kb yellow open example_index akWscE7MQKy_fceS9ZMGGA 1 1 2 1 8.1kb 8.1kb
[/simterm]
filebeat-7.16.3-2022.01.22 — есть новый индекс.
Установка Kibana
Устанавливаем:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# apt -y install kibana
[/simterm]
Редактируем файл /etc/kibana/kibana.yml, задаём server.host==0.0.0.0, что бы Kibana была доступна из мира.
Запускаем:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# systemctl start kibana root@ip-172-31-43-4:/home/ubuntu# systemctl enable kibana
[/simterm]
Проверяем в браузере:
Статус — /status:
Кдикаем Explore on my own, переходим в Management > Stack management:
Переходим в Index patterns, создаём новый индекс для Kibana используя маску filebeat-* — справа видим, что Кибана уже нашла все индексы в Elastiseacrh:
И видим все поля, проиндексированные Кибаной:
Переходим в Observability — Logs:
И видим наш /var/log/syslog:
Logstash, Filebeat и NGINX: пример настройки
Ну и давайте сделаем что-то приближённое к реальности:
- установим NGINX
- настроим Filebeat на сбор его логов
- настроим Logstash на их приём и отправку в Elastic
- и посмотрим, что мы увидим в Kibana
Устанавливаем NGINX:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# apt -y install nginx
[/simterm]
Его файлы логов:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# ll /var/log/nginx/ access.log error.log
[/simterm]
Проверяем его работу:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# curl localhost:80 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> ...
[/simterm]
И access.log:
[simterm]
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"
[/simterm]
Okay.
Настройка Filebeat Inputs
Документация — Configure inputs и Configure general settings.
Редактируем блок filebeat.inputs, к сбору данных из /var/log/syslog добавим ещё два инпута — для access и error логов NGINX:
...
# ============================== Filebeat inputs ===============================
filebeat.inputs:
- type: filestream
enabled: true
paths:
- /var/log/syslog
fields:
type: syslog
fields_under_root: true
scan_frequency: 5s
- type: log
enabled: true
paths:
- /var/log/nginx/access.log
fields:
type: nginx_access
fields_under_root: true
scan_frequency: 5s
- type: log
enabled: true
paths:
- /var/log/nginx/error.log
fields:
type: nginx_error
fields_under_root: true
scan_frequency: 5s
...
Тут мы используем тип инпута log, и добавляем поле type: nginx_access/nginx_error.
Настройка Logstash
Удалим старый конфиг и пишем новый, и обновляем /etc/logstash/conf.d/beats.conf:
input {
beats {
port => 5044
}
}
filter {
if [type] == "syslog" {
grok {
match => { "message" => "%{SYSLOGTIMESTAMP:syslog_timestamp} %{SYSLOGHOST:syslog_hostname} %{DATA:syslog_program}(?:\[%{POSINT:syslog_pid}\])?: %{GREEDYDATA:syslog_message}" }
add_field => [ "received_at", "%{@timestamp}" ]
add_field => [ "received_from", "%{host}" ]
remove_field => "message"
}
}
}
filter {
if [type] == "nginx_access" {
grok {
match => { "message" => "%{IPORHOST:remote_ip} - %{DATA:user} \[%{HTTPDATE:access_time}\] \"%{WORD:http_method} %{DATA:url} HTTP/%{NUMBER:http_version}\" %{NUMBER:response_code} %{NUMBER:body_sent_bytes} \"%{DATA:referrer}\" \"%{DATA:agent}\"" }
}
}
date {
match => [ "timestamp" , "dd/MMM/YYYY:HH:mm:ss Z" ]
}
geoip {
source => "remote_ip"
target => "geoip"
add_tag => [ "nginx-geoip" ]
}
}
output {
if [type] == "syslog" {
elasticsearch {
hosts => ["localhost:9200"]
index => "logstash-%{+YYYY.MM.dd}"
}
}
if [type] == "nginx_access" {
elasticsearch {
hosts => ["localhost:9200"]
index => "nginx-%{+YYYY.MM.dd}"
}
}
stdout { }
}
В нём описываем:
inputна порт 5044 для filebeat- два
filter:- первый проверяет поле
type, если оно == syslog, то парсит данные, а разделяет их по полям лога/var/log/syslog - второй проверяет поле
type, если оно == nginx_access, то парсит содержимое, и разносит данные по полям access-лога NGINX
- первый проверяет поле
outoutиспользует два условияif, и в зависимости от типа данных отправляет документы в индексlogstash-%{+YYYY.MM.dd}илиnginx-%{+YYYY.MM.dd}
Перезапускаем Logstash и Filebeat:
[simterm]
root@ip-172-31-43-4:/home/ubuntu# systemctl restart logstash root@ip-172-31-43-4:/home/ubuntu# systemctl restart filebeat
[/simterm]
Запустим curl на постоянные запросы к NGINX, что бы сгенерить access-логи:
[simterm]
ubuntu@ip-172-31-43-4:~$ watch -n 1 curl -I localhost
[/simterm]
Проверяем индексы:
[simterm]
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 ... yellow open logstash-2022.01.28 bYLp_kI3TwW3sPfh7XpcuA 1 1 213732 0 159mb 159mb ... yellow open nginx-2022.01.28 0CwH4hBhT2C1sMcPzCQ9Pg 1 1 1 0 32.4kb 32.4kb
[/simterm]
Ага, индекс появился.
Идём в Kibana, к уже имеющемуся nginx-* добавляем logstash-*:
Переходим в Analitycs > Discover, выбираем индекс, смотрим данные:
И аналогично — логи NGINX:
Готово.
Ссылки по теме
Elastic Stack
- Elastic Stack on Kubernetes 1.15 using Helm v3
- ELK Stack Tutorial: Get Started with Elasticsearch, Logstash, Kibana, & Beats
- How to Install ELK Stack (Elasticsearch, Logstash, and Kibana) on Ubuntu 18.04 / 20.04
- UPDATED ELK STACK GUIDE FOR 2022
- How To Install Elasticsearch, Logstash, and Kibana (Elastic Stack) on Ubuntu 18.04
Elasticsearch
Logstash
- How Logstash Works
- Filter plugins
- A Practical Introduction to Logstash
- Getting started with logstash
- Tutorial: Logstash Grok Patterns with Examples
- A Beginner’s Guide to Logstash Grok
- Beats input plugin
























