Тысячи логов без анализа: ELK Stack для телеком-оператора

Задача клиента: тысячи логов с сетевого оборудования без единой точки анализа

К нам обратился региональный телеком-оператор из Самары, обслуживающий более 50 000 абонентов. Инфраструктура компании включала сотни единиц сетевого оборудования — маршрутизаторы, коммутаторы, точки доступа, серверы RADIUS и DNS. Каждое устройство генерировало десятки гигабайт логов ежедневно, но единой системы их сбора и анализа не существовало.

Инженеры NOC (Network Operations Center) тратили часы на ручной анализ логов при расследовании инцидентов: подключались к каждому устройству по SSH, искали нужные записи grep-ом, сопоставляли события вручную. Среднее время расследования сетевого инцидента составляло 2-4 часа, а многие проблемы обнаруживались только по жалобам абонентов.

Мы предложили развернуть полноценную платформу централизованного логирования на базе ELK Stack (Elasticsearch, Logstash, Kibana) с Filebeat-агентами на серверах и syslog-сборщиком для сетевого оборудования. Проект был реализован за 5 недель.

Проектирование: архитектура ELK Stack для production

ELK Stack (Elasticsearch, Logstash, Kibana) — де-факто стандарт для централизованного сбора, хранения и визуализации логов. Мы спроектировали архитектуру с учётом объёмов данных телеком-оператора и требований к отказоустойчивости.

Компоненты стека и их роли в нашем решении

Каждый компонент ELK Stack в нашей архитектуре выполняет свою задачу:

  • Filebeat — лёгкий агент на каждом Linux/Windows-сервере. Читает лог-файлы и отправляет в Logstash. Потребляет минимум ресурсов (20-50 МБ RAM)
  • Logstash — конвейер обработки данных. Принимает события из Filebeat и syslog от сетевого оборудования, парсит, обогащает и отправляет в Elasticsearch
  • Elasticsearch — распределённый поисковый движок. Хранит, индексирует и обеспечивает полнотекстовый поиск по терабайтам логов
  • Kibana — веб-интерфейс для визуализации. Дашборды для NOC, поиск по логам, алерты

Архитектура, которую мы реализовали

Для телеком-оператора мы спроектировали следующую архитектуру:

# Схема потока данных:
#
# [Серверы]   --Filebeat--\
# [Маршрутизаторы] --syslog--+---> [Logstash x2] ---> [Elasticsearch Cluster] <--- [Kibana]
# [Коммутаторы] --syslog---/       (парсинг)          (3 узла, SSD)            (NOC панель)
# [RADIUS/DNS] --Filebeat-/

Серверы, которые мы выделили:

КомпонентCPURAMДискКоличество
Elasticsearch (master/data)8 ядер32 ГБSSD 500 ГБ+3
Logstash4 ядра8 ГБHDD 50 ГБ2
Kibana2 ядра4 ГБHDD 20 ГБ1
Filebeat (на каждом сервере)0.5 ядра128 МБ40+

Правило, которому мы следуем: JVM heap для Elasticsearch не более 50% RAM и не более 32 ГБ. На сервере с 64 ГБ RAM задаём heap 31 ГБ — остальное использует файловый кэш ОС.

Установка Elasticsearch кластера

Мы начали с установки Elasticsearch — ядра системы. Развернули кластер из трёх узлов на Ubuntu Server для отказоустойчивости.

Как мы устанавливали Elasticsearch

# На каждом узле (es01, es02, es03):

# 1. Добавляем репозиторий Elastic
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | \
    gpg --dearmor -o /usr/share/keyrings/elastic.gpg

echo "deb [signed-by=/usr/share/keyrings/elastic.gpg] \
    https://artifacts.elastic.co/packages/8.x/apt stable main" | \
    tee /etc/apt/sources.list.d/elastic-8.x.list

apt update && apt install elasticsearch -y

# 2. Системные настройки
cat >> /etc/security/limits.conf << 'EOF'
elasticsearch  soft  nofile  65536
elasticsearch  hard  nofile  65536
elasticsearch  soft  memlock unlimited
elasticsearch  hard  memlock unlimited
EOF

swapoff -a
sed -i '/swap/s/^/#/' /etc/fstab

echo 'vm.max_map_count=262144' >> /etc/sysctl.conf
sysctl -p

Применённая конфигурация кластера

Конфигурация основного узла (/etc/elasticsearch/elasticsearch.yml), которую мы разработали:

# === Конфигурация узла Elasticsearch ===
# Разработано инженерами АйТи Фреш

