Выберите продукт

Fluent Bit на VDS: сбор логов в Loki/ELK с минимальной нагрузкой

Практическая схема для админов и девопсов: ставим Fluent Bit на VDS, собираем логи Nginx и journald, настраиваем мультилайн и фильтры, ограничиваем память и включаем дисковый буфер, отправляем данные в Loki или Elasticsearch. Акцент на стабильность и низкие расходы CPU и RAM.
Fluent Bit на VDS: сбор логов в Loki/ELK с минимальной нагрузкой

Fluent Bit — легковесный агент логов, который отлично чувствует себя на небольших VDS. Его сильные стороны: низкое потребление памяти и CPU, богатый набор входов/фильтров/выходов и надёжная схема буферизации. В этой статье разберём боевую конфигурацию под типичный стек: Nginx + systemd‑сервисы, отгрузка в Loki и/или Elasticsearch (ELK), и акцент на экономию ресурсов без потери данных.

Почему Fluent Bit на VDS и как избежать лишней нагрузки

На небольших инстансах важны два фактора: предсказуемая память и устойчивость к пикам. Fluent Bit позволяет:

  • Писать части буфера на диск при сетевых проблемах (filesystem storage), не раздувая RAM.
  • Лимитировать объём памяти на каждый выход (Mem_Buf_Limit), чтобы избежать OOM.
  • Фильтровать шум до отгрузки (например, health‑checks, статические ответы 200).
  • Аккуратно парсить JSON‑логи Nginx без тяжёлых регэкспов.
  • Собрать journald/systemd‑логи без лишнего «мусора» по unit‑фильтрам.

Дальше — практическая конфигурация, которую можно взять за основу и адаптировать под свои каталоги логов и приёмники.

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

На современных дистрибутивах достаточно обычной установки пакета. Сервисный unit и базовые конфиги ставятся автоматически.

sudo apt update
sudo apt install fluent-bit

# Проверить версию и плагины
fluent-bit --version
fluent-bit --help

Рекомендуемая структура конфигурации: один «корневой» /etc/fluent-bit/fluent-bit.conf с Service и @INCLUDE на отдельные файлы входов/фильтров/выходов, плюс /etc/fluent-bit/parsers.conf для парсеров.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Базовый fluent-bit.conf с дисковым буфером

Сервисная секция задаёт тайминги, лог‑уровень и каталог для файлам буфера. HTTP‑сервер удобен для локальной диагностики метрик агента.

# /etc/fluent-bit/fluent-bit.conf
[SERVICE]
    Flush           5
    Daemon          Off
    Log_Level       info
    Parsers_File    /etc/fluent-bit/parsers.conf
    HTTP_Server     On
    HTTP_Listen     127.0.0.1
    HTTP_Port       2020

    # Дисковый сторедж для устойчивости при сбоях сети
    storage.path              /var/lib/fluent-bit/storage
    storage.sync              normal
    storage.checksum          On
    storage.backlog.mem_limit 64M

@include inputs.conf
@include filters.conf
@include outputs.conf

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

Схема конфигурации: Nginx и journald, Fluent Bit и дисковый буфер

Парсеры: JSON для Nginx и мультилайн

Лучше сформировать JSON прямо в Nginx, чтобы отказаться от тяжёлых регэкспов. Пример формата:

# В nginx.conf (фрагмент)
log_format json escape=json '{"time":"$time_iso8601","remote":"$remote_addr","method":"$request_method","uri":"$request_uri","status":$status,"size":$body_bytes_sent,"ua":"$http_user_agent","referer":"$http_referer","host":"$host","req_time":$request_time}';
access_log /var/log/nginx/access.json json;

В парсерах ничего «выдумывать» не нужно — используем встроенный JSON‑парсер, лишь укажем ключ времени и формат.

# /etc/fluent-bit/parsers.conf
[PARSER]
    Name        nginx_json
    Format      json
    Time_Key    time
    Time_Format %Y-%m-%dT%H:%M:%S%z
    Time_Keep   On

