ELK Stack — сбор и анализ логов

Продолжительность: 19 уроков · Уровень: средний

ELK — это связка Elasticsearch + Logstash + Kibana (плюс легковесные сборщики Beats). Стек собирает логи со всех серверов и приложений в одно место, индексирует их и позволяет искать по ним за секунды.

1. Компоненты стека

КомпонентРоль
Elasticsearchхранение, индексация и поиск
Logstashприём, преобразование и доставка данных
Kibanaвизуализация и интерфейс
Filebeatлёгкий сборщик логов с серверов (shipper)

Схема: Filebeat → Logstash → Elasticsearch → Kibana.

2. Установка Elasticsearch

wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elastic-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/elastic-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list
sudo apt update && sudo apt install elasticsearch
sudo systemctl enable --now elasticsearch

Проверка

curl http://localhost:9200

3. Индексы и документы

Данные хранятся в индексах (аналог коллекций/таблиц) и документах (JSON).

# создать документ
curl -X PUT "localhost:9200/products/_doc/1" -H 'Content-Type: application/json' -d '{
  "name": "Чашка",
  "price": 990
}'

# получить
curl "localhost:9200/products/_doc/1"
Elasticsearch — это JSON-документная БД с полнотекстовым поиском, а не просто хранилище логов.

4. Logstash — пайплайн

Пайплайн Logstash состоит из трёх зон: input, filter, output.

# /etc/logstash/conf.d/logs.conf
input {
  beats { port => 5044 }
}

filter {
  if [log][file][path] =~ "error" {
    mutate { add_field => { "severity" => "error" } }
  }
  grok {
    match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{GREEDYDATA:msg}" }
  }
  date {
    match => [ "timestamp", "ISO8601" ]
  }
}

output {
  elasticsearch {
    hosts => ["http://localhost:9200"]
    index => "app-logs-%{+YYYY.MM.dd}"
  }
}
sudo systemctl enable --now logstash
grok — распаковка неструктурного текста в поля по шаблонам. Это самый мощный инструмент Logstash.

5. Filebeat — сборщик файлов

sudo apt install filebeat

Конфигурация /etc/filebeat/filebeat.yml:

