Fluent Bit или легко о логах… часть 1.

В современном мире, меня, больше всего огорчает бесконтрольное использование памяти или вообще халатное к ней отношение. Я вырос в то время когда за каждый килобайт программисты боролись. А сейчас для многих 4 Gb это ерунда. Но сегодня речь не о разработке и памяти, а о логах. Тогда при чем тут память? А память тут вот при чем… В текущих реалиях для сбора, транспортировки и парсинга логов у нас есть следующие популярные инструменты: Logstash, Fluentd, Fluent Bit, Vector. Пожалуй первый самый популярный, так как входит в классический стек ELK ( Elasticsearch, Logstash, Kibana ). Но я сегодня хотел бы остановиться именно на Fluent Bit. Почему? Потому что: 1. Он требует всего 450 кб памяти для работы. 2. Он написан на С. 3. Он прекрасно работает в Docker контейнерах и самое главное в Kubernetes средах. 4. Конфигурационные файлы могут быть как в виде обычного текста так и в yaml формате. 5. У Docker есть встроенный драйвер Fluentd который сразу может писать в Fluent Bit. Это же прекрасно! Но, я хотел бы рассказать просто о сложном по этому начнем с простого, как установить и работать с ним.

Установка хорошо описана в официальной документации https://docs.fluentbit.io/manual/installation/linux/ubuntu по этому описывать её не имеет смысла, я же буду рассматривать в данном примере Docker образ и работу в Docker. Вы же можете установить его на голую систему с тем же конфигурационными файлами что бы получить тоже самое но на «железе». И так, если вы хотите так же как и я развернуть все это в Docker, то идем и читаем конфигурацию запуска и смотрим образ: https://hub.docker.com/r/fluent/fluent-bit/, все понятно, я сразу буду делать docker-compose.yml что бы в будущем добавить к нему Elasticsearch, Grafana или Kibana. По этому создаем следующую структуру файлов и каталогов:

.
├── conf
│   ├── fluent-bit.conf
│   └── parsers.conf
└── docker-compose.yml

1 directory, 3 files

Что это за файлы и для чего они? В каталоге conf я расположил 2 конфигурационных файла для самого Fluent Bit, основной файл конфигурации fluent-bit.conf и parsers.conf где будут храниться регулярные выражения или другие настройки парсеров. В корне каталога расположен docker-compose. Далее редактируем docker-compose.yml

# vim docker-compose.yml

version: '2.8'
services:

  fluent-bit:
    image: fluent/fluent-bit
    container_name: fluent-bit
    volumes:
      - ./conf:/fluent-bit/etc
      - /var/log:/var/log

Немного поясню, в секции volumes я «пробрасываю» локальные каталоги в docker, если вы устанавливаете fluent bit на голую машину, то файлы будут располагаться в каталоге /etc/fluent-bit. Но содержание будет тем же. Теперь сконфигурируем fluent bit для запуска, основной файл конфигурации fluent-bit.conf (все параметры файла, хорошо описаны в документации, не ленитесь её читать.):

# vim conf/fluent-bit.conf

[SERVICE]
    flush            1
    log_Level        info
    daemon           off
    parsers_File     parsers.conf
    http_server      on
    http_listen      127.0.0.1
    http_port        2020
    storage.metrics  on

[INPUT]

    # Указываем что нам необходимо следить за файлом.
    Name tail
    Path /var/log/fluent-bit.log

[FILTER]

    # Говорим что нам необходимо обратиться к парсеру, парсить все что приходит в файл.
    # для этого используем имя парсера yakunin который объявляется в файле parsers.conf
    Name parser
    Match *
    Key_Name log
    Parser yakunin 

[OUTPUT]

    # В данный момент все что будет после парсинга, нам необходимо выводить на экран.
    name stdout
    match *

Далее создадим и наполним наш файл парсинга, fluent bit прекрасно работает с регулярными выражениями без применения каких либо сторонних плагинов и прочего, просто из коробки. По этому создаем:

# vim conf/parsers.conf

[PARSER]

    # Указываем имя парсера, по нему идет совпадение из основного файла конфигурации в
    # директиве Parser
    Name   yakunin

    # Говорим что формат парсинга это регулярные выражения.
    # Входящие сообщения лога будут выглядеть так:
    # Name: Yakunin V. Vasily Age: 42 City: Volgograd
    Format regex
    Regex  /Name:\s(?<name>\w+.*)Age:.(?<age>\d+)\sCity:\s(?<city>\w+)\s+IP:\s+( <ip>\d+.\d+.\d+.\d+)/

    # Говорим что группа age, должна быть как целое а не как текст.
    Types age:integer

Все готово для запуска, можно запускать и смотреть:

# docker compose up

[+] Running 2/2
 ⠿ Network efk_default  Created                                                     0.1s
 ⠿ Container fluent-bit  Created                                                     0.1s