# Пример мультилайна для ошибок/трейсов (адаптируйте под свой софт)
[MULTILINE_PARSER]
    Name          php_trace
    Type          regex
    Flush_Timeout 2000
    # Первая строка трейс-сообщения: дата в начале
    Rule          "start_state"   "/^\d{4}\/\d{2}\/\d{2} /"  "cont"
    Rule          "cont"          "/^(\s|#|Stack trace:|PHP )/" "cont"

Если приложение уже пишет чистый JSON, достаточно указать Format json. Для текстовых трейс‑логов настраивайте мультилайн под реальный шаблон первой строки.

Inputs: tail для Nginx и systemd для journald

Опишем входы в отдельном файле. Важные моменты для tail:

  • storage.type filesystem — чтобы куски уходили в дисковый буфер при проблемах сети.
  • DB и DB.Sync — надёжное хранение оффсетов, чтобы не пропускать строки после рестартов.
  • Buffer_Chunk_Size и Buffer_Max_Size — контроль размера чанков и памяти.
# /etc/fluent-bit/inputs.conf
[INPUT]
    Name                tail
    Tag                 nginx.access
    Path                /var/log/nginx/access.json
    Parser              nginx_json
    Skip_Long_Lines     On
    Refresh_Interval    5
    Rotate_Wait         5
    DB                  /var/lib/fluent-bit/nginx-access.db
    DB.Sync             Full
    Mem_Buf_Limit       16M
    Buffer_Chunk_Size   64k
    Buffer_Max_Size     256k
    storage.type        filesystem

[INPUT]
    Name                tail
    Tag                 nginx.error
    Path                /var/log/nginx/error.log
    Multiline           On
    Multiline.Parser    php_trace
    Skip_Long_Lines     On
    Refresh_Interval    5
    DB                  /var/lib/fluent-bit/nginx-error.db
    DB.Sync             Full
    Mem_Buf_Limit       16M
    Buffer_Chunk_Size   64k
    Buffer_Max_Size     256k
    storage.type        filesystem

# journald через systemd input: фильтруем по unit, чтобы не тащить весь системный шум
[INPUT]
    Name                systemd
    Tag                 sysd.*
    Systemd_Filter      _SYSTEMD_UNIT=nginx.service
    Systemd_Filter      _SYSTEMD_UNIT=php-fpm.service
    Read_From_Tail      On
    Mem_Buf_Limit       32M
    storage.type        filesystem

Если у вас несколько пуулов PHP‑FPM или сервисов приложений, добавьте дополнительные Systemd_Filter. Так вы избежите лишней нагрузки и индексации ненужных сообщений.

Фильтры: чистим шум и ограничиваем кардинальность

Главная экономия — не отправлять то, что не нужно анализировать. Для HTTP‑доступов это, как правило, статические 200‑ответы к ассетам, а для сервисов — шумное debug‑логирование. Ещё одна статья затрат в Loki/ELK — кардинальность меток/полей, так что аккуратно выбираем, что поднимаем до labels/fields.

# /etc/fluent-bit/filters.conf
# Удалим самые шумные записи статического кеша (примерный паттерн)
[FILTER]
    Name          grep
    Match         nginx.access
    Regex         uri  ^(?!.*\.(css|js|png|jpg|gif|svg|ico|mp4)$).+

# Нормализуем и удалим чувствительные ключи, если они встречаются
[FILTER]
    Name          modify
    Match         *
    Remove_Key    authorization
    Remove_Key    cookie

# Снижаем объем при бурстах: дропаут повторяющихся строк
[FILTER]
    Name          throttle
    Match         nginx.error
    Rate          200
    Window        5
    Print_Status  Off

# Преобразуем типы полей (числа и время) для ES
[FILTER]
    Name          parser
    Match         nginx.access
    Key_Name      log
    Parser        nginx_json
    Reserve_Data  On

grep с отрицательной проверкой сэкономит трафик и место в хранилище по доступам. throttle спасает при шторме идентичных ошибок: например, одно и то же сообщение миллион раз за минуту. Фильтр modify — быстрый способ убирать потенциально приватные поля.

Выход в Loki: минимальные и безопасные лейблы

В Loki критично держать низкую кардинальность labels. Не используйте динамичные поля (URI с query, user‑agent) в labels — их оставляем частью строки или JSON. Подробно про метки и пайплайны см. материал Лейблы и пайплайны в Loki: практический разбор.

