Писать, собирать, агрегировать и сохранять логи для последующего анализа важно: это наиболее подробное представление того, как работает система.

Логи можно собирать и отправлять в централизованную систему по-разному, например используя библиотеки в самом приложении или сторонние агенты вроде Filebeat, Fluent Bit, Vector. Есть множество систем хранения вроде Elasticsearch, Loki, Splunk, файлы на диске или объекты в S3.

Мы в М2 тоже занимаемся этим вопросом и постоянно ищем схемы и инструменты, помогающие улучшать централизованную систему логирования. Я, как инженер развития инфраструктуры, непосредственно принимаю в этом участие. В статье хотел бы поговорить об этапе агрегации и поделиться нашими наработками.

Агрегация

Агрегация, или агрегирование (лат. aggregatio — присоединение), — процесс объединения элементов в одну систему.

Как только у нас появляется множество разнотипных источников логов, нужно производить различные преобразования данных: фильтрацию, объединение по определенным признакам, парсинг и т. д. Все это принято выносить в слой агрегации. И если в самом простом случае можно обойтись такой схемой:

то в более сложных вариантах действовать нужно так:

А при более большом объеме сообщений и так:

В какой-то момент мы пришли в нашей системе к схеме, подобной третьей, но позже встал вопрос, как гибко управлять уровнем агрегации и масштабировать его.

Управление слоем агрегации

Сейчас существует множество агрегаторов логов. Наиболее популярные, на мой взгляд, — Logstash, Fluentd, Vector. Так как изначально мы использовали Elastic Stack, логично было сосредоточиться именно на Logstash. Инстансы Logstash разворачивались в Kubernetes там, где и генерировалась основная масса логов. Для развертывания мы использовали официальный Helm chart.

Так выглядела схема работы
Так выглядела схема работы

С подов собирались логи и отправлялись в Kafka, затем инстансы Logstash, запущенные как StatefulSet, перекладывали логи в кластер Elasticsearch. Каждому namespace соответствовал свой топик в Kafka и индекс в Elasticsearch.

С ростом числа приложений стало понятно, что одним пулом Logstash не обойтись — нужно создавать отдельный пул под каждый топик и масштабировать их в зависимости от потока сообщений. Все это выливается в большое число helm-релизов с во многом дублирующейся конфигурацией и увеличением времени обновления.

Хотелось сделать все так, чтобы при создании нового namespace было достаточно указать несколько лейблов, и пул Logstash запускался автоматически. Так мы решили создать свой logstash-operator, т. к. ничего готового найти не удалось. Мы думали о варианте с logging-operator от Banzai Cloud, но он не вполне нам подходил.

Путь эволюции оказался довольно длинным и не завершился созданием оператора. О нем я расскажу подробнее в отдельной статье.

Logstash operator

Оператор управляется посредством пары CRD и ряда лейблов и аннотаций для namespace.

Общая схема оператора
Общая схема оператора

Чтобы начать работу с оператором, его нужно установить с помощью Kustomize или Helm Chart. Для корректной работы admission webhook требуется cert-manager. 

Далее вам потребуется создать ресурс M2Logstash. Он определяет основные параметры запуска инстансов Logstash: образ, ресурсы, опции запуска JVM. 

Затем — указать конфигурацию цепочек input, filter, output через ресурс M2LogstashPipeline. Помимо Kafka и Elasticsearch есть еще несколько вариантов. 

После того, как CRD установлены, можно создать пул Logstash. Для этого достаточно на нужных namespace установить label “m2/logger=true”. Пулы появятся в том namespace, где создан M2Logstash. Число реплик можно регулировать с помощью аннотации "logger.m2.ru/logstash-replicas".

Если для подключения требуются креды, нужно заранее создать Secret с их значениями, а название указать в M2LogstashPipeline. Подробней можно прочитать в документации.

Ряд настроек input/output вычисляются исходя из названия namespace, к которому привязывается пул Logstash. Это может быть Kafka topic, Elasticsearch index, S3 bucket.

Таким образом, для конфигурирования необходимо только два манифеста с M2Logstash, M2LogstashPipeline, а также лейблы. Вся остальная работа возлагается на оператор.

Подробности по спецификации CRD и лейблам можно найти в документации.

Сфера применения

Изначально мы задумали оператор как средство агрегации логов, генерируемых подами в кластере kubernetes. Но ничего не мешает использовать его для логов с других сервисов и виртуальных машин. 

После внедрения, оператор хорошо себя показал, поэтому мы решили опубликовать его на Github. Так он сможет приносить пользу и в других компаниях. Важно отметить, что задача сбора логов должна решаться отдельно, например при помощи Filebeat, Fluent-bit, Vector.

Ограничения и планы по развитию

Сейчас нет привязки M2LogstashPipeline к M2Logstash, поэтому они могут использоваться в единственном экземпляре. 

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

  1. Сделать привязку M2LogstashPipeline к M2Logstash, чтобы можно было использовать несколько pipeline в одном Logstash. А также использовать несколько групп пулов с разным pipeline.

  2. Добавить возможность автоскейлинга реплик внутри StatefulSet.

  3. Добавить больше вариантов input/output.

  4. Возможность создать Servicemonitor для добавления в Prometheus.

Буду рад другим идеям и предложениям по улучшению. Ссылка на репозиторий.

Комментарии (0)