Attaching to fluent-bit
fluent-bit  | Fluent Bit v1.9.3
fluent-bit  | * Copyright (C) 2015-2022 The Fluent Bit Authors
fluent-bit  | * Fluent Bit is a CNCF sub-project under the umbrella of Fluentd
fluent-bit  | * https://fluentbit.io
fluent-bit  | 
fluent-bit  | [2022/05/17 13:16:23] [ info] [fluent bit] version=1.9.3, commit=9eb4996b7d, pid=1
fluent-bit  | [2022/05/17 13:16:23] [ info] [storage] version=1.2.0, type=memory-only, sync=normal, checksum=disabled, max_chunks_up=128
fluent-bit  | [2022/05/17 13:16:23] [ info] [cmetrics] version=0.3.1
fluent-bit  | [2022/05/17 13:16:23] [ info] [output:stdout:stdout.0] worker #0 started
fluent-bit  | [2022/05/17 13:16:23] [ info] [http_server] listen iface=127.0.0.1 tcp_port=2020
fluent-bit  | [2022/05/17 13:16:23] [ info] [sp] stream processor started
fluent-bit  | [2022/05/17 13:16:23] [ info] [input:tail:tail.0] inotify_fs_add(): inode=1835058 watch_fd=1 name=/var/log/fluent-bit.log

Как видим все создалось и запустилось, в последней строке видим следующее: fluent-bit | [2022/05/17 13:16:23] [ info] [input:tail:tail.0] inotify_fs_add(): inode=1835058 watch_fd=1 name=/var/log/fluent-bit.log что говорит о том, что файл /var/log/fluent-bit.log взят на слежение и будет обработан как только туда что-то добавится. Ещё один плюс fluent bit в том, что выходные данные он предоставляет в формате json. А это просто прекрасно. И так добавим запись:

# echo "Name: Yakunin V. Vasily Age: 42 City: Volgograd IP: 10.10.10.10" >> /var/log/fluent-bit.log

И смотрим что получилось:

fluent-bit  | [2022/05/17 13:16:23] [ info] [sp] stream processor started
fluent-bit  | [2022/05/17 13:16:23] [ info] [input:tail:tail.0] inotify_fs_add(): inode=1835058 watch_fd=1 name=/var/log/fluent-bit.log
fluent-bit  | [0] tail.0: [1652793708.089137491, {"name"=>"Yakunin V. Vasily ", "age"=>42, "city"=>"Volgograd", "ip"=>"10.10.10.10"}]

В последнем сообщении из вывода на экран мы видим что строка попавшая в файл, обработалась и вывелась, так как вывод мы указали как stdout, соответственно мы можем указать вывод например в Elasticsearch, а из него уже сможем визуализировать это в Grafana или в Kibana. Таким образом, можно парсить любые логи, любых программ. Так же fluent bit умеет фильтровать уже полученный результат скажем аналогично grep. Например, ниже приведен боевой конфиг который парсит логи sshd и если человеку или злоумышленнику не удалось авторизоваться, лог записывается и передается на сервер Elasticsearch.

[SERVICE]
    flush            1
    log_Level        info
    daemon           off
    parsers_File     parsers.conf
    http_server      on
    http_listen      127.0.0.1
    http_port        2020
    storage.metrics  on

[INPUT]
    name tail
    path /var/log/auth.log

    # Если у вас не один файл который обрабатывается, вы можете использовать
    # теги, что бы помечать выход и по тегам обрабатывать дальше, в данном
    # случае, мы обрабатываем все из файла и присваиваем этим данным тег gitlab.sshd.auth
    tag gitlab.sshd.auth

[FILTER]
    name parser
    match gitlab.sshd.auth
    key_name log
    parser gitlab.sshd.parser

[FILTER]

    # Из всех полученных данных после парсинга на интересует только те, которые
    # содержат слово preauth. По этому грепаем это слово из полученных данных и
    # передаем дальше.
    name   grep
    match  gitlab.sshd.auth
    regex  messages preauth


[OUTPUT]

    # В данном случае мы говорим что будем использовать в качестве выхода Elasticsearch
    name es
    match gitlab.sshd.auth
    host 127.0.0.1
    port 9200
    replace_dots on
    index gitlab.sshd.auth
    Retry_Limit False
    Suppress_Type_Name On

На github можно найти не мало уже готовых парсеров под любые нужды в том числе и то что идет в комплекте с fluent bit. https://github.com/fluent/fluent-bit/blob/master/conf/parsers.conf Вот собственно и все. Каков итог?

  1. Мы имеем быстрый инструмент, который может отдавать данные в различные источники.
  2. Можно писать собственные регулярные выражения под любые типы логов, можем вычленять из результатов уже только то, что нам необходимо, а не писать все в базу.
  3. Интуитивно понятная настройка.
  4. Отличная документация.
  5. Интеграция из коробки с K8s и Docker.
  6. Выход по умолчанию в JSON.

В следующей статье, будем отдавать данные в Elasticsearch и визуализировать это в Kibana. Удачного парсинга друзья.

1 комментарий к “Fluent Bit или легко о логах… часть 1.

  1. Спасибо за статью. Вот заинтересовало , а где тег log был объявлен? как фильтр поймет , что нужно отдавать на парсинг?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *