0 added
0 removed
Original
2026-01-01
Modified
2026-03-10
1
<ul><li><a>Предыстория</a></li>
1
<ul><li><a>Предыстория</a></li>
2
<li><a>Особенности Opensearch</a></li>
2
<li><a>Особенности Opensearch</a></li>
3
<li><a>Описание решения</a></li>
3
<li><a>Описание решения</a></li>
4
<li><a>SLA решения</a></li>
4
<li><a>SLA решения</a></li>
5
<li><a>Планы</a></li>
5
<li><a>Планы</a></li>
6
</ul><p><em>Привет! Я</em>-<em>Максим Чудинов, выпускник курса "</em><a><em>SRE практики и инструменты</em></a><em>". В конце обучения каждый студент курса выполнял итоговую работу, чтобы закрепить полученные знания. Я расскажу про свой проект "Кластер Opensearch для централизованного хранения логов".</em><em></em></p>
6
</ul><p><em>Привет! Я</em>-<em>Максим Чудинов, выпускник курса "</em><a><em>SRE практики и инструменты</em></a><em>". В конце обучения каждый студент курса выполнял итоговую работу, чтобы закрепить полученные знания. Я расскажу про свой проект "Кластер Opensearch для централизованного хранения логов".</em><em></em></p>
7
<h2><a></a>Предыстория</h2>
7
<h2><a></a>Предыстория</h2>
8
<p>Я инженер команды мониторинга в<a>Cloud.ru</a>. Одним из направлений мониторинга и работы нашей команды является обеспечение сбора логов с элементов инфраструктуры компании и их длительного хранения. На момент начала обучения на курсе, хранение логов в компании осуществлялось на 18 кластерах Elasticsearch, о которых я рассказывал<a>на Big Monitoring Meetup 9</a>. Все кластеры работали на устаревшей версии 7.9, а перейти на более свежую версию, по сумме обстоятельств, мы не могли. Поэтому приняли решение перейти с Elasticsearch на Opensearch.</p>
8
<p>Я инженер команды мониторинга в<a>Cloud.ru</a>. Одним из направлений мониторинга и работы нашей команды является обеспечение сбора логов с элементов инфраструктуры компании и их длительного хранения. На момент начала обучения на курсе, хранение логов в компании осуществлялось на 18 кластерах Elasticsearch, о которых я рассказывал<a>на Big Monitoring Meetup 9</a>. Все кластеры работали на устаревшей версии 7.9, а перейти на более свежую версию, по сумме обстоятельств, мы не могли. Поэтому приняли решение перейти с Elasticsearch на Opensearch.</p>
9
<p>Кластеров у нас много, а в перспективе будет еще больше. Запускать новые и расширять существующие нужно быстро. В рамках учебного проекта я разработал решение по автоматизации развертывания стека Opensearch на виртуальных машинах с Ubuntu 20.04.</p>
9
<p>Кластеров у нас много, а в перспективе будет еще больше. Запускать новые и расширять существующие нужно быстро. В рамках учебного проекта я разработал решение по автоматизации развертывания стека Opensearch на виртуальных машинах с Ubuntu 20.04.</p>
10
<p>При разработке нужно было учесть важное условие - описание конфигурации всех кластеров должно храниться в одном месте, чтобы можно было разворачивать/обновлять/вносить изменения коммитом в одном репозитории.</p>
10
<p>При разработке нужно было учесть важное условие - описание конфигурации всех кластеров должно храниться в одном месте, чтобы можно было разворачивать/обновлять/вносить изменения коммитом в одном репозитории.</p>
11
<p>Поскольку Opensearch - это форк Elasticsearch 7.10, особых отличий в работе кластера нет. Для проведения теста можно было поднять однонодовый кластер, но я сразу использовал рекомендованную производителем конфигурацию - от трёх нод.</p>
11
<p>Поскольку Opensearch - это форк Elasticsearch 7.10, особых отличий в работе кластера нет. Для проведения теста можно было поднять однонодовый кластер, но я сразу использовал рекомендованную производителем конфигурацию - от трёх нод.</p>
12
<p>Ноды это хранилище данных и основа стека. Также частью стека являются фронтенд - для удобного поиска по индексами, и коллекторы - при необходимости предобработки и работы в распределенной инфраструктуре.</p>
12
<p>Ноды это хранилище данных и основа стека. Также частью стека являются фронтенд - для удобного поиска по индексами, и коллекторы - при необходимости предобработки и работы в распределенной инфраструктуре.</p>
13
<a></a><p>События из журналов систем и оборудования отправляются в кластер и складываются в индексы. Индексы имеют один основной шард и от нуля до нескольких его реплик. Количество реплик зависит от количества нод. Кластер сам распределяет шарды таким образом, чтобы на одной ноде в один момент времени не находились основной шард и его реплика. За счет этого обеспечивается надежность хранения, а шардирование ускоряет выполнение поисковых запросов.</p>
13
<a></a><p>События из журналов систем и оборудования отправляются в кластер и складываются в индексы. Индексы имеют один основной шард и от нуля до нескольких его реплик. Количество реплик зависит от количества нод. Кластер сам распределяет шарды таким образом, чтобы на одной ноде в один момент времени не находились основной шард и его реплика. За счет этого обеспечивается надежность хранения, а шардирование ускоряет выполнение поисковых запросов.</p>
14
<h2><a></a>Описание решения</h2>
14
<h2><a></a>Описание решения</h2>
15
<p>Чтобы развернуть 18 однотипных кластеров сейчас, N-е количество в будущем и поддерживать их дальше, я решил использовать Ansible. Для нод написал роль opensearch, для фронтенда роль opensearch_dashboards. Также подготовил описание кластеров<a>в соседнем репозитории</a>.</p>
15
<p>Чтобы развернуть 18 однотипных кластеров сейчас, N-е количество в будущем и поддерживать их дальше, я решил использовать Ansible. Для нод написал роль opensearch, для фронтенда роль opensearch_dashboards. Также подготовил описание кластеров<a>в соседнем репозитории</a>.</p>
16
<a></a><p>В ролях предусмотрел тестирование с помощью molecule. При этом разворачиваются три ноды, кластер инициализируется дефолтными параметрами, проверяется возможность авторизации и возврат статуса.</p>
16
<a></a><p>В ролях предусмотрел тестирование с помощью molecule. При этом разворачиваются три ноды, кластер инициализируется дефолтными параметрами, проверяется возможность авторизации и возврат статуса.</p>
17
<p>Аналогично для фронтенда: всё запускается в контейнерах, а если не выполнять шаг destroy, то можно получить полноценную инсталляцию, походить по интерфейсу и попробовать настройки.</p>
17
<p>Аналогично для фронтенда: всё запускается в контейнерах, а если не выполнять шаг destroy, то можно получить полноценную инсталляцию, походить по интерфейсу и попробовать настройки.</p>
18
<p>Из-за отсутствия DNS в некоторых сегментах инфраструктуры в инвентаре мы используем параметр ansible_host с IP-адресом. С molecule в контейнерах такой возможности нет - адреса выдаются произвольно и сетевой доступ осуществляется по именам. А мне для конфигурации каждой ноды нужно было собрать массив IP-адресов всех нод.</p>
18
<p>Из-за отсутствия DNS в некоторых сегментах инфраструктуры в инвентаре мы используем параметр ansible_host с IP-адресом. С molecule в контейнерах такой возможности нет - адреса выдаются произвольно и сетевой доступ осуществляется по именам. А мне для конфигурации каждой ноды нужно было собрать массив IP-адресов всех нод.</p>
19
<p>Чтобы роли работали и в тесте, и на виртуальных машинах, я написал код с формированием списка хостов в зависимости от значения ansible_host. Нативными командами ansible реализовать не получилось, поэтому я написал код на jinja2.</p>
19
<p>Чтобы роли работали и в тесте, и на виртуальных машинах, я написал код с формированием списка хостов в зависимости от значения ansible_host. Нативными командами ansible реализовать не получилось, поэтому я написал код на jinja2.</p>
20
<a></a><p>Основой для применения ролей служит инвентарь - он описан в файле opensearch_cluster/inventory/hosts и содержит только имена и адреса целевых машин. Сами роли применяются к группам, описание которых можно увидеть в файле opensearch_cluster/inventory/logsearch.yml.</p>
20
<a></a><p>Основой для применения ролей служит инвентарь - он описан в файле opensearch_cluster/inventory/hosts и содержит только имена и адреса целевых машин. Сами роли применяются к группам, описание которых можно увидеть в файле opensearch_cluster/inventory/logsearch.yml.</p>
21
<a></a><p>Соответственно, для нод это группа logsearch_node, для фронта logsearch_frontend. И группа logsearch_logstash заложена на перспективу использования инвентаря для коллектора logstash.</p>
21
<a></a><p>Соответственно, для нод это группа logsearch_node, для фронта logsearch_frontend. И группа logsearch_logstash заложена на перспективу использования инвентаря для коллектора logstash.</p>
22
<p>Общие сертификаты безопасности я вынес в групповые переменные и в будущем планирую перенести их в корпоративный Vault.</p>
22
<p>Общие сертификаты безопасности я вынес в групповые переменные и в будущем планирую перенести их в корпоративный Vault.</p>
23
<a></a><p>В отдельном файле в словаре clusters описаны параметры каждого кластера. Поле type для возможности развертывания как opensearch, так и elasticsearch. Сертификаты берутся из общих переменных, при этом для каждого кластера можно переопределить свой. Куски для конфигурационных файлов internal_users.yml и roles_mapping.yml описаны в виде plain text.</p>
23
<a></a><p>В отдельном файле в словаре clusters описаны параметры каждого кластера. Поле type для возможности развертывания как opensearch, так и elasticsearch. Сертификаты берутся из общих переменных, при этом для каждого кластера можно переопределить свой. Куски для конфигурационных файлов internal_users.yml и roles_mapping.yml описаны в виде plain text.</p>
24
<a></a><p>Все зависимости я свёл в requirements.yml, а средствами Gitlab CI/CD настроил выполнение плейбука при коммите изменений репозитория в основную ветку.</p>
24
<a></a><p>Все зависимости я свёл в requirements.yml, а средствами Gitlab CI/CD настроил выполнение плейбука при коммите изменений репозитория в основную ветку.</p>
25
<h2><a></a>SLA решения</h2>
25
<h2><a></a>SLA решения</h2>
26
<p>Архитекторы Cloud.ru определили для кластера SLA в 97%. Для себя я установил SLO в 98%. С помощью ресурса uptime.is проценты превращаются в допустимые периоды простоя</p>
26
<p>Архитекторы Cloud.ru определили для кластера SLA в 97%. Для себя я установил SLO в 98%. С помощью ресурса uptime.is проценты превращаются в допустимые периоды простоя</p>
27
<p><strong> Daily:</strong>28m 48s</p>
27
<p><strong> Daily:</strong>28m 48s</p>
28
<p><strong> Weekly:</strong>3h 21m 36s</p>
28
<p><strong> Weekly:</strong>3h 21m 36s</p>
29
<p><strong> Monthly:</strong>14h 29m 23s</p>
29
<p><strong> Monthly:</strong>14h 29m 23s</p>
30
<p><strong> Quarterly:</strong>1d 19h 28m 8.8s</p>
30
<p><strong> Quarterly:</strong>1d 19h 28m 8.8s</p>
31
<p><strong> Yearly:</strong>7d 5h 52m 35s</p>
31
<p><strong> Yearly:</strong>7d 5h 52m 35s</p>
32
<p>По факту Opensearch очень стабильный готовый продукт. Вывести из строя может только падение операционной системы или несоблюдение рекомендаций разработчиков.</p>
32
<p>По факту Opensearch очень стабильный готовый продукт. Вывести из строя может только падение операционной системы или несоблюдение рекомендаций разработчиков.</p>
33
<p>Но эта стабильность не отменяет обязательного мониторинга. Я определил несколько ключевых метрик (SLI):</p>
33
<p>Но эта стабильность не отменяет обязательного мониторинга. Я определил несколько ключевых метрик (SLI):</p>
34
<ul><li>Health status - доступность кластера и его способность принимать новые данные;</li>
34
<ul><li>Health status - доступность кластера и его способность принимать новые данные;</li>
35
<li>Indexing rate - скорость поступления событий;</li>
35
<li>Indexing rate - скорость поступления событий;</li>
36
<li>Indexing latency - задержка записи событий;</li>
36
<li>Indexing latency - задержка записи событий;</li>
37
<li>Failed get operations - ошибки поисковых запросов;</li>
37
<li>Failed get operations - ошибки поисковых запросов;</li>
38
<li>Storage utilization - величина использования хранилища кластера;</li>
38
<li>Storage utilization - величина использования хранилища кластера;</li>
39
<li>Product Index size - размер индексов каждого продукта источника;</li>
39
<li>Product Index size - размер индексов каждого продукта источника;</li>
40
<li>Estimated time to 15% free space - прогнозное время до достижения 15% остатка хранилища.</li>
40
<li>Estimated time to 15% free space - прогнозное время до достижения 15% остатка хранилища.</li>
41
</ul><p>Для сбора метрик использовал Zabbix и немного доработанный<a>шаблон Elasticsearch</a>, а визуализацию настроил средствами Grafana.</p>
41
</ul><p>Для сбора метрик использовал Zabbix и немного доработанный<a>шаблон Elasticsearch</a>, а визуализацию настроил средствами Grafana.</p>
42
<p>С помощью шаблонных наименований хостов (naming convention) получилось сделать динамический шаблон, который отображает SLI по каждому кластеру. С помощью метрики Estimated time организовал capacity management.</p>
42
<p>С помощью шаблонных наименований хостов (naming convention) получилось сделать динамический шаблон, который отображает SLI по каждому кластеру. С помощью метрики Estimated time организовал capacity management.</p>
43
<a></a><p>По размерам индексов продуктов сделал фрейм с Top 10 и графиками изменения. Продукты - это системы или комплексы, например, корпоративный кластер Confluence или Gitlab, или кластер K8s для облачных сервисов. Продукт включает в себя множество источников событий, и каждый в любой момент может значительно увеличить количество генерируемых событий.</p>
43
<a></a><p>По размерам индексов продуктов сделал фрейм с Top 10 и графиками изменения. Продукты - это системы или комплексы, например, корпоративный кластер Confluence или Gitlab, или кластер K8s для облачных сервисов. Продукт включает в себя множество источников событий, и каждый в любой момент может значительно увеличить количество генерируемых событий.</p>
44
<a></a><p>Мы не применяем жёстких ограничений и не фильтруем события - так можно потерять действительно важные данные. Что отправить в хранилище - решает команда каждого продукта.</p>
44
<a></a><p>Мы не применяем жёстких ограничений и не фильтруем события - так можно потерять действительно важные данные. Что отправить в хранилище - решает команда каждого продукта.</p>
45
<p>Поскольку хранилище не бесконечное, важно отслеживать, какой продукт и сколько места занимает. Для этого мы создали Logging budget: теперь события от каждого продукта попадают в отдельный индекс и можно сразу увидеть, сколько места в байтах они занимают. При резком росте значения команда-владелец разбирается в причинах.</p>
45
<p>Поскольку хранилище не бесконечное, важно отслеживать, какой продукт и сколько места занимает. Для этого мы создали Logging budget: теперь события от каждого продукта попадают в отдельный индекс и можно сразу увидеть, сколько места в байтах они занимают. При резком росте значения команда-владелец разбирается в причинах.</p>
46
<h2><a></a>Планы</h2>
46
<h2><a></a>Планы</h2>
47
<p>Я планирую развивать проект дальше: перенести все секреты и сертификаты в Vault, разработать и подключить роль logstash, собрать логи всех элементов проекта в один индекс и настроить предупреждения по аварийным событиям. Также предстоит договориться с командами разработки внутренних продуктов о формате событий приложений (contract), чтобы избежать ошибок несовпадения типов данных при индексировании.</p>
47
<p>Я планирую развивать проект дальше: перенести все секреты и сертификаты в Vault, разработать и подключить роль logstash, собрать логи всех элементов проекта в один индекс и настроить предупреждения по аварийным событиям. Также предстоит договориться с командами разработки внутренних продуктов о формате событий приложений (contract), чтобы избежать ошибок несовпадения типов данных при индексировании.</p>
48
<p><em>Хотите знать об SRE больше? Добро пожаловать на</em><a><em>специализированный курс в Otus</em></a><em>!</em><em></em></p>
48
<p><em>Хотите знать об SRE больше? Добро пожаловать на</em><a><em>специализированный курс в Otus</em></a><em>!</em><em></em></p>
49
49