filebeat.inputs:
  - type: log
    enabled: true
    paths:
      - /var/log/nginx/*.log
      - /opt/app/logs/*.log

output.logstash:
  hosts: ["logstash:5044"]
sudo systemctl enable --now filebeat

6. Kibana — интерфейс

sudo apt install kibana
sudo systemctl enable --now kibana
# http://localhost:5601

Настройка: перейти в Stack Management → Data Views и создать view для индексов app-logs-* с временным полем по выбору.

7. Поиск в Kibana (Discover)

// простой поиск
error AND status:500

// по полю
level: WARN OR level: ERROR

// диапазон
response_time > 1000 AND service: payment

Полнотекстовый запрос Elasticsearch

GET app-logs-2026.09.04/_search
{
  "query": {
    "bool": {
      "must":   [ { "match": { "message": "exception" } } ],
      "filter": [ { "term":  { "level": "ERROR" } } ]
    }
  }
}

8. Визуализация

В Kibana создаются визуализации и комбинируются в дашборды:

9. Жизненный цикл индексов (ILM)

Политики ILM автоматически переносят старые индексы в более холодное хранение:

hot  => 7 дней, искать часто
warm => 30 дней
delete => после 90 дней

10. Мониторинг стека

curl "localhost:9200/_cluster/health"
curl "localhost:9200/_cat/indices?v"
Статус кластера red значит, что часть данных недоступна, yellow — реплики не разложены. Исправляй, а не игнорируй.

11. Альтернативы лёгкого стека

# вместо Logstash часто ставят Filebeat напрямую в Elasticsearch:
filebeat --> elasticsearch --> kibana  # проще, меньше ресурсов

Для «супер-лёгкого» сценария подойдёт стек Loki + Grafana из урока Grafana.

12. Grok: разбираем логи в поля

Grok-фильтр превращает неструктурированную строку лога в типизированные поля:

filter {
  grok {
    match => {
      "message" => "%{TIMESTAMP_ISO8601:ts} %{LOGLEVEL:level} %{DATA:msg}"
    }
  }
}
# вход: 2026-09-19T10:00:01 ERROR DB timeout
# поля: ts, level="ERROR", msg="DB timeout"
ПаттернЧто ловитПример
%{IP:client}IP-адрес192.168.1.10
%{NUMBER:code:int}число404
%{UUID:req_id}UUIDa1b2-…
В Kibana есть Grok Debugger — вставляй тестовую строку и смотри разбор мгновенно, без деплоя пайплайна.

13. Multiline и обогащение: mutate

Стек-трейсы и многострочные сообщения падают в одной записи только с фильтром multiline:

input {
  beats { port => 5044 }
}
filter {
  multiline {
    pattern => "^\\s"
    negate => false
    what => "previous"
  }
  mutate {
    add_field => { "app" => "billing" }
    rename    => { "message" => "raw" }
  }
  date {
    match => [ "timestamp", "ISO8601" ]
    target => "@timestamp"
  }
}
multiline держит буфер до переполнения: параметр max_lines и таймауты защищают от зависаний воркеров.

14. Alerting и оповещения

Elastic Alerting следит за правилами и шлёт уведомления при нарушении условий. Правило на частоту ошибок:

POST /_alerting/rules?filter_path=id
{
  "rule_type_id": ".es-query",
  "name": "Ошибка 5xx за 5 минут",
  "params": {
    "index": ["logs"],
    "timeField": "@timestamp",
    "esQuery": {
      "query": { "range": { "count5xx": { "gt": 10 } } }
    }
  },
  "actions": [
    { "group": "query matched",
      "id": "my-slack-connector",
      "params": { "message": "5xx превышен: {{count}} за 5 минут" } }
  ]
}
Начинай с малого: «быстрее чем» (throttling) и простая связка E-mail/Slack. Главное — не «шум», а срабатывание на реальную проблему.

15. Производительность и масштабирование

Стек растёт — и его нужно уметь расширять:

# размер шардов держи в диапазоне 10–50 ГБ
GET /_cat/shards?v
Расширение кластера Elasticsearch подробно описан в курсе Elasticsearch, а метрики приложений — в Prometheus.

16. Алиасы и reindex

Менять mapping и поля у готового индекса трудно — проще создать новый и перенести данные. Для «прозрачной» замены используют алиасы:

POST /_aliases
{
  "actions": [
    { "remove": { "index": "logs-2026.09", "alias": "logs-live" } },
    { "add": { "index": "logs-2026.09-v2", "alias": "logs-live" } }
  ]
}

Reindex копирует документы между индексами (можно с квалифицирующим запросом):

POST _reindex
{ "source": { "index": "logs-2026.09" },
  "dest": { "index": "logs-2026.09-v2" } }
Подход «новый индекс + алиас» — стандартный для миграций схемы в ELK.

17. Enrich: обогащение логов справочниками

Чтобы лог стал понятнее, добавь к нему контекст: имя сервиса из инстанса, регион, владельца. Enrich-processor делает это на входе.

PUT /_enrich/policy/services-policy
{ "match": { "indices": ["services"],
    "match_field": "instance",
    "enrich_fields": ["service", "team", "region"] } }
PUT /_ingest/pipeline/enrich-logs
{ "processors": [
    { "enrich": { "policy_name": "services-policy",
        "field": "instance", "target_field": "meta" } }
] }
Не добавляй в каждый лог по 20 полей: enrich только то, что реально используют дашборды и алерты.

18. X-Pack Security: защита стека

Стек без аутентификации отдаёт логи любому, кто дотянется до порта. Включение защиты в новом стеке — с самого начала:

# elasticsearch.yml
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
kibana.yml  -> elasticsearch.username: kibana_system
Включение защиты «на лету» на боевом кластере — болезненно. Включи до копирования данных, а потом обновляй только сертификаты.

19. Кейс: расследование инцидента по логам

Практический сценарий: пo/háчe нaчин в 14:02 выросла ошибка 500. Пошаговое разбирательство:

  1. Discover: фильтр по уровню status >= 500 за последние 2 часа;
  2. Cut by service.name и host — это API-шлюз или конкретный инстанс;
  3. трейн самого медленного запроса: traceId из лога → собери вкладки по времени;
  4. посмотри correlation с деплоем и метриками (если подключен Prometheus);
  5. алерт-правило (раздел 14) о подобном случае уже снимет поиск.
# Kibana Discover — стартовый запрос инцидента
level: ERROR AND status: [500 TO 599] | Last 2h
ГипотезаПроверка
деплой сломал APIсверка времени рестарта и времени ошибок
нагрузкаметрики CPU, лог «connection refused»
баговый запросгруппировка по IP и пользователю
Не чини по одному логу: соберимин 3–5 ошибок одного типа, иначе лечишь симптом, а не причину.

20. dissect vs grok: скорость парсинга

grok мощный, но на высоком потоке медленный. Для «простых» логов быстрее dissect:

filter {
  dissect {
    mapping => {
      "message" => "%{ts} %{level} [%{thread}] %{msg}"
    }
  }
}
# гибрид: лёгкий dissect для типовой строки + grok для «странной»
if [log][file][path] =~ /error/ { grok { match => { "message" => "..." } } }
else { dissect { mapping => { "message" => "..." } } }
Профилируй на реальной нагрузке, а не на фикстуре: одна тяжёлая строка на миллионе событий портит всю картину.

21. Шаблоны индексов и data streams

Правила создания индексов хранят в шаблонах, чтобы каждый день не настраивать руками:

PUT /_index_template/logs-template
{
  "index_patterns": ["logs-*"],
  "template": {
    "settings": {
      "number_of_shards": 2,
      "lifecycle": { "name": "logs-policy" }
    },
    "mappings": {
      "properties": { "@timestamp": { "type": "date" } }
    }
  },
  "priority": 100
}
Используй data streams для всех лог-потоков: они убирают ручное logs-2026.09.19-именование.

22. Импорт внешних данных

Данные приходят не только из Beats. Быстрые каналы — CSV и bulk API:

curl -X POST "localhost:9200/_bulk" \
  -H 'Content-Type: application/x-ndjson' --data-binary @bulk.ndjson
# bulk.ndjson — пары строк: метаданные и документ
{"index":{"_index":"prices"}}
{"sku":"A1","price":1000}
{"index":{"_index":"prices"}}
{"sku":"A2","price":2000}
bulk без _id создаёт новые документы: второй прогон того же CSV удвоит данные.

23. Чек-лист боевого ELK

Стек «завёлся на локалке» ≠ готов к бою. Пройди по списку:

  1. heap JVM: 50% RAM узла, не выше 31 ГБ — выше Java работает иначе;
  2. swap выключен, vm.max_map_count >= 262144;
  3. X-Pack включен: пароли, TLS между узлами, роли для Kibana и Filebeat;
  4. порты 9200/9300 закрыты, мониторинг кластера подключен;
  5. ILM и retention согласованы с требованиями хранения логов.
sysctl -w vm.max_map_count=262144   # и в /etc/sysctl.conf
Заведёшь стек без security, а потом «добавишь» — больно и дорого: включай защиту с первого запуска.

Что дальше

Метрики приложений собирай в Prometheus, графики — в Grafana, разворачивай всё через Docker. Все курсы — на главной странице.

← Вернуться к курсам