# /etc/fluent-bit/outputs.conf
[OUTPUT]
    Name            loki
    Match           nginx.*
    Host            127.0.0.1
    Port            3100
    Labels          job=nginx, host=${HOSTNAME}, stream=access
    Line_Format     json
    Remove_Keys     ua,referer
    Auto_Kubernetes_Labels Off
    Http_User       loki_user
    Http_Passwd     loki_pass
    TLS             On
    TLS.Verify      On
    Workers         1
    Mem_Buf_Limit   16M
    Retry_Limit     False

[OUTPUT]
    Name            loki
    Match           sysd.*
    Host            127.0.0.1
    Port            3100
    Labels          job=systemd, host=${HOSTNAME}
    Line_Format     json
    TLS             On
    TLS.Verify      On
    Workers         1
    Mem_Buf_Limit   16M
    Retry_Limit     False

Line_Format json позволит передавать структуру, но помните: чем больше полей в записи, тем тяжелее индексация downstream. Метки держите минимальными и стабильными.

Настройки выходов в Loki и Elasticsearch и основные метрики

Выход в Elasticsearch (ELK): экономим на батчах и компрессии

Для ELK полезны логсташ‑совместимые индексы и gzip‑компрессия. Правильно выбирайте количество worker‑потоков: на маленьком VDS 1–2 обычно достаточно.

[OUTPUT]
    Name                es
    Match               nginx.*
    Host                127.0.0.1
    Port                9200
    HTTP_User           es_user
    HTTP_Passwd         es_pass
    Logstash_Format     On
    Logstash_Prefix     nginx
    Replace_Dots        On
    Time_Key            @timestamp
    Generate_ID         On
    Compress            gzip
    Workers             1
    Mem_Buf_Limit       32M
    Retry_Limit         False

[OUTPUT]
    Name                es
    Match               sysd.*
    Host                127.0.0.1
    Port                9200
    HTTP_User           es_user
    HTTP_Passwd         es_pass
    Logstash_Format     On
    Logstash_Prefix     systemd
    Replace_Dots        On
    Time_Key            @timestamp
    Generate_ID         On
    Compress            gzip
    Workers             1
    Mem_Buf_Limit       16M
    Retry_Limit         False

При необходимости прикрутите ingest‑pipeline в ES (например, для гео‑IP или user‑agent), но помните, что это удорожает обработку. Иногда выгоднее парсить заранее и хранить только необходимое.

Запуск, проверка и метрики

После редактирования конфигов проверьте синтаксис и запустите службу:

sudo fluent-bit -c /etc/fluent-bit/fluent-bit.conf -t
sudo systemctl enable --now fluent-bit
sudo systemctl status fluent-bit

Метрики доступны на локальном HTTP‑эндпоинте агента. Полезно смотреть чередование памяти и количество ретраев/дисковых чанков при тестовых отключениях сети.

Тонкая настройка под низкую нагрузку

Ниже — список практик, которые реально снижают потребление ресурсов на VDS, не теряя устойчивости.

  • Увеличьте Flush до 5–10 секунд, если latency не критична. Это уменьшит количество сетевых запросов.
  • Дисковый буфер обязателен: storage.path в [SERVICE], а в входах storage.type filesystem. Это предотвращает рост RAM при недоступности Loki/ES.
  • Ограничьте Mem_Buf_Limit у каждого выхода. Типичные значения на маленьком инстансе: 16–64 МБ.
  • Тщательно подберите поля в labels для Loki и индексы в ES. Избыточные метки = взрыв кардинальности и высокая нагрузка downstream.
  • Отбрасывайте шум через grep/throttle до отгрузки. Дешевле удалить строку локально, чем индексировать её в кластере.
  • Без нужды не используйте тяжёлые regex‑парсеры: лучше писать JSON на стороне приложения или веб‑сервера.
  • В tail держите небольшие чанки: Buffer_Chunk_Size 64k и Buffer_Max_Size 256k обычно достаточно.
  • Храните оффсеты tail в SQLite: DB + DB.Sync Full — меньше дублирования строк при рестартах.

Надёжность: что происходит при сбое сети