cluster.name: telecom-logging
node.name: es01
node.roles: [ master, data, ingest ]

path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch

network.host: 0.0.0.0
http.port: 9200
transport.port: 9300

discovery.seed_hosts:
  - 10.0.1.31:9300
  - 10.0.1.32:9300
  - 10.0.1.33:9300

cluster.initial_master_nodes:
  - es01
  - es02
  - es03

xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: elastic-certificates.p12

xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.keystore.path: http.p12

JVM heap (/etc/elasticsearch/jvm.options.d/heap.options):

-Xms16g
-Xmx16g
# Запуск и проверка
systemctl enable elasticsearch
systemctl start elasticsearch

curl -k -u elastic:password https://localhost:9200/_cluster/health?pretty
# Статус: green — все шарды распределены!

Генерация сертификатов для безопасности кластера

Elasticsearch 8.x требует TLS. Мы сгенерировали полный набор сертификатов:

# На первом узле (es01):

# 1. Создание CA
/usr/share/elasticsearch/bin/elasticsearch-certutil ca \
    --out /etc/elasticsearch/elastic-stack-ca.p12 --pass ""

# 2. Сертификаты для транспортного уровня
/usr/share/elasticsearch/bin/elasticsearch-certutil cert \
    --ca /etc/elasticsearch/elastic-stack-ca.p12 --ca-pass "" \
    --out /etc/elasticsearch/elastic-certificates.p12 --pass ""

# 3. Сертификаты для HTTP
/usr/share/elasticsearch/bin/elasticsearch-certutil http

