Загрузка данных
Шаг 1. Добавить Fluent Bit в compose
Создать новую директорию:
fluent-bit/
├── fluent-bit.conf
└── parsers.conf
Добавить сервис:
fluent-bit-ma:
container_name: fluent-bit-ma
hostname: fluent-bit-ma
image: it-infradev.repository.avp.ru:443/shared/fluent-bit:<version>
restart: unless-stopped
depends_on:
- django-ma-app
- apache-ma-rproxy
volumes:
- ./fluent-bit:/fluent-bit/etc:ro
# Docker logs
- /var/lib/docker/containers:/var/lib/docker/containers:ro
# Apache logs
- ./logs/apache2:/logs/apache2:ro
# Если понадобится читать Django из файлов
#- ./logs/django:/logs/django:ro
# База состояния tail
- ./fluent-bit-state:/var/fluent-bit
environment:
ELK_ENV: {{ branch }}
networks:
- MailArchive
Шаг 2. Настроить INPUT
Docker
[INPUT]
Name tail
Path /var/lib/docker/containers/*/*-json.log
Parser docker
Tag docker
DB /var/fluent-bit/docker.db
Read_from_Head On
Это автоматически соберет
Django
Celery Worker
Celery Beat
Kerberos
Redis
Exporters
Apache access
[INPUT]
Name tail
Path /logs/apache2/mailarchive_access.log
Parser apache2
Tag apache.access
DB /var/fluent-bit/apache-access.db
Apache error
[INPUT]
Name tail
Path /logs/apache2/mailarchive_error.log
Tag apache.error
DB /var/fluent-bit/apache-error.db
Шаг 3. Парсеры
Подключить
[SERVICE]
Parsers_File parsers.conf
И создать минимум два парсера
[PARSER]
Name docker
Format json
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%LZ
Time_Keep On
и
[PARSER]
Name apache2
Format regex
Regex ^(?<host>[^ ]*) [^ ]* [^ ]* \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>\d{3}) (?<size>\d+|-)$
Time_Key time
Time_Format %d/%b/%Y:%H:%M:%S %z
Шаг 4. Добавить полезные поля
Например
[FILTER]
Name modify
Match *
Add application mailarchive
Add environment {{ branch }}
Тогда каждая запись будет содержать
{
"application": "mailarchive",
"environment": "dev"
}
или
{
"application": "mailarchive",
"environment": "stage"
}
Шаг 5. Отправка в OpenSearch
Я бы использовал Logstash Format.
[OUTPUT]
Name opensearch
Match *
Host {{ elk_host }}
Port 9200
HTTP_User {{ elk_user }}
HTTP_Passwd {{ elk_password }}
tls on
tls.verify off
Logstash_Format On
Logstash_Prefix mailarchive-{{ branch }}
Suppress_Type_Name On
Получатся индексы
mailarchive-dev-2026.08.05
mailarchive-stage-2026.08.05
mailarchive-prod-2026.08.05
Шаг 6. Проверить работу
Запустить
docker compose up -d fluent-bit-ma
Посмотреть
docker logs -f fluent-bit-ma
Там должны появиться сообщения о начале чтения логов и успешной отправке данных.
Шаг 7. Проверить OpenSearch
Убедиться, что появились индексы
mailarchive-dev-*
или
mailarchive-stage-*
и что документы содержат поля вроде:
application
environment
log
container_name (если добавишь обогащение)
@timestamp
Шаг 8. Что можно улучшить позже
После того как базовая схема заработает, можно добавить:
фильтрацию шумных контейнеров (redis, node-exporter, cadvisor и т.п.), чтобы не засорять индексы;
раздельные индексы для apache.access, apache.error и логов приложений, если это потребуется для аналитики;
обогащение Docker-логов метаданными контейнера (имя сервиса, образ, compose-проект) через Docker API или дополнительные фильтры;
парсинг Django-логов в структурированные поля, если они имеют стабильный формат.
Итоговая архитектура
Docker JSON logs
+--------------------------------+
| Django |
| Celery Worker |
| Celery Beat |
| Kerberos |
+--------------------------------+
│
│
▼
Fluent Bit
▲
│
Apache access/error log files
│
▼
OpenSearch
│
▼
Kibana
Для твоего текущего проекта это выглядит наиболее практичным: минимальные изменения в существующих контейнерах, сохранение файловых логов Apache для локальной диагностики и единая отправка всех журналов в OpenSearch.
А где мне настраивать INPUT?
Просто все блоками кидать в конфиг Fluentbit?
Да, именно так. Fluent Bit устроен довольно просто: весь пайплайн описывается в конфигурационных файлах.
Обычно делают так:
fluent-bit/
├── fluent-bit.conf
├── parsers.conf
└── scripts/
Основной файл — fluent-bit.conf. В нем просто последовательно идут секции:
[SERVICE]
...
[INPUT]
...
[INPUT]
...
[FILTER]
...
[FILTER]
...
[OUTPUT]
...
То есть ты действительно просто добавляешь блоки один за другим.
Например, для твоего проекта fluent-bit.conf на первом этапе мог бы выглядеть так:
[SERVICE]
Flush 5
Daemon Off
Log_Level info
Parsers_File parsers.conf
#
# Docker контейнеры
#
[INPUT]
Name tail
Path /var/lib/docker/containers/*/*-json.log
Parser docker
Tag docker
DB /var/fluent-bit/docker.db
Read_from_Head On
#
# Apache access.log
#
[INPUT]
Name tail
Path /logs/apache2/mailarchive_access.log
Parser apache2
Tag apache.access
DB /var/fluent-bit/apache-access.db
#
# Apache error.log
#
[INPUT]
Name tail
Path /logs/apache2/mailarchive_error.log
Tag apache.error
DB /var/fluent-bit/apache-error.db
#
# Добавляем общие поля
#
[FILTER]
Name modify
Match *
Add application mailarchive
Add environment {{ branch }}
#
# Отправляем в ELK
#
[OUTPUT]
Name opensearch
Match *
Host {{ elk_host }}
Port 9200
HTTP_User {{ elk_user }}
HTTP_Passwd {{ elk_password }}
tls on
tls.verify off
Logstash_Format On
Logstash_Prefix mailarchive-{{ branch }}
Suppress_Type_Name On
А parsers.conf будет отдельным файлом, например:
[PARSER]
Name docker
Format json
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%LZ
Time_Keep On
[PARSER]
Name apache2
Format regex
...
Я бы предложил сделать в несколько этапов
Не пытаться сразу добавить FILTER, Lua, парсинг и прочее.
Этап 1 (15 минут):
один INPUT для Docker;
один INPUT для Apache access;
один INPUT для Apache error;
один OUTPUT в OpenSearch.
Проверить, что логи вообще появились в OpenSearch.
Этап 2:
добавить парсеры;
добавить поля environment, application;
при необходимости исключить лишние контейнеры (redis, cadvisor, node-exporter).
Так гораздо проще отлаживать: если что-то не работает, сразу понятно, проблема в чтении логов, парсинге или отправке.