С включённым дисковым стореджем Fluent Bit делает следующее:

При временной недоступности Loki/ES исходящие чанки откладываются на диск, не заполняя память. После восстановления связи агент по ретраям дозагружает данные, сохраняя порядок внутри чанков.

Убедитесь, что диска хватит на типичный объём логов за время простоя и что на файловой системе включён мониторинг свободного места. Retry_Limit False полезен, если данные нельзя терять, но следите за накоплением «хвостов».

Производительность: ориентиры для маленькой машины

Схема вроде «Nginx JSON + journald, grep/throttle, 1–2 выхода» на инстансе с 1 vCPU и 1–2 ГБ RAM обычно укладывается:

  • CPU: 1–3% при скорости 1–2 тыс. строк/сек для Nginx JSON.
  • RAM: 20–60 МБ при Mem_Buf_Limit 16–32 МБ и включённом дисковом буфере.
  • Диск: десятки мегабайт в обычном режиме; при длительном простое сетевого приёмника — по фактическому объёму логов.

На пиках увеличивайте лимиты поэтапно и проверяйте метрики. Если downstream перегружен, агрессивнее фильтруйте шум и уменьшайте кардинальность меток.

Траблшутинг и практические советы

  • Пропуски строк после ротации: проверьте Rotate_Wait в tail и корректность логротейта для Nginx.
  • Дубли после рестартов: включите DB.Sync Full и убедитесь, что путь к базе tail на постоянном диске.
  • «Сыпется» парсер: временно поставьте Log_Level debug и посмотрите метрики parser на HTTP‑эндпоинте агента.
  • Большие сообщения от приложений: увеличьте Buffer_Max_Size у соответствующего входа и проверьте мультилайн‑правила.
  • ES отклоняет документы из‑за типов: настроьте Time_Key, Replace_Dots и фильтр parser для корректной типизации.
  • Высокая латентность приёмника: увеличьте Flush, включите компрессию (ES), уменьшите количество воркеров до устойчивого уровня.

Мини‑чеклист перед продом

  • JSON‑логи Nginx включены и валидны; мультилайн настроен под реальные трейсы.
  • Фильтры grep/modify/throttle режут шум и приватные поля.
  • Дисковый буфер включён, места достаточно; Mem_Buf_Limit проставлен у выходов.
  • Labels для Loki — только стабильные и малокардинальные.
  • ES: включена компрессия, корректные индексы и ключи времени.
  • Метрики агента доступны локально, есть базовый мониторинг RAM/CPU/диска.

Итого

Fluent Bit позволяет собрать логи на одном VDS и надёжно доставить их в Loki или ELK без лишней нагрузки. Секрет — отдавать предпочтение JSON‑логам, вовремя фильтровать шум, ограничивать память через Mem_Buf_Limit и всегда включать дисковый буфер. Такая конфигурация упрощает эксплуатацию и предсказуемо ведёт себя при сбоях сети, что особенно важно на небольших инстансах.

Поделиться статьей

Вам будет интересно

LVM snapshot и I/O: почему растёт задержка и как делать backup без сюрпризов OpenAI Статья написана AI (GPT 5)

LVM snapshot и I/O: почему растёт задержка и как делать backup без сюрпризов

LVM snapshot удобен для горячего backup, но почти всегда увеличивает нагрузку на диск. Объясняю, откуда берётся рост I/O latency, ...
PostgreSQL SSL/TLS: sslmode require и verify-full, root.crt, SNI и типовые ошибки проверки сертификата OpenAI Статья написана AI (GPT 5)

PostgreSQL SSL/TLS: sslmode require и verify-full, root.crt, SNI и типовые ошибки проверки сертификата

Пошагово настраиваем SSL/TLS в PostgreSQL и клиентах: разница между sslmode=require и verify-full, где хранится root.crt, как устр ...
DNS TTL: как работает время жизни записей, кэш резолверов и «распространение» изменений OpenAI Статья написана AI (GPT 5)

DNS TTL: как работает время жизни записей, кэш резолверов и «распространение» изменений

TTL в DNS — не «время распространения», а срок хранения ответа в кэше. Разберём, где живут кэши резолверов, ОС и приложений, почем ...