# 4. Копирование на все узлы
cp elasticsearch/http.p12 /etc/elasticsearch/
chown elasticsearch:elasticsearch /etc/elasticsearch/*.p12
chmod 660 /etc/elasticsearch/*.p12

scp /etc/elasticsearch/elastic-certificates.p12 es02:/etc/elasticsearch/
scp /etc/elasticsearch/elastic-certificates.p12 es03:/etc/elasticsearch/

# 5. Установка паролей
/usr/share/elasticsearch/bin/elasticsearch-setup-passwords auto

Настройка Logstash: пайплайны для телеком-логов

Logstash стал ключевым компонентом — именно здесь мы парсили разнородные логи от сотен устройств в единый структурированный формат.

Установка и базовая конфигурация Logstash

apt install logstash -y

cat > /etc/logstash/logstash.yml << 'EOF'
node.name: logstash-01
path.data: /var/lib/logstash
path.logs: /var/log/logstash
pipeline.workers: 4
pipeline.batch.size: 250
pipeline.batch.delay: 50
http.host: "0.0.0.0"
http.port: 9600
log.level: info

xpack.monitoring.enabled: true
xpack.monitoring.elasticsearch.hosts: ["https://10.0.1.31:9200"]
xpack.monitoring.elasticsearch.username: logstash_system
xpack.monitoring.elasticsearch.password: "your_password"
xpack.monitoring.elasticsearch.ssl.certificate_authority: /etc/logstash/ca.crt
EOF

Пайплайны обработки логов, которые мы разработали

Мы создали специализированные пайплайны для каждого типа логов телеком-оператора:

Пайплайн для syslog от сетевого оборудования и Filebeat (/etc/logstash/conf.d/01-syslog.conf):

input {
  beats {
    port => 5044
    ssl => true
    ssl_certificate => "/etc/logstash/logstash.crt"
    ssl_key => "/etc/logstash/logstash.key"
    tags => ["beats"]
  }
}

filter {
  if [fileset][module] == "system" {
    grok {
      match => {
        "message" => "%{SYSLOGTIMESTAMP:syslog_timestamp} %{SYSLOGHOST:hostname} %{DATA:program}(?:\\[%{POSINT:pid}\\])?: %{GREEDYDATA:log_message}"
      }
    }
    date {
      match => [ "syslog_timestamp", "MMM  d HH:mm:ss", "MMM dd HH:mm:ss" ]
      target => "@timestamp"
    }
    mutate {
      remove_field => [ "syslog_timestamp" ]
    }
  }

  if [fileset][name] == "access" and [fileset][module] == "nginx" {
    grok {
      match => {
        "message" => "%{IPORHOST:client_ip} - %{DATA:user} \\[%{HTTPDATE:timestamp}\\] \"%{WORD:method} %{URIPATHPARAM:request} HTTP/%{NUMBER:http_version}\" %{NUMBER:response_code} %{NUMBER:bytes} \"%{DATA:referrer}\" \"%{DATA:user_agent}\""
      }
    }
    geoip {
      source => "client_ip"
      target => "geoip"
    }
    useragent {
      source => "user_agent"
      target => "ua"
    }
  }

  mutate {
    add_field => { "environment" => "production" }
  }
}

output {
  elasticsearch {
    hosts => ["https://10.0.1.31:9200", "https://10.0.1.32:9200", "https://10.0.1.33:9200"]
    user => "logstash_writer"
    password => "your_password"
    ssl => true
    cacert => "/etc/logstash/ca.crt"
    index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
    ilm_enabled => true
    ilm_rollover_alias => "logs"
    ilm_pattern => "000001"
    ilm_policy => "logs-lifecycle"
  }
}

Пайплайн для Windows Event Log:

filter {
  if [agent][type] == "winlogbeat" {
    mutate {
      rename => {
        "[winlog][event_id]" => "event_id"
        "[winlog][computer_name]" => "hostname"
        "[winlog][channel]" => "log_channel"
        "[winlog][provider_name]" => "source_name"
      }
    }

    if [event_id] == 4625 {
      mutate { add_tag => ["failed_login"] }
    }
    if [event_id] == 4624 {
      mutate { add_tag => ["successful_login"] }
    }
  }
}

Запуск и верификация Logstash

# Проверка конфигурации
/usr/share/logstash/bin/logstash --config.test_and_exit \
    -f /etc/logstash/conf.d/

systemctl enable logstash
systemctl start logstash

# Проверка статуса
systemctl status logstash
curl -s http://localhost:9600/_node/stats | python3 -m json.tool

tail -f /var/log/logstash/logstash-plain.log

Развёртывание Filebeat на серверах и Winlogbeat на Windows

Мы установили Filebeat на все Linux-серверы клиента и Winlogbeat на Windows-серверы — в сумме более 40 агентов.

Конфигурация Filebeat, которую мы применили

apt install filebeat -y

cat > /etc/filebeat/filebeat.yml << 'FBEOF'
# Конфигурация Filebeat — АйТи Фреш для телеком-оператора

filebeat.inputs:
  - type: log
    enabled: true
    paths:
      - /var/log/syslog
      - /var/log/auth.log
      - /var/log/kern.log
    fields:
      log_type: syslog
      environment: production
    fields_under_root: true

  - type: log
    enabled: true
    paths:
      - /var/log/nginx/access.log
    fields:
      log_type: nginx_access
    multiline.pattern: '^\d{1,3}\.'
    multiline.negate: true
    multiline.match: after

  - type: log
    enabled: true
    paths:
      - /var/log/myapp/*.json
    fields:
      log_type: application
    json.keys_under_root: true
    json.add_error_key: true

processors:
  - add_host_metadata:
      when.not.contains.tags: forwarded
  - add_cloud_metadata: ~
  - drop_fields:
      fields: ["agent.ephemeral_id", "agent.id", "ecs.version"]

output.logstash:
  hosts: ["10.0.1.40:5044"]
  ssl.certificate_authorities: ["/etc/filebeat/ca.crt"]
  loadbalance: true
  bulk_max_size: 2048

logging.level: info
logging.to_files: true
logging.files:
  path: /var/log/filebeat
  name: filebeat
  keepfiles: 7
FBEOF

filebeat modules enable system nginx
systemctl enable filebeat
systemctl start filebeat

filebeat test config
filebeat test output

Winlogbeat для Windows-серверов клиента

Для Windows-серверов RADIUS и DNS мы развернули Winlogbeat:

# Конфигурация winlogbeat.yml
winlogbeat.event_logs:
  - name: Application
    ignore_older: 72h
  - name: System
    ignore_older: 72h
  - name: Security
    event_id: 4624, 4625, 4634, 4648, 4672, 4720, 4726, 4740, 4767
    ignore_older: 72h
  - name: Microsoft-Windows-Sysmon/Operational
    ignore_older: 72h

processors:
  - add_host_metadata: ~

output.logstash:
  hosts: ["10.0.1.40:5044"]
  ssl.certificate_authorities: ["C:\\Program Files\\Winlogbeat\\ca.crt"]
# Установка как служба Windows
cd 'C:\Program Files\Winlogbeat'
.\install-service-winlogbeat.ps1
.\winlogbeat.exe test config
.\winlogbeat.exe test output
Start-Service winlogbeat

Kibana: дашборды для NOC

Kibana стала главным рабочим инструментом инженеров NOC. Мы установили её и создали специализированные дашборды для телеком-оператора.

Установка и конфигурация Kibana

apt install kibana -y

cat > /etc/kibana/kibana.yml << 'EOF'
server.port: 5601
server.host: "0.0.0.0"
server.name: "kibana-telecom"

elasticsearch.hosts: [
  "https://10.0.1.31:9200",
  "https://10.0.1.32:9200",
  "https://10.0.1.33:9200"
]
elasticsearch.username: "kibana_system"
elasticsearch.password: "your_password"
elasticsearch.ssl.certificateAuthorities: ["/etc/kibana/ca.crt"]

server.ssl.enabled: true
server.ssl.certificate: /etc/kibana/kibana.crt
server.ssl.key: /etc/kibana/kibana.key

i18n.locale: "en"

xpack.security.encryptionKey: "длинный-случайный-ключ-минимум-32-символа"
xpack.encryptedSavedObjects.encryptionKey: "другой-случайный-ключ-32-символа"
EOF

systemctl enable kibana
systemctl start kibana

Дашборды и алерты для инженеров NOC

Мы создали набор визуализаций и дашбордов, оптимизированных для задач телеком-оператора:

Настройка Data View и дашбордов:

  • Data View: паттерн filebeat-*, поле времени @timestamp
  • Топ хостов по ошибкам: Lens, Vertical Bar, hostname vs Count, Filter: level: error
  • Карта источников HTTP-запросов: Maps, geoip.location — для отслеживания DDoS
  • Timeline событий безопасности: Lens, Line Chart, @timestamp, разбивка по event_id
  • Таблица неудачных входов: Lens, Table, фильтр tags: failed_login

Алерты, которые мы настроили:

# Алерт: 10+ неудачных входов за 5 минут
# Stack Management -> Rules -> Create rule
# Тип: Elasticsearch query
# Условие: tags: "failed_login", count > 10, within 5 minutes
# Group by: source.ip
# Действия: Email admin + Slack #security-alerts

Дополнительные алерты для телеком-оператора:

  • Disk space warning: сообщение «No space left on device» в логах
  • Service down: нет логов от хоста > 5 минут
  • Error spike: ошибки превышают среднее за неделю в 3 раза
  • Brute force: 50+ неудачных попыток с одного IP за 10 минут

ILM-политики и оптимизация хранения

Для телеком-оператора с терабайтами логов управление жизненным циклом индексов — критически важная задача. Без ILM диски заполнились бы за считанные дни.

ILM-политика, которую мы разработали

# Создание ILM-политики для логов телеком-оператора
curl -k -u elastic:password -X PUT \
  "https://localhost:9200/_ilm/policy/logs-lifecycle" \
  -H 'Content-Type: application/json' -d '{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_primary_shard_size": "50gb",
            "max_age": "1d"
          },
          "set_priority": { "priority": 100 }
        }
      },
      "warm": {
        "min_age": "7d",
        "actions": {
          "shrink": { "number_of_shards": 1 },
          "forcemerge": { "max_num_segments": 1 },
          "set_priority": { "priority": 50 },
          "allocate": { "require": { "data": "warm" } }
        }
      },
      "cold": {
        "min_age": "30d",
        "actions": {
          "set_priority": { "priority": 0 },
          "freeze": {},
          "allocate": { "require": { "data": "cold" } }
        }
      },
      "delete": {
        "min_age": "90d",
        "actions": { "delete": {} }
      }
    }
  }
}'

Наша политика реализует типовой жизненный цикл:

  • Hot (0-7 дней): активная запись и поиск на SSD. Rollover при 50 ГБ или через 1 день
  • Warm (7-30 дней): только чтение. Индексы сжимаются, переносятся на HDD
  • Cold (30-90 дней): редкий доступ. Замораживание для экономии памяти
  • Delete (90+ дней): автоматическое удаление

Оптимизация производительности

Для высоконагруженной инсталляции телеком-оператора мы применили оптимизации:

# Шаблон индекса с оптимальными настройками
curl -k -u elastic:password -X PUT \
  "https://localhost:9200/_index_template/logs-template" \
  -H 'Content-Type: application/json' -d '{
  "index_patterns": ["filebeat-*"],
  "template": {
    "settings": {
      "number_of_shards": 3,
      "number_of_replicas": 1,
      "index.refresh_interval": "30s",
      "index.translog.durability": "async",
      "index.translog.sync_interval": "30s",
      "index.codec": "best_compression"
    }
  }
}'

Команды мониторинга, которые мы передали инженерам NOC:

# Здоровье кластера
curl -k -u elastic:password 'https://localhost:9200/_cluster/health?pretty'

# Статистика узлов
curl -k -u elastic:password 'https://localhost:9200/_nodes/stats?pretty&filter_path=nodes.*.os,nodes.*.jvm.mem,nodes.*.fs'

# Статистика индексов
curl -k -u elastic:password 'https://localhost:9200/_cat/indices?v&s=store.size:desc&h=index,docs.count,store.size,pri.store.size'

# Pending tasks
curl -k -u elastic:password 'https://localhost:9200/_cluster/pending_tasks?pretty'

# Thread pool queues
curl -k -u elastic:password 'https://localhost:9200/_cat/thread_pool?v&h=node_name,name,active,rejected,queue'

Результаты внедрения

Проект по внедрению централизованного логирования ELK Stack для телеком-оператора был завершён за 5 недель. Вот что мы достигли:

  • Единая панель мониторинга для инженеров NOC — все логи со всех устройств в одном месте
  • Время расследования инцидента сократилось с 2-4 часов до 15-30 минут — полнотекстовый поиск по терабайтам за секунды
  • Проактивное обнаружение проблем — алерты в Kibana оповещают до жалоб абонентов
  • 40+ Filebeat-агентов на серверах + syslog-сбор с сотен единиц сетевого оборудования
  • ILM-политика с автоматической ротацией: hot (SSD) → warm → cold → delete за 90 дней
  • Отказоустойчивый кластер Elasticsearch из 3 узлов — потеря одного узла не влияет на работу
  • TLS-шифрование всех коммуникаций между компонентами
  • Обучение команды NOC — 8-часовой тренинг по работе с Kibana и расследованию инцидентов

Бизнес-результат: среднее время восстановления сервиса (MTTR) при сетевых инцидентах сократилось на 70%. Количество жалоб абонентов, обнаруженных до обращения, выросло с 0% до 40%. Руководство получило реальные метрики качества сети для принятия инвестиционных решений.

Часто задаваемые вопросы

По нашему опыту, для 50 серверов со средней нагрузкой (10-20 ГБ логов в сутки) рекомендуется: Elasticsearch — 3 узла по 8 CPU / 32 ГБ RAM / 500 ГБ SSD; Logstash — 1 сервер 4 CPU / 8 ГБ RAM; Kibana — 1 сервер 2 CPU / 4 ГБ RAM. При хранении 90 дней потребуется около 1.5-2 ТБ на кластер. Filebeat потребляет 50-100 МБ RAM на источнике.

Да, Filebeat может отправлять данные напрямую в Elasticsearch. Filebeat имеет встроенные модули для парсинга популярных форматов. Такая архитектура проще. Logstash нужен, когда требуется сложная обработка: обогащение данными из внешних источников (GeoIP, lookup-таблицы), кастомный парсинг нестандартных форматов, маршрутизация в несколько хранилищ. В проекте для телеком-оператора мы использовали Logstash из-за разнородных источников.

Elasticsearch обеспечивает отказоустойчивость через репликацию: primary shard имеет replica на другом узле. Минимум 3 узла. Logstash масштабируется горизонтально — мы ставим 2 инстанса за балансировщиком. Filebeat имеет встроенный буфер и повторную отправку. Для буферизации при пиковых нагрузках добавляем Redis или Kafka между Filebeat и Logstash.

Миграция выполняется поэтапно. Шаг 1: Установите ELK параллельно. Шаг 2: Настройте дублирование логов в оба места. Шаг 3: Воссоздайте дашборды в Kibana. Шаг 4: Переключите пользователей. Шаг 5: Отключите старую систему. Исторические данные можно загрузить через Logstash с file input.

Основные альтернативы: Graylog — проще, но менее гибок; Loki + Grafana — экономичнее по ресурсам, не индексирует текст; Splunk — коммерческое решение корпоративного класса; ClickHouse + Vector — для больших объёмов; Datadog / Sumo Logic — облачные SaaS. Специалисты АйТи Фреш чаще всего выбирают ELK как оптимальный баланс возможностей и стоимости.

Нужна помощь с настройкой?

Специалисты АйТи Фреш помогут с внедрением и настройкой — 15+ лет опыта, обслуживание от 15 000 ₽/мес

📞 Связаться с нами
#ELK Stack настройка#Elasticsearch установка#Logstash конфигурация#Kibana дашборды#Filebeat настройка#централизованное логирование#ELK мониторинг серверов#Elasticsearch индексы