Сбор логов в OpenSearch строится по одной схеме: агент читает источник (файл, journald, Event Log, stdout контейнера), отправляет документы по HTTP на порт 9200, кластер раскладывает их по индексам согласно шаблону, а вы ищете события в Dashboards или через API. Для базового сценария хватает одного Filebeat: он закрывает логи Linux, Nginx и приложений, которые пишут в файл.
Большинство проблем после запуска связано не с агентом, а с маппингом полей, отсутствием write-алиаса и политики хранения. Рабочий порядок настройки: шаблон индексов, ролловер и ISM-политика, затем агент, затем проверка поступления событий. Кластер уже готов принять поток, а ошибки маппинга видны на первом же документе, поэтому отладка занимает минуты, а не часы.
Дальше: конфигурации Filebeat, Logstash, Fluent Bit и Vector, структура индексов logs-APP-YYYY.MM.DD, шаблоны и маппинг, ISM-политики, диагностика ошибок и готовые поисковые запросы для логов приложений, Linux, Windows, Docker и Kubernetes.
Архитектура сбора логов в OpenSearch: от источника до индекса
Пайплайн состоит из четырех зон: сбор, обработка, хранение, визуализация. Источник формирует поток событий, агент читает его и отправляет по сети, обработчик приводит поля к общему виду, OpenSearch хранит документы в индексах, Dashboards показывает результаты поиска.
источник агент обработка хранилище визуализация /var/log/nginx Filebeat Logstash OpenSearch Dashboards journald Fluent Bit Vector индексы + ISM Discover Windows Event Log Vector ingest pipeline снапшоты визуализации stdout контейнера
OpenSearch появился как форк Elasticsearch 7.10.2 и Kibana 7.10.2 под лицензией Apache 2.0. Для логирования это означает: агенты семейства Beats 7.17 OSS работают с кластером без переделок, а версии 8.x формально совместимы через output.elasticsearch, но поддержки от Elastic у такой связки нет. В продакшне с OpenSearch чаще берут Filebeat OSS 7.17, Fluent Bit, Vector и Data Prepper, собственный ingest-инструмент проекта OpenSearch.
Если вы только выбираете стек, начните с обзора архитектуры централизованного логирования: централизованный сбор и анализ логов в 2026. Там разобраны варианты хранилищ и критерии выбора.
Ключевые компоненты: агенты, обработчики, хранилище, визуализация
| Компонент | Задача | Инструменты | Что настроить |
|---|---|---|---|
| Агенты | читать источник и доставить события | Filebeat, Fluent Bit, Vector, Logstash input | inputs/sources, очереди, TLS, лимиты буфера |
| Обработчики | парсить, обогащать, маршрутизировать | Logstash filters, Vector remap, ingest pipelines, Data Prepper | grok/VRL, маппинг дат, ветвление потоков |
| Хранилище | принять, разложить, хранить | OpenSearch | шаблоны, шарды, реплики, ISM, снапшоты |
| Визуализация | поиск и анализ | OpenSearch Dashboards | index pattern, saved search, алерты, роли |
Зоны ответственности задают направление диагностики: агент отвечает за чтение файла и доставку, обработчик за корректность полей, кластер за прием и хранение, Dashboards за доступ к данным.
Когда достаточно Filebeat, а когда нужен Logstash или Vector
Filebeat читает файлы и журналы, умеет базовые processors (add_fields, drop_event, decode_json_fields) и отправляет данные напрямую в OpenSearch. Потребляет 50-100 МБ памяти. Этого хватает, если логи уже структурированы или парсятся готовым модулем (nginx, system, docker).
Logstash нужен для тяжелой обработки: grok по десяткам шаблонов, geoip, translate, несколько выходов, условные ветки. Цена: JVM и heap 1-2 ГБ на инстанс.
Vector дает гибкость Logstash при потреблении 50-150 МБ: трансформации описываются на VRL, конфиг компактный. Fluent Bit самый легкий (10-30 МБ) и стандартен для Kubernetes: DaemonSet, парсер CRI, multiline, метаданные подов.
| Агент | Память | Сильные стороны | Когда брать |
|---|---|---|---|
| Filebeat | 50-100 МБ | модули, winlog, container input, поля ECS | Linux, Windows и Docker без сложного парсинга |
| Fluent Bit | 10-30 МБ | CRI, Kubernetes, низкое потребление | Kubernetes, edge-узлы, sidecar |
| Vector | 50-150 МБ | VRL, агрегация, несколько sinks | замена Logstash, фильтрация на источнике |
| Logstash | 1-2 ГБ | grok, плагины, маршрутизация | сложный парсинг, legacy-пайплайны |
Правило выбора простое: один источник и простой формат - Filebeat; много источников и сложный парсинг - Logstash или Vector; контейнеры - Fluent Bit.
Подключение агентов: Beats, Logstash, Fluent Bit и Vector
Примеры рассчитаны на OpenSearch 2.x и 3.x с включенным security plugin и TLS. Для каждого агента создайте отдельного пользователя с правами только на запись в нужные индексы: общий admin-аккаунт в конфиге агента приводит к неконтролируемому доступу к кластеру.
Filebeat: лёгкий агент для Linux, Windows и Docker
Ставьте OSS-сборку 7.17 (deb/rpm или архив). Отключите управление шаблонами и ILM: механизмы Elastic с OpenSearch не работают, индексы создаст ваш шаблон.
filebeat.inputs:
- type: filestream
id: nginx
paths:
- /var/log/nginx/*.log
fields:
service.name: nginx
- type: container
paths:
- /var/lib/docker/containers/*/*.log
output.elasticsearch:
hosts: ["https://os-node1.example.com:9200"]
username: "beats-writer"
password: "${OS_PASSWORD}"
ssl.certificate_authorities: ["/etc/filebeat/ca.pem"]
index: "logs-nginx"
setup.ilm.enabled: false
setup.template.enabled: false
В index указан write-алиас logs-nginx: за ежедневные индексы и переключение алиаса отвечает ISM. Без ролловера подставляйте дату: logs-nginx-%{+yyyy.MM.dd}.
Для Windows вместо filestream подключают winlog:
- type: winlog name: Security event_id: 4624, 4625, 4634 ignore_older: 72h
Проверка: ./filebeat test config -c filebeat.yml, затем ./filebeat test output -c filebeat.yml. Для наблюдения за отправкой запустите ./filebeat -e -d "publish" -c filebeat.yml: в логе появятся строки PublishEvents и ack. Если PublishEvents есть, а ack нет, проблема на стороне кластера: права, TLS или маппинг.
Logstash: обработка и маршрутизация логов перед отправкой
Для OpenSearch нужен плагин logstash-output-opensearch: bin/logstash-plugin install logstash-output-opensearch.
input {
beats { port => 5044 }
}
filter {
grok {
match => { "message" => "%{IPORHOST:client.ip} - %{DATA:user.name} \[%{HTTPDATE:log.timestamp}\] \"%{WORD:http.request.method} %{DATA:url.original}\" %{NUMBER:http.response.status_code:int}" }
}
date {
match => [ "log.timestamp", "dd/MMM/yyyy:HH:mm:ss Z" ]
target => "@timestamp"
}
mutate { remove_field => [ "log.timestamp" ] }
}
output {
opensearch {
hosts => ["https://os-node1.example.com:9200"]
user => "logstash-writer"
password => "${OS_PASSWORD}"
ssl => true
ssl_certificate_verification => true
index => "logs-nginx"
}
}
Проверка конфига: bin/logstash -f nginx.conf --config.test_and_exit. Если grok не сработал, Logstash ставит тег _grokparsefailure: отправляйте такие события в отдельный индекс logs-nginx-unparsed и разбирайте отдельно.
Схему с Elasticsearch и Kibana для сравнения разбираем в материале готовое решение ELK-стека для сбора и анализа логов.
Fluent Bit: сбор логов в Kubernetes и контейнерах
[SERVICE]
Flush 1
Log_Level info
[INPUT]
Name tail
Path /var/log/containers/*.log
Parser cri
Tag kube.*
Mem_Buf_Limit 50MB
[FILTER]
Name kubernetes
Match kube.*
Merge_Log On
Keep_Log Off
[OUTPUT]
Name opensearch
Match *
Host os-node1.example.com
Port 9200
HTTP_User fluentbit
HTTP_Passwd ${OS_PASSWORD}
tls On
tls.verify On
Logstash_Prefix logs-k8s
Logstash_DateFormat %Y.%m.%d
Suppress_Type_Name On
В Kubernetes Fluent Bit ставят DaemonSet через Helm. Плагин kubernetes добавляет имена подов, namespace и labels. Задайте Mem_Buf_Limit и Storage.type filesystem, чтобы не потерять события при перезапуске пода.
Про маршрутизацию потоков и совместную работу с метриками: маршрутизация логов и метрик в DevOps.
Vector: производительный агент с гибкими трансформациями
[sources.app_logs]
type = "file"
include = ["/var/log/app/*.log"]
[transforms.parse_app]
type = "remap"
inputs = ["app_logs"]
source = '''
. = parse_json!(.message)
.level = upcase(string!(.level))
.ts = parse_timestamp!(.ts, format: "%+")
'''
[sinks.opensearch]
type = "elasticsearch"
inputs = ["parse_app"]
endpoints = ["https://os-node1.example.com:9200"]
mode = "bulk"
bulk.index = "logs-app"
auth.strategy = "basic"
auth.user = "vector-writer"
auth.password = "${OS_PASSWORD}"
compression = "gzip"
request.retry_attempts = 10
Проверка: vector validate /etc/vector/vector.toml и vector top для наблюдения за потоками. Трансформации на VRL отбрасывают шум до отправки: debug-события health-check в продакшне не нужны и только занимают место в индексах.
Настройка индексов, шаблонов и политик хранения
Индекс в OpenSearch это набор шардов с документами; шаблон задает настройки и маппинг для всех новых индексов по маске; ISM-политика управляет жизненным циклом. Без шаблона кластер создаст индекс с динамическим маппингом, и первое строковое значение в числовом поле заблокирует запись.
Структура индексов и именование: logs-app-YYYY.MM.DD
Рабочая схема именования: logs-ИСТОЧНИК-YYYY.MM.DD, например logs-nginx-2026.09.11, logs-app-2026.09.11, logs-k8s-2026.09.11. Для каждого потока заведите write-алиас (logs-nginx) и используйте его в конфиге агента. Чтение в Dashboards идет по маске logs-* через index pattern.
Плюсы схемы: старые индексы удаляются целиком без дорогого delete_by_query; роли в security plugin выдаются по маске (аналитик видит logs-app-*, но не logs-audit-*); ролловер и ISM работают предсказуемо.
Шаблоны индексов и маппинг полей
Шаблон создается один раз через API или Dashboards:
PUT _index_template/logs-app-template
{
"index_patterns": ["logs-app-*"],
"priority": 200,
"template": {
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"refresh_interval": "30s"
},
"mappings": {
"dynamic_templates": [
{
"strings_as_keywords": {
"match_mapping_type": "string",
"mapping": { "type": "keyword", "ignore_above": 1024 }
}
}
],
"properties": {
"@timestamp": { "type": "date" },
"level": { "type": "keyword" },
"message": { "type": "text" },
"service.name": { "type": "keyword" },
"http.response.status_code": { "type": "integer" },
"client.ip": { "type": "ip" }
}
}
}
}
Что здесь важно: dynamic_templates переводят строки в keyword с ignore_above, чтобы поля вида request_id не раздували индекс; @timestamp объявлен как date; level и service.name это keyword для точных фильтров; message остается text для полнотекстового поиска. Для критичных индексов включайте dynamic: strict, тогда неизвестное поле не появится в маппинге незаметно.
Типовые конфликты: поле, которое в одном сервисе строка, а в другом число; вложенный JSON с меняющейся структурой; поля с сотнями уникальных ключей (например, http.headers.*). Лечится явным маппингом и отключением индексации для отладочных полей: "index": false экономит место и ускоряет запись.
Если логи приходят из внешних систем и требуют нормализации на входе, посмотрите разбор ingest pipeline и ограничений OpenSearch в статье корпоративный поиск: от файлового сервера до S3 и Elasticsearch.
Политики хранения и ролловер индексов (ISM)
ISM-политика описывает состояния hot, warm, delete и условия переходов. Пример: ролловер при 50 ГБ или сутках, переход в warm через два дня, удаление через 30 дней.
PUT _plugins/_ism/policies/logs-app-policy
{
"policy": {
"description": "rollover 50gb или 1 день, удаление через 30 дней",
"default_state": "hot",
"states": [
{
"name": "hot",
"actions": [
{ "rollover": { "min_index_age": "1d", "min_primary_shard_size": "50gb" } }
],
"transitions": [
{ "state_name": "warm", "conditions": { "min_index_age": "2d" } }
]
},
{
"name": "warm",
"actions": [
{ "force_merge": { "max_num_segments": 1 } },
{ "replica_count": { "number_of_replicas": 1 } }
],
"transitions": [
{ "state_name": "delete", "conditions": { "min_index_age": "30d" } }
]
},
{
"name": "delete",
"actions": [ { "delete": {} } ]
}
],
"ism_template": [
{ "index_patterns": ["logs-app-*"], "priority": 100 }
]
}
}
Политику привязывают к шаблону через блок ism_template, тогда каждый новый индекс получит ее автоматически. Первый индекс под write-алиас создают вручную:
PUT logs-app-000001
{
"aliases": {
"logs-app": { "is_write_index": true }
}
}
Дальше ISM создает logs-app-000002, logs-app-000003 и переключает алиас. Проверить состояние: GET _plugins/_ism/explain/logs-app-*.
Проверка поступления событий и типовые ошибки
Проверка строится от кластера к агенту: сначала смотрим, создан ли индекс и растет ли счетчик документов, затем сверяем маппинг, затем проверяем агент.
Проверка через OpenSearch Dashboards и API
GET _cluster/health GET _cat/indices/logs-*?v&s=index GET _cat/aliases/logs-app?v GET logs-app-*/_count GET logs-app-2026.09.11/_mapping GET _plugins/_ism/explain/logs-app-*
В Dashboards создайте index pattern logs-* с полем времени @timestamp, откройте Discover и отсортируйте по времени. Сравните @timestamp документа с системным временем хоста: расхождение в часы означает неверный часовой пояс или пропущенный date-фильтр.
Типовые ошибки при сборе логов и их решение
| Симптом | Причина | Решение |
|---|---|---|
| Индекс не создается, агент пишет 403 | у пользователя нет прав create_index и index на маску | выдать роль с index_permissions на logs-* в security plugin |
| mapper_parsing_exception | конфликт типов в маппинге | поправить шаблон, переиндексировать, включить dynamic: strict |
| @timestamp 1970 года или время агента | дата не распарсена | добавить grok и date, указать формат и timezone |
| 401 или 403 при подключении | нет пароля, неверный сертификат, закрыт _bulk | проверить filebeat test output, роль, настройки TLS |
| 429 Too Many Requests | переполнена очередь bulk, кластер не успевает | снизить размер батча, включить retry, увеличить heap |
| Поля есть, поиск по ним не работает | строки стали text, а не keyword | задать маппинг и dynamic_templates |
| Диск быстро заполняется | нет ISM, индексы не удаляются | применить политику с ролловером и delete |
Отдельно про доступ: в security plugin OpenSearch роли собираются из backend roles и прав на индексы. Аналитику достаточно read на logs-*, агентам нужны create_index и index, администратору manage. В Dashboards разграничение делают через tenants, чтобы дашборды одной команды не меняли другие.
Поиск и анализ логов: приложения, Linux, Windows, Docker
В Dashboards доступны KQL (level: ERROR and service.name: checkout) и Lucene (level:ERROR AND http.response.status_code:[500 TO 599]). Для агрегаций и точных фильтров используйте DSL через API.
Поиск логов приложений: ошибки, исключения, тайминги
POST logs-app-*/_search
{
"size": 0,
"query": {
"bool": {
"filter": [
{ "term": { "level": "ERROR" } },
{ "range": { "@timestamp": { "gte": "now-24h" } } }
]
}
},
"aggs": {
"errors_per_hour": {
"date_histogram": { "field": "@timestamp", "fixed_interval": "1h" }
}
}
}
Для расследования ищите по request_id или trace.id: один запрос покажет всю цепочку событий. График ошибок по часам строится агрегацией date_histogram с фильтром level: ERROR, а топ проблемных сервисов - terms-агрегацией по service.name.
Анализ логов Linux: system.auth и системные события
Модуль system в Filebeat кладет события аутентификации в dataset system.auth. Полезные поля: system.auth.user, system.auth.sudo.command, system.auth.sudo.tty, event.outcome. Запрос для неудачных входов: dataset: "system.auth" and event.outcome: failure. Топ sudo-команд строится terms-агрегацией по system.auth.sudo.command.
Без включенного модуля system логи sudo и sshd не попадут в индекс, даже если Filebeat запущен и отправляет другие события.
Логи Windows: Event Log и безопасность
Сбор идет через winlog input. Ключевые поля: winlog.event_id, winlog.provider_name, winlog.event_data.*. Вход в систему: event.code 4624, неудачный вход 4625, выход 4634. Запрос по неудачным входам: event.code: 4625 and winlog.event_data.TargetUserName: admin. Распределение событий по кодам дает быстрый обзор состояния парка Windows.
Логи Docker и Kubernetes: контейнеры и поды
Filebeat container input или Fluent Bit добавляют поля container.name, container.id, kubernetes.pod.name, kubernetes.namespace. Поиск ошибок в конкретном сервисе: container.name: "checkout-api" and level: ERROR. Топ контейнеров по числу ошибок строится terms-агрегацией по container.name с фильтром level: ERROR.
Когда потоков становится много, ручной разбор уступает автоматике: анализ логов с помощью ИИ и LLM описывает связку OpenSearch и моделей. Для доступа к моделям без VPN и с оплатой в рублях подойдет агрегатор API AiTunnel: единый интерфейс к GPT, Gemini и Claude, бюджеты и ключи по проектам.
Подготовка кластера к росту объема данных
Кластер деградирует не от объема логов, а от количества мелких шардов и отсутствия ролловера. Планируйте шарды и tier'ы заранее, пока данных немного.
Размер шардов и количество реплик: практические рекомендации
- Размер первичного шарда: 10-50 ГБ. Меньше 10 ГБ дает лишний overhead, больше 50 ГБ усложняет восстановление.
- Количество шардов на узел: до 20 на каждый 1 ГБ heap. Узел с heap 16 ГБ держит около 320 шардов.
- Реплики: минимум 1 для отказоустойчивости. Для горячих данных с высокой нагрузкой чтения добавьте вторую.
- Расчет: 100 ГБ логов в сутки при ролловере по 50 ГБ дают два индекса в день. С тремя первичными шардами и одной репликой это около 360 шардов за 30 дней хранения, что укладывается в кластер из трех узлов с heap 16 ГБ.
Для размещения кластера подходит облачная инфраструктура: Timeweb Cloud дает серверы, VDS/VPS и хранилище, ресурсы меняются по мере роста потока логов.
Tiered storage: hot-warm-cold архитектура
Узлам задают атрибуты node.attr.temp: hot, warm, cold. Свежие индексы живут на SSD (hot), данные старше двух дней переезжают на HDD (warm), архив уходит в cold или в снапшот объектного хранилища. Переходы описываются в ISM-политике: force_merge, reduce_replicas и allocation по атрибуту temp.
{
"name": "warm",
"actions": [
{ "allocation": { "require": { "temp": "warm" }, "wait_for": "false" } }
]
}
Снапшоты в S3 дешевле дисков и позволяют восстановить архив за минуты. Регулярность: раз в сутки и перед массовыми изменениями маппинга.
Мониторинг: GET _cluster/health, GET _cat/nodes?v&h=name,heap.percent,disk.used_percent, GET _cat/shards/logs-*?v&s=store:desc. Порог для реакции: heap выше 75% или disk выше 80%. Начните с шаблона и ISM-политики, подключите первый агент, проверьте счетчик документов через _count, и только потом расширяйте поток на все хосты.