Логирование: ELK stack

ELK stack (Elasticsearch + Logstash + Kibana) — платформа централизованного сбора, хранения и визуализации логов со всех сервисов в едином интерфейсе.

Зачем нужно

При наличии нескольких сервисов или серверов ручной просмотр логов через SSH на каждом становится неудобным. ELK собирает логи в одном месте: поиск по всем сервисам одновременно, фильтрация, дашборды, алерты. Стандарт для enterprise и крупных проектов.

Где используется

  • Централизованный сбор логов из Docker-контейнеров, Kubernetes, серверов
  • Поиск по логам всех микросервисов из единого интерфейса Kibana
  • Анализ паттернов ошибок и аномалий
  • Дебаггинг распределённых запросов через trace ID

Основной контент

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

Приложение/Сервер → Filebeat/Logstash → Elasticsearch → Kibana
    (генерирует логи)   (сбор и парсинг)  (хранение)    (UI поиск)
Компонент Роль
Elasticsearch Поисковое хранилище данных
Logstash ETL: сбор, трансформация, отправка логов
Kibana Web UI для поиска и дашбордов
Filebeat Лёгкий агент сбора логов (альтернатива Logstash на хостах)
Fluentd Альтернатива Logstash, популярен в Kubernetes

ELK через docker-compose

# docker-compose.elk.yml
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
    environment:
      - discovery.type=single-node
      - ELASTIC_PASSWORD=changeme
      - xpack.security.enabled=true
    volumes:
      - esdata:/usr/share/elasticsearch/data
    ports:
      - "9200:9200"

  kibana:
    image: docker.elastic.co/kibana/kibana:8.12.0
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
      - ELASTICSEARCH_USERNAME=kibana_system
      - ELASTICSEARCH_PASSWORD=changeme
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch

  logstash:
    image: docker.elastic.co/logstash/logstash:8.12.0
    volumes:
      - ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
    depends_on:
      - elasticsearch

volumes:
  esdata:

Конфиг Logstash

# logstash.conf
input {
  beats {
    port => 5044      # принимает от Filebeat
  }
}

filter {
  # Парсинг JSON-логов Node.js
  if [message] =~ /^\{/ {
    json {
      source => "message"
    }
  }

  # Добавить геолокацию по IP
  geoip {
    source => "clientip"
  }
}

output {
  elasticsearch {
    hosts => ["elasticsearch:9200"]
    index => "myapp-logs-%{+YYYY.MM.dd}"
    user => "elastic"
    password => "changeme"
  }
}

Filebeat на сервере/в контейнере

# filebeat.yml
filebeat.inputs:
  - type: log
    paths:
      - /var/log/myapp/*.log
    json.keys_under_root: true     # парсить JSON-логи
    json.add_error_key: true

  - type: container
    paths:
      - /var/lib/docker/containers/*/*.log

output.logstash:
  hosts: ["logstash:5044"]

Более простая альтернатива: Loki + Grafana

Для небольших проектов Grafana Loki значительно легче ELK:

# docker-compose.loki.yml
services:
  loki:
    image: grafana/loki:latest
    ports:
      - "3100:3100"

  promtail:
    image: grafana/promtail:latest
    volumes:
      - /var/log:/var/log
      - ./promtail-config.yml:/etc/promtail/config.yml

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"

Частые ошибки

  • Запускать Elasticsearch с 512MB heap — минимально рекомендуется 2GB (ES_JAVA_OPTS=-Xms2g -Xmx2g)
  • Хранить все логи в одном индексе без rotation — индекс растёт неограниченно
  • Логировать в ELK вместо console.log напрямую из кода — правильно: файл/stdout → Filebeat → ELK
  • Не настроить index lifecycle management (ILM) — диск заполняется старыми логами

Связанные темы

Ресурсы