Русский
Русский
English
Статистика
Реклама

Kibana

Новые возможности анализа табличных данных с алгоритмами машинного обучения в Elastic

11.03.2021 12:11:09 | Автор: admin


Elastic stack, также известный как ELK Stack (аббревиатура из программных компонентов: Elasticsearch, Kibana и Logstash), это платформа построения озера данных с возможностью аналитики по ним в реальном масштабе времени. В настоящее время широко применяется для обеспечения информационной безопасности, мониторинга бесперебойности и производительности работы ИТ-среды и оборудования, анализа рабочих процессов, бизнес-аналитики.


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


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


В текущей версии v7.11 доступны следующие наборы инструментов анализа данных с использованием технологий машинного обучения:


  1. Обнаружение аномалий на потоке данных (Anomaly detection)
  2. Аналитика табличных данных (Data frame analytics)

Примечание: Попрактиковаться в использовании перечисленных выше наборов инструментов анализа данных можно будет 24 марта. Совместно с коллегами Elastic мы продемонстрируем, как применять Anomaly detection и Data frame analytics для выявления инцидентов информационной безопасности. Ссылка на регистрацию.

Об инструментах обнаружения аномалий Elastic ранее уже писали на Хабре. С того времени (Elastic версии 7.1) они продолжали активно развиваться, было улучшено качество алгоритмов и удобство их применения для прикладных задач. Но в этой статье мы решили осветить совершенно новый набор функций анализа табличных данных, появившийся в версиях с 7.2 до 7.11.


Data frame analytics это набор функций Elasticsearch и визуализаций Kibana, позволяющих проводить анализ данных без их привязки к временным меткам. В отличии от Anomaly detection, где предполагается временная последовательность анализируемых данных.


Работа с Data frame analytics осуществляется через графический интерфейс с пошаговым мастером настройки. При этом, за счёт автоматической оптимизации параметров обучения (hyperparameters) пользователю не требуются глубокие знания стоящих за ними математических алгоритмов.


Возможности Data frame analytics Elastic версии 7.11 включают в себя:


  1. Выявление отклонений в значениях параметров (outlier detection) с использованием алгоритмов машинного обучения без учителя (unsupervised)
  2. Построение моделей машинного обучения с учителем (supervised) для решения задач:


    a) Регрессии (regression), как определение зависимости одного значения от одного или нескольких других значений


    b) Классификации (classification), как определение принадлежности произвольного объекта к одному из заданных классов



Примечание: Используемые при подготовке статьи датасеты приведены исключительно в целях обзора доступных в Elastic функций машинного обучения, не претендуют на репрезентативность и не могут использоваться для оценки качества алгоритмов.


Выявление отклонений с использованием алгоритмов машинного обучения без учителя (Outlier detection)


Функция Outlier detection, как и ранее существовавшая в Elastic anomaly detection, предназначена для выявления аномальных значений (выбросов) каких-либо параметров и не предполагает обучение с учителем модель строится каждый раз при запуске. Но в отличие от anomaly detection, значения признаков (фич, особенностей, характерных черт анализируемых объектов) в ней анализируются без учета временной последовательности.


Исходными данными для функции выступает массив записей (JSON документов), в котором данные представлены в виде полей и их значений (поддерживаются числовые и логические типы значений). Каждая запись характеризует поведение какого-либо объекта. Поля в записи включают в себя поле, идентифицирующее объект, и поля со значениями, указывающими на аномальное поведение объекта, их называют признаками (feature).


Результатом функции является оценка отклонения для каждого признака и документа в диапазоне от 0 до 1, где 1 указывает на максимальную вероятность того, что соответствующий признак/документ является выбросом по сравнению с другими документами в анализируемых данных.


В качестве алгоритмов поиска выбросов по умолчанию в Elastic используется ансамбль следующих методов:


  • Метод ближайшего соседа (distance of Kth nearest neighbor)
  • Метод K ближайших соседей (distance of K-nearest neighbors)
  • Локальный уровень выброса (local outlier factor)
  • Локальный уровень выброса на основе расстояния (local distance-based outlier factor)

Подробнее про алгоритмы можно почитать здесь и здесь.


Для оценки и интерпретации результатов выявления отклонений Elastic рассчитывает степень влияния признаков на искомое значение.


В качестве иллюстрации приведём несколько примеров применения Outlier detection:


  • анализ метрик производительности для выявления отклонений в нагрузке на сервера со стороны сразу нескольких приложений (здесь);
  • анализ отпечатков бинарных гистограмм исполняемых файлов для обнаружения обфусцированных и вредоносных файлов (здесь);
  • анализ публичных объявлений airnbnb.com (insideairbnb.com) для поиска необычных предложений (здесь).

Ниже рассмотрим функцию анализа выбросов на примере из документации Elastic.



Цель анализа в этом примере выявить необычное поведение пользователей интернет-магазина. Из магазина в систему поступают события оформления заказа продукции, каждое из которых содержит полное имя заказчика (customer_full_name.keyword), количество покупок в заказе (products.quantity), стоимость заказа (products.taxful_price), id заказа (order_id).


Документы в исходном индексе выглядят так
{  "_index": "kibana_sample_data_ecommerce",  "_type": "_doc",  "_id": "_mXypHcB6S7rlhJIFCvB",  "_version": 1,  "_score": null,  "_source": {    "category": [      "Women's Clothing",      "Women's Accessories"    ],    "currency": "EUR",    "customer_first_name": "Sonya",    "customer_full_name": "Sonya Smith",    "customer_gender": "FEMALE",    "customer_id": 28,    "customer_last_name": "Smith",    "customer_phone": "",    "day_of_week": "Saturday",    "day_of_week_i": 5,    "email": "sonya@smith-family.zzz",    "manufacturer": [      "Oceanavigations",      "Pyramidustries"    ],    "order_date": "2021-03-06T23:31:12+00:00",    "order_id": 592097,    "products": [      {        "base_price": 28.99,        "discount_percentage": 0,        "quantity": 1,        "manufacturer": "Oceanavigations",        "tax_amount": 0,        "product_id": 19238,        "category": "Women's Clothing",        "sku": "ZO0265502655",        "taxless_price": 28.99,        "unit_discount_amount": 0,        "min_price": 13.05,        "_id": "sold_product_592097_19238",        "discount_amount": 0,        "created_on": "2016-12-31T23:31:12+00:00",        "product_name": "Vest - red/white",        "price": 28.99,        "taxful_price": 28.99,        "base_unit_price": 28.99      },      {        "base_price": 13.99,        "discount_percentage": 0,        "quantity": 1,        "manufacturer": "Pyramidustries",        "tax_amount": 0,        "product_id": 13328,        "category": "Women's Accessories",        "sku": "ZO0201102011",        "taxless_price": 13.99,        "unit_discount_amount": 0,        "min_price": 6.86,        "_id": "sold_product_592097_13328",        "discount_amount": 0,        "created_on": "2016-12-31T23:31:12+00:00",        "product_name": "Across body bag - aqua ",        "price": 13.99,        "taxful_price": 13.99,        "base_unit_price": 13.99      }    ],    "sku": [      "ZO0265502655",      "ZO0201102011"    ],    "taxful_total_price": 42.98,    "taxless_total_price": 42.98,    "total_quantity": 2,    "total_unique_products": 2,    "type": "order",    "user": "sonya",    "geoip": {      "country_iso_code": "CO",      "location": {        "lon": -74.1,        "lat": 4.6      },      "region_name": "Bogota D.C.",      "continent_name": "South America",      "city_name": "Bogotu00e1"    },    "event": {      "dataset": "sample_ecommerce"    }  },  "fields": {    "order_date": [      "2021-03-06T23:31:12.000Z"    ],    "products.created_on": [      "2016-12-31T23:31:12.000Z",      "2016-12-31T23:31:12.000Z"    ]  },  "sort": [    1615073472000  ]}

Начнём с подготовки данных для анализа. Так как мы сравниваем между собой заказчиков, то исходные события необходимо группировать по полю customer_full_name.keyword. Признаками поведения заказчиков будут выступать суммарные значения количества заказов, количества покупок, стоимость заказов.


Чтобы сгруппировать события, используем функцию трансформации transforms, которая позволяет на лету формировать и сохранять в Elasticsearch результаты агрегации ранее собранных данных.


Примечание: Для расчёта нужных признаков используем функции Elastic по агрегации: числовые значения считаем через products.quantity.sum и products.taxful_price.sum, а количество заказов order_id.value_count.



Результат агрегации, представленный в табличном виде, выглядит следующим образом:



Эти данные будем записывать в индекс ecommerce_customers_outlier_detection. Документы в нём соответствуют строкам указанной выше таблицы, а столбцы полям в этих документах.



Чтобы просматривать индекс встроенными средствами Kibana, а не только через API, можно включить опцию "Create index template". Тогда соответствующий шаблон отображения индекса будет доступен в Kibana Discovery и при создании дашбордов в Kibana.


Опция "Continuous mode" включит выполнение трансформации в непрерывном режиме. Это обеспечит автоматическое обновление данных в индексе ecommerce_customers_outlier_detection с заданной периодичностью.


Примечание: Функцию транформации можно заменить правилом обработки данных, самостоятельно написанным для корреляционного движка watcher, также являющимся частью Elasticsearch.


Документы в результирующем индексе ecommerce_customers_outlier_detection выглядят следующим образом
{  "_index": "ecommerce_customers_outlier_detection",  "_type": "_doc",  "_id": "QWoH6FA5JvsfN4JjO_LF32QAAAAAAAAA",  "_version": 1,  "_score": 0,  "_source": {    "customer_full_name": {      "keyword": "Abd Adams"    },    "order_id": {      "value_count": 2    },    "products": {      "taxful_price": {        "sum": 98.9765625      },      "quantity": {        "sum": 4      }    }  }}

Теперь самое интересное запускаем задачу машинного обучения (job в терминах Elastic ML). Мастер создания задачи позволяет отфильтровать данные для анализа с использованием встроенных в Elasticsearch языков запросов KQL (Kibana query language) или Lucene.



Здесь же можно посмотреть анализируемые данные, а также наглядно визуализировать данные различных полей на диаграммах рассеяния.



С помощью Advanced configuration параметров создания модели мы можем включить/выключить расчёт степени влияния признаков на модель (Compute feature influence), задать минимальное значение выброса для расчёта этого влияния (Feature influence threshold), а также объём выделенной под модель оперативной памяти (Model memory limit) и количество используемых заданием потоков процессора (Maximum number of threads), тем самым снижая или увеличивая нагрузку на кластер Elasticsearch.



Блок Hyperparameters используется для управления параметрами обучения. Здесь можно выбрать:


  • математический алгоритм (Method) обнаружения отклонений (lof, ldof, distance_kth_nn, distance_knn) или использования ансамбля алгоритмов (ensemble), когда значения отклонений определяются путём комбинации и оценки их результатов;
  • количество используемых в расчётах соседей (N neighbors);
  • переключатель использования предварительной стандартизации значений (Standardization enabled).

Подробнее о параметрах и их значениях можно почитать в референсах на соответствующий эндпоинт API.


На завершающем шаге мастера указываем название и описание для задания, имя целевого индекса для сохранения результатов, имя поля с результатами анализа и необходимость создания шаблона в kibana.



После запуска, задание проходит через этапы:


  • создание результирующего индекса и добавление в него исходных данных (reindexing);
  • загрузка данных из индекса (loading data);
  • анализ данных и расчёт оценок выбросов (analyzing);
  • запись значений оценок выбросов в результирующий индекс (writing results).


Результаты работы задания можно подробно рассмотреть через интерфейс Kibana Data frame analytics.



На таблице с результатами анализа видим значение совокупной оценки выброса для каждого заказчика (ml.outlier_score) и оценку влияния признаков по насыщенности цвета соответствующей ячейки. Соответствующее числовое значение оценки сохраняется в служебном индексе с результатами анализа в поле ml.feature_influence.


В итоговом индексе результат работы алгоритма выглядит следующим образом
 {  "_index": "ecommerce_customers_outlier_detection_results",  "_type": "_doc",  "_id": "RQzr5SwrcdFVVAr9s9NEOwAAAAAAAAAA",  "_version": 2,  "_score": 1,  "_source": {    "customer_full_name": {      "keyword": "Elyssa Tran"    },    "order_id": {      "value_count": 4    },    "products": {      "taxful_price": {        "sum": 223.9921875      },      "quantity": {        "sum": 5      }    },    "ml__incremental_id": 926,    "ml": {      "outlier_score": 0.9770675301551819,      "feature_influence": [        {          "feature_name": "order_id.value_count",          "influence": 0.9383776783943176        },        {          "feature_name": "products.quantity.sum",          "influence": 0.05973121151328087        },        {          "feature_name": "products.taxful_price.sum",          "influence": 0.0018910884391516447        }      ]    }  },  "sort": [    1,    0.9770675301551819  ]}

Графически выбросы отображаются на диаграммах рассеяния. Здесь можно подсвечивать значения выбросов по выбранному порогу оценки.



И включить отображение размера точек в соответствии со значением отклонения.



Примечание: Данные диаграммы разработаны с использованием языка Vega, доступного любому пользователю в конструкторе визуализаций Kibana.


Регрессия и классификация с учителем


Рассмотрим следующий набор функций Data frame analytics контролируемое обучение (обучение с учителем). Они предоставляют пользователю возможность обучить в Elastic свою собственную модель и использовать её для автоматического предсказания значений. Модель можно загружать и выгружать из системы, а также оценивать её качество. Кроме того, через Eland поддерживается импорт в Elastic моделей, обученных с помощью библиотек scikit-learn, XGBoost или LightGBM. Вместе с возможностями платформы по сбору и обработке данных эти функции помогают реализовать в ней подход CRISP-DM (Cross-Industry Standard Process for Data Mining).


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


Исходными данными (обучающим датасетом) для функции служит массив из уникальных записей (JSON документов). В каждой записи присутствует искомое поле (числовое для регрессии или категориальное для классификации) и поля признаков, влияющих на искомое поле. Значения искомого поля здесь используются для обучения модели и проверки её результатов. Результатом работы функции выступает обученная модель и новый массив данных, включающий исходный датасет, предсказанные значения и данными о степени влияния каждого признака. Датасет при этом можно использовать для оценки качества модели, а саму модель для анализа потока данных, поступающих в Elastic или ранее сохранённых в системе.


Схема реализации функций в Elastic


В качестве показателей поддерживаются числовые, логические и категориальные типы данных.


Обе функции используют собственные алгоритмы Elastic, построенные на базе градиентного бустинга деревьев решений XGBoost. Также возможно определение важности признаков по методу SHapley Additive exPlanations (SHAP).


Алгоритмы регрессии и классификации применяются для кредитного скоринга, оценки рисков, предсказания стоимости продукции, планирования производственных мощностей, обнаружения вредоносного программного обеспечения, мошеннических действий. Реализация этих функций на базе платформы анализа машинных данных с высокой скоростью сбора, индексации и поиска данных упрощает решение трудоёмких и ресурсоёмких задач, например,обнаружение активности сгенерированных доменов (DGA), анализ удовлетворённости клиентов, определение языка.


Далее разберем примеры использования регрессии и классификации и возможности платформы по интерпретации результатов их работы.


Регрессия


С помощью регрессионного анализа попробуем предсказать продолжительность задержки рейса, на примере из документации Elastic. Для анализа используем метеоданные, данные с табло вылета/прилёта и стоимость билетов.


Документы в исходном индексе выглядят так
{  "_index": "kibana_sample_data_flights",  "_type": "_doc",  "_id": "lmX0pHcB6S7rlhJI2kVr",  "_version": 1,  "_score": null,  "_source": {    "FlightNum": "6GZQTCH",    "DestCountry": "IT",    "OriginWeather": "Thunder & Lightning",    "OriginCityName": "Tokyo",    "AvgTicketPrice": 849.1194483923543,    "DistanceMiles": 6127.633563869634,    "FlightDelay": false,    "DestWeather": "Rain",    "Dest": "Pisa International Airport",    "FlightDelayType": "No Delay",    "OriginCountry": "JP",    "dayOfWeek": 2,    "DistanceKilometers": 9861.470310212213,    "timestamp": "2021-02-17T15:41:38",    "DestLocation": {      "lat": "43.683899",      "lon": "10.3927"    },    "DestAirportID": "PI05",    "Carrier": "ES-Air",    "Cancelled": false,    "FlightTimeMin": 493.07351551061066,    "Origin": "Narita International Airport",    "OriginLocation": {      "lat": "35.76470184",      "lon": "140.3860016"    },    "DestRegion": "IT-52",    "OriginAirportID": "NRT",    "OriginRegion": "SE-BD",    "DestCityName": "Pisa",    "FlightTimeHour": 8.217891925176845,    "FlightDelayMin": 0  },  "fields": {    "hour_of_day": [      15    ],    "timestamp": [      "2021-02-17T15:41:38.000Z"    ]  },  "sort": [    1613576498000  ]}

В данном случае функцию transforms применять не нужно, так как каждый документ датасета содержит данные только об одном полёте, и цель анализа предсказать задержку в отношении каждого полёта. Но подготовить данные можно исключим ошибочные записи с расстоянием перелёта 0 километров. В качестве предсказываемого (проверочного) поля указываем FlightDelayMin.



В таблице included Fields выбираем поля признаков длительности задержки рейса, которые будут учтены при построении модели.



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



Обучение с учителем предполагает возможность проверки результатов предсказаний. Для этого используем исходный датасет, задав пропорцию разделения данных на учебные и тестовые.


Следующий шаг после выбора признаков настройка параметров.



Advanced configuration:


  • количество признаков, для которых в результирующий индекс будет записано значение влияния соответствующего признака на результат предсказания (Feature importance values);
  • имя поля, в которое будет записан результат предсказания (Prediction field name);
  • лимит на объём используемой заданием оперативной памяти (Model memory limit);
  • максимальное количество используемых заданием потоков процессора (Maximum numbers of threads).

Hyperparameters:


  • коэффициент регуляризации Лямбда (Lambda);
  • максимальное количество деревьев для бустинга (Max trees);
  • коэффициент регуляризации Гамма (Gamma);
  • размер градиентного шага Эта (Eta);
  • доля выборки (Feature bag fraction);
  • псевдослучайное число, используемое при выборе из датасета документов для обучения модели (Randomize seed).

Примечание: Описание применения в Elastic этих и дополнительных гиперпараметров приведено в документации к API.


Теперь посмотрим на результаты работы алгоритма. Они записываются в итоговый индекс Elasticsearch и представлены в отчёте в табличном виде.



Здесь можно увидеть новые, по сравнению с датасетом, поля:


  1. Отметка об использовании данных для обучения (ml.is_training)
  2. Результаты предсказания задержки рейса (ml.FlightDelayMin_prediction)

Если при создании задания было указано количество признаков, для которых будет рассчитано значение их влияния на результат (Feature importance values), в таблице отобразятся соответствующие значения для каждого признака (ml.feature_importance), а в результатах бар-чарт средних значений по всему датасету.



При клике на поле ml.feature_importance увидим наглядный график принятия решения алгоритмом SHAP.



Точкой обозначено среднее значение прогнозов для всего датасета. Линией соединены значения степени влияния признаков, от меньшего к большему. Верхний признак сильнее всего влияет на решение, в нашем примере это причина задержки рейса (FlightDelayType).


Результаты доступны для просмотра и другими средствами визуализации Kibana

Например, в Kibana Lens. Ниже построен бар-чарт фактических и предсказанных задержек рейсов с разбивкой по погоде в пункте назначения.



Кроме индекса с предсказанными моделью значениями, основным результатом выполнения задания также является обученная модель. Выгрузить модель из Elastic в JSON файл позволяет эндпоинт trained_models, как указано здесь.


В этом же отчете можно увидеть метрики качества модели:


  • среднеквадратическая ошибка (Mean Squared Error, MSE);
  • коэффициент детерминации (R-squared, R2 );
  • псевдо-функция потерь Хьюбера (Pseudo-Huber loss);
  • среднеквадратичная логарифмическая ошибка (Mean squared logarithmic error, MSLE).


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


После того как модель сформирована, она может применяться для предсказания значений по новым данным. Для этого в Elasticsearch есть две возможности:


  • анализ поступающих в Elasticsearch данных (Inference processor);
  • анализ ранее сохранённых в Elasticsearch данных (Inference aggregation).

Пример c Inference processor
POST /_ingest/pipeline/_simulate{  "pipeline" : {    "description" : "Flight delay prophecy",    "processors" : [       {          "inference": {           "model_id":"flights_delay_prophecy-1613827670191",           "inference_config": {             "regression": {               "results_field": "FlightDelayMin_prediction"             }           }         }       }    ]  },  "docs": [    {      "_index": "index",      "_id": "id",      "_source": {          "FlightNum" : "9HY9SWR",          "Origin" : "Frankfurt am Main Airport",          "OriginLocation" : {            "lon" : "8.570556",            "lat" : "50.033333"          },          "DestLocation" : {            "lon" : "151.177002",            "lat" : "-33.94609833"          },          "DistanceMiles" : 10247.856675613455,          "FlightTimeMin" : 1030.7704158599038,          "OriginWeather" : "Sunny",          "dayOfWeek" : 0,          "AvgTicketPrice" : 841.2656419677076,          "Carrier" : "Kibana Airlines",          "FlightDelayMin" : 0,          "OriginRegion" : "DE-HE",          "FlightDelayType" : "No Delay",          "DestAirportID" : "SYD",          "timestamp" : "2021-02-08T00:00:00",          "Dest" : "Sydney Kingsford Smith International Airport",          "FlightTimeHour" : 17.179506930998397,          "DistanceKilometers" : 16492.32665375846,          "OriginCityName" : "Frankfurt am Main",          "DestWeather" : "Rain",          "OriginCountry" : "DE",          "DestCountry" : "AU",          "DestRegion" : "SE-BD",          "OriginAirportID" : "FRA",          "DestCityName" : "Sydney"        }    }  ]}

Пример c Inference aggregation
GET kibana_sample_data_flights/_search{  "size":0,  "query": {    "term": {      "FlightNum": {        "value": "00HGV4F"      }    }  },   "aggs": {    "res": {       "composite": {         "size": 1,        "sources": [          {            "FlightNum": {              "terms": {                "field": "FlightNum"                              }            }          }        ]      },      "aggs" : {        "AvgTicketPrice": {          "max": {            "field": "AvgTicketPrice"          }        },       "Dest": {           "scripted_metric": {             "init_script": "state.Dest = ''",             "map_script": "state.Dest = params._source.Dest",             "combine_script": "return state.Dest",             "reduce_script": "for (d in states) if (d != null) return d"           }         },         "DestAirportID": {           "scripted_metric": {             "init_script": "state.DestAirportID = ''",             "map_script": "state.DestAirportID = params._source.DestAirportID",             "combine_script": "return state.DestAirportID",             "reduce_script": "for (d in states) if (d != null) return d"           }         },         "DestRegion": {           "scripted_metric": {             "init_script": "state.DestRegion = ''",             "map_script": "state.DestRegion = params._source.DestRegion",             "combine_script": "return state.DestRegion",             "reduce_script": "for (d in states) if (d != null) return d"           }         },         "DistanceKilometers": {          "max": {            "field": "DistanceKilometers"          }        },        "DistanceMiles": {          "max": {            "field": "DistanceMiles"          }        },        "FlightDelayType": {           "scripted_metric": {             "init_script": "state.FlightDelayType = ''",             "map_script": "state.FlightDelayType = params._source.FlightDelayType",             "combine_script": "return state.FlightDelayType",             "reduce_script": "for (d in states) if (d != null) return d"           }         },         "FlightTimeMin": {          "max": {            "field": "FlightTimeMin"          }        },        "Origin": {           "scripted_metric": {             "init_script": "state.Origin = ''",             "map_script": "state.Origin = params._source.Origin",             "combine_script": "return state.Origin",             "reduce_script": "for (d in states) if (d != null) return d"           }         },         "OriginAirportID": {           "scripted_metric": {             "init_script": "state.OriginAirportID = ''",             "map_script": "state.OriginAirportID = params._source.OriginAirportID",             "combine_script": "return state.OriginAirportID",             "reduce_script": "for (d in states) if (d != null) return d"           }         },        "OriginRegion": {           "scripted_metric": {             "init_script": "state.OriginRegion = ''",             "map_script": "state.OriginRegion = params._source.OriginRegion",             "combine_script": "return state.OriginRegion",             "reduce_script": "for (d in states) if (d != null) return d"           }         },        "FlightDelayMin_prediction" : {          "inference": {            "model_id": "flights_delay_prophecy-1613827670191",             "buckets_path": {               "AvgTicketPrice": "AvgTicketPrice",               "Dest": "Dest.value",               "DestAirportID": "DestAirportID.value",               "DestRegion": "DestRegion.value",               "DistanceKilometers": "DistanceKilometers",               "DistanceMiles": "DistanceMiles",               "FlightDelayType": "FlightDelayType.value",               "FlightTimeMin": "FlightTimeMin",               "Origin": "Origin.value",               "OriginAirportID": "OriginAirportID.value",               "OriginRegion": "OriginRegion.value"             }          }        }      }     }  }}

Классификация


Продолжим тему полетов и проанализируем данные об авиарейсах, предсказывая не длительность задержки, как в регрессии, а факт отмены рейса. Используем датасет из предыдущего примера, трансформация в агрегированный индекс здесь тоже не требуется.


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



Как и в предыдущих типах анализа, для числовых полей можно построить диаграммы рассеяния, при этом соответствующие значениям классы, в нашем случае true и false, выделяются цветом.



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


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



В таблице результатов данные датасета дополнены полями:


  • отметка об использовании данных для обучения (ml.is_training);
  • предсказанный статус отмены рейса (ml.Cancelled_prediction);
  • вероятность предсказания (ml.prediction_probability);
  • влияние признаков на результат (ml.feature_importance);
  • оценка предсказания для всех искомых классов (ml.prediction_score).

Пример сохраненных результатов расчётов ml.prediction_score
"top_classes": [        {          "class_probability": 0.9617513617353418,          "class_score": 0.24080996012552122,          "class_name": false        },        {          "class_probability": 0.03824863826465814,          "class_score": 0.03824863826465814,          "class_name": true        }      ]

В понимании параметров оценки поможет документация Elastic.


Как и в регрессии, в результатах доступен график усреднённых значений важности признаков.



Для проверки результатов в классификации доступны следующие метрики:


  • матрица ошибок (Confusion matrix);
  • площадь кривой ошибок (area under receiver operating characteristic curve, AUC ROC).

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



Кривая ошибок и значение площади AUC ROC в версии 7.11 не отображается, но значения можно получить через API. В 7.12 такая возможность уже будет добавлена.


Пример запроса AUC ROC
POST _ml/data_frame/_evaluate{   "index": "cancelled_flights_prediction_2",   "evaluation": {      "classification": {          "actual_field": "Cancelled",          "predicted_field": "ml.Cancelled_prediction",          "metrics": {           "auc_roc": {             "class_name": "true"           }          }      }   }}

и ответа
{  "classification" : {    "auc_roc" : {      "value" : 0.8240223547611558    }  }}   

Сохранённая модель доступна для использования в Inference processor и Inference aggregation, как в предыдущем примере.


Заключение


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


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


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

Подробнее..

Как лицензируется и чем отличаются лицензии Elastic Stack (Elasticsearch)

05.11.2020 02:15:38 | Автор: admin
В этой статье расскажем как лицензируется Elastic Stack, какие бывают лицензии, что туда входит (ключевые возможности), немножечко сравним Elastic с OpenDistro от AWS и другими известными дистрибутивами.



Как видно на картинке выше, существует 5 типов, условно говоря, подписок, по которым можно пользоваться системой. Подробности по тому, что написано ниже, вы можете узнать на специальной странице Elastic. Всё написанное в этой статье применимо к Elastic Stack, размещаемому на собственной инфраструктуре (on-premise).

Open Source. Это версия Elastic Stack, которая находится в свободном доступе в репозитории Elastic на Github. В принципе, вы можете взять ее и сделать убийцу Arcsight, QRadar, Splunk и других прямых конкурентов Elastic. Платить за это ничего не нужно.

Basic. Этот тип лицензии включает в себя возможности предыдущей лицензии, но дополнен функционалом, который не имеет открытого кода, но, тем не менее, доступен на бесплатной основе. Это, например, SIEM, доступ к ролевой модели, некоторые виды визуализаций в Kibana, Index Lifecycle Management, некоторые встроенные интеграции и другие возможности.

На этом бесплатные лицензии закончились и пришло время разобраться с платными лицензиями. Elastic Stack лицензируется по количеству нод Elasticsearch. Рядом может стоять хоть миллион Kibana и Logstash (или Fluentd, если угодно), но лицензии будут считаться именно по хостам, на которых развернут Elasticsearch. В расчет лицензий также не входят ноды с ролями Ingest, Client/Coordinating. На попадающее в расчет количество нод напрямую влияет объем входящего трафика и требования к хранению данных. Напомним, что для обеспечения надежности работы кластера, в нем должно быть минимум 3 ноды. Мы проводим расчет сайзинга исходя из методики, которую описывали в одной из предыдущих статей. При покупке лицензий Elasticsearch доступен только формат подписки длительностью от 1 года с шагом в 1 год (2, 3 и так далее). Теперь вернемся к типам лицензий.

Gold. В лицензии Elasticsearch уровня Gold появляется поддержка авторизации через LDAP/AD, расширеное логирование для внутреннего аудита, расширяются возможности алертинга и техподдержка вендора в рабочие часы. Именно подписка уровня Gold очень похожа на AWS OpenDistro.

Platinum. Наиболее популярный тип подписки. кроме возможностей уровня Gold, тут появляется встроенное в Elastic машинное обучение, кросс-кластерная репликация, поддержка клиентов ODBC/JDBC, возможность гранулярного управления доступом до уровня документов, поддержка вендора 24/7/365 и некоторые другие возможности. Ещё в рамках этой подписки они могут выпускать Emergency patches.

Enterprise. Самый выскоий уровень подписки. Кроме всех возможностей уровня Platinum, сюда входят оркестратор Elastic Cloud Enterprise, Elastic Cloud on Kubernetes, решение по безопасности для конечных устройств Endgame (со всеми его возможностями), поддержка вендором неограниченного количества проектов на базе Elastic и другие возможности. Обычно используется в крупных и очень крупных инсталляциях.

У Elastic появилось уже немало форков, самый известный из которых OpenDistro от AWS. Его ключевым преимуществом является поддержка некоторых возможностей оригинального Elastic, доступных на платных подписках. Основные это интеграция с LDAP/AD (а еще SAML, Kerberos и другими), встроенный алертинг (на бесплатном Elastic это реализуется через Elast Alert), логирование действий пользователей и поддержка JDBC-драйверов.

Упомянем также про HELK и Logz.io. Первый проект на Github, который обвешивает Elasticsearch дополнительным ПО для аналитики угроз (пишут, что пока это всё находится в альфе), а второй облачный сервис, основанный на Elastic и добавляющий некоторые приятные фичи. В комментариях можно поделиться другими форками, о которых вам известно.

Для получения дополнительной информации о сайзинге Elasticsearch, лицензировании и по другим вопросам, вы можете оставить заявку в форме обратной связи на сайте или другим удобным способом.

А ещё можно почитать:

Сайзинг Elasticsearch

Разбираемся с Machine Learning в Elastic Stack (он же Elasticsearch, он же ELK)

Elastic под замком: включаем опции безопасности кластера Elasticsearch для доступа изнутри и снаружи

Что полезного можно вытащить из логов рабочей станции на базе ОС Windows
Подробнее..

Сборка логов в kubernetes. Установка EFK стека с LDAP интеграцией. (Bitnami, opendistro)

26.01.2021 10:19:42 | Автор: admin

Постепенно эволюционируя, каждая организация переходит от ручного grep логов к более современным инструментам для сбора, анализа логов. Если вы работаете с kubernetes, где приложение может масштабироваться горизонтально и вертикально, вас просто вынуждают отказаться от старой парадигмы сбора логов. В текущее время существует большое количество вариантов систем централизованного логирования, причем каждый выбирает наиболее приемлемый вариант для себя. В данной статье пойдет речь о наиболее популярном и зарекомендовавшем себя стэке Elasticsearch + Kibana + Fluentd в связке с плагином OpenDistro Security. Данный стэк полностью open source, что придает ему особую популярность.

Проблематика

Нам необходимо было наладить сборку логов с кластера kubernetes. Из требований:

  • Использовать только открытые решения.

  • Сделать очистку логов.

  • Необходимо прикрутить LDAP, для разграничения прав.

Пререквизиты

Данный материал предполагает:

  • Имеется установленный kuberenetes 1.18 или выше (ниже версию не проверяли)

  • Установленный пакетный менеджер helm 3

Немного о helm chart

Наиболее популярным способом установки приложения в kubernetes является helm. Helm это пакетный менеджер, с помощью которого можно подготовить набор компонентов для установки и связать их вместe, дополнив необходимыми метриками и конфигурацией.

В своей практике мы используем helm chart от компании bitnami(подразделение vmware)

  • собраны open source продукты на все случаи жизни.

  • корпоративные стандарты по разработке чатов и докер образов

  • красивая документация

  • проект живой и активно поддерживается сообществом

Выбор стека

Во многом выбор стека технологий определило время. С большой долей вероятностью два года назад мы бы деплоили ELK стек вместо EFK и не использовали helm chart.

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

Elasticsearch и kibana поставляются с открытой лицензией, однако плагины для security и других вкусностей идут под иной лицензией. Однако компания Amazon выпустила плагины Open Distro, которые покрывают оставшийся функционал под открытой лицензией.

Схема выглядит примерно так

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

Минимальный деплой EFK стека (без Security)

Сборка EFK стека была произведена по статье Collect and Analyze Log Data for a Kubernetes Cluster with Bitnami's Elasticsearch, Fluentd and Kibana Charts. Компоменты упакованы в отдельный чат. Исходники можно взять здесь и произвести командой

helm dependency updatehelm upgrade --install efk . -f values-minimal.yaml

Из исходников values-minimal.yaml

elasticsearch:  volumePermissions:    enabled: truekibana:  volumePermissions:    enabled: true  elasticsearch:    hosts:    - "efk-elasticsearch-coordinating-only"    port: 9200# Пропишите свой хост, если используете ингресс  ingress:    enabled: true    hostname: kibana.local# Либо   service:    type: NodePort    port: 30010fluentd:  aggregator:    enabled: true    configMap: elasticsearch-output    extraEnv:    - name: ELASTICSEARCH_HOST      value: "efk-elasticsearch-coordinating-only"    - name: ELASTICSEARCH_PORT      value: "9200"  forwarder:#    Чтение логов с диска /var/log/containers/* отключено    enabled: false    configMap: apache-log-parser    extraEnv:    - name: FLUENTD_DAEMON_USER      value: root    - name: FLUENTD_DAEMON_GROUP      value: root

Кибана будет доступна по адресу http://minikube_host:30010/, либо http://kibana.local.

Как видим компонент fluentd forwarder не включен. Перед включением парсинга, я рекомендовал бы настроить на определенные логи, иначе еластику может быть послано слишком большое количество логов. Правила для парсинга описаны в файле apache-log-parser.yaml.

Как отправить логи в EFK

Существует много способов, для начала предлагаем либо включить fluentd forwarder, либо воспользоваться простейшим приложением на python. Ниже пример для bare metal. Исправьте FLUENT_HOST FLUENT_PORT на ваши значения.

cat <<EOF | kubectl apply -f -apiVersion: apps/v1kind: Deploymentmetadata:  name: helloworld  labels:    app: helloworldspec:  replicas: 1  template:    metadata:      name: helloworld      labels:        app: helloworld    spec:      containers:        - name: helloworld          image: sergbs/django-hello-world:1          imagePullPolicy: Always          ports:            - containerPort: 8000          env:            - name: FLUENT_HOST              value: "efk-fluentd-headless"            - name: FLUENT_PORT              value: "24224"  selector:    matchLabels:      app: helloworld---apiVersion: v1kind: Servicemetadata:  name: helloworldspec:  selector:    app: helloworld  ports:    - port: 8000      nodePort: 30011  type: NodePortEOF

По ссылке http://minikube_host:30011/ Будет выведено "Hello, world!" И лог уйдет в elastic

Пример

Включить fluentd forwarder, он создаст daemon set, т.е. запустится на каждой ноде вашего кубернетеса и будет читать логи docker container-ов.

Добавить в ваш докер контейнер драйвер fluentd, тем более можно добавлять более одного драйвера

Добавить в ваше приложение библиотеку, которая будет напрямую логировать. Пример приложения на python. Используйте его, как отладочное средство при установке EFK.

И как показывает практика, логировать напрямую эффективный, но далеко не самый надежный способ. Даже если вы логируете сразу в fluentd и в консоль. В случае потери конекта, во fluentd часть логов просто не смогут попасть и будут потеряны для него навсегда. Поэтому наиболее надежный способ, это считывать логи с диска для отправки в EFK.

Очистка логов.

Для очистки логов используется curator. Его можно включить, добавив в yaml файл:

elasticsearch:  curator:    enabled: true

По умолчанию его конфигурация уже предусматривает удаление через индекса старше 90 дней это можно увидеть внутри подчата efk/charts/elasticsearch-12.6.1.tgz!/elasticsearch/values.yaml

configMaps:  # Delete indices older than 90 days  action_file_yml: |-      ... unit: daysunit_count: 90

Security

Как обычно security доставляет основную боль при настройке и использовании. Но если ваша организация чуть подросла, это необходимый шаг. Стандартом де факто при настройке безопасности является интеграция с LDAP. Официальные плагины от еластика выходят не под открытой лицензией, поэтому приходится использовать плагин Open Distro. Далее продемонстрируем, как его можно запустить.

Сборка elasticsearch c плагином opendistro

Вот проект в котором собирали docker images.

Для установки плагина, необходимо, чтобы версия elasticsearch соответствовала версии плагина.

В quickstart плагина рекомендуется установить install_demo_configuration.sh с демо сертификатами.

FROM bitnami/elasticsearch:7.10.0RUN elasticsearch-plugin install -b https://d3g5vo6xdbdb9a.cloudfront.net/downloads/elasticsearch-plugins/opendistro-security/opendistro_security-1.12.0.0.zipRUN touch /opt/bitnami/elasticsearch/config/elasticsearch.ymlUSER rootRUN /bin/bash /opt/bitnami/elasticsearch/plugins/opendistro_security/tools/install_demo_configuration.sh -y -iRUN mv /opt/bitnami/elasticsearch/config/elasticsearch.yml /opt/bitnami/elasticsearch/config/my_elasticsearch.ymlCOPY my_elasticsearch.yml /opt/bitnami/elasticsearch/config/my_elasticsearch.ymlUSER 1001

Есть небольшая магия, ввиду, того что плагин дополняет elasticsearch.yml, а контейнеры bitnami только при старте генерируют этот файл. Дополнительные же настройки они просят передавать через my_elasticsearch.yml

В my_elasticsearch.yml мы изменили настройку, это позволит нам обращаться к рестам elasticsearch по http.

# turn off REST layer tlsopendistro_security.ssl.http.enabled: false

Сделано это в демонстрационных целях, для облегчения запуска плагина. Если вы захотите включить Rest Layer tls придется добавлять соответствующие настройки во все компоненты, которые общаются с elasticsearch.

Запуск docker-compose с LDAP интеграцией

Запустим проект с помощью docker-compose up , и залогинимся на http://0:5601 под admin/admin

Теперь у нас есть вкладка Security

Можно посмотреть настройку LDAP через интерфейс кибаны

Настройки должны совпадать с файлами конфигурации. Стоит обратить внимание, что плагин хранит свои данные в индексе еластика, и файлы конфигурации применяет при инициализации, т.е. если индекс не создан. Если вы измените файлы позже то вам придется воспользоваться утилитой securityadmin.sh

docker exec -it elasticsearch /bin/bashI have no name!@68ac2255bb85:/$ ./securityadmin_demo.shOpen Distro Security Admin v7Will connect to localhost:9300 ... doneConnected as CN=kirk,OU=client,O=client,L=test,C=deElasticsearch Version: 7.10.0Open Distro Security Version: 1.12.0.0Contacting elasticsearch cluster 'elasticsearch' and wait for YELLOW clusterstate ...Clustername: elasticsearchClusterstate: YELLOWNumber of nodes: 1Number of data nodes: 1.opendistro_security index already exists, so we do not need to create one.Populate config from /opt/bitnami/elasticsearch/plugins/opendistro_security/securityconfig/Will update '_doc/config' with /opt/bitnami/elasticsearch/plugins/opendistro_security/securityconfig/config.yml    SUCC: Configuration for 'config' created or updatedWill update '_doc/roles' with /opt/bitnami/elasticsearch/plugins/opendistro_security/securityconfig/roles.yml    SUCC: Configuration for 'roles' created or updatedWill update '_doc/rolesmapping' with /opt/bitnami/elasticsearch/plugins/opendistro_security/securityconfig/roles_mapping.yml    SUCC: Configuration for 'rolesmapping' created or updatedWill update '_doc/internalusers' with /opt/bitnami/elasticsearch/plugins/opendistro_security/securityconfig/internal_users.yml    SUCC: Configuration for 'internalusers' created or updatedWill update '_doc/actiongroups' with /opt/bitnami/elasticsearch/plugins/opendistro_security/securityconfig/action_groups.yml    SUCC: Configuration for 'actiongroups' created or updatedWill update '_doc/tenants' with /opt/bitnami/elasticsearch/plugins/opendistro_security/securityconfig/tenants.yml    SUCC: Configuration for 'tenants' created or updatedWill update '_doc/nodesdn' with /opt/bitnami/elasticsearch/plugins/opendistro_security/securityconfig/nodes_dn.yml    SUCC: Configuration for 'nodesdn' created or updatedWill update '_doc/whitelist' with /opt/bitnami/elasticsearch/plugins/opendistro_security/securityconfig/whitelist.yml    SUCC: Configuration for 'whitelist' created or updatedWill update '_doc/audit' with /opt/bitnami/elasticsearch/plugins/opendistro_security/securityconfig/audit.yml    SUCC: Configuration for 'audit' created or updatedDone with successI have no name!@68ac2255bb85:/$ 

настройка Ldap

Для настройки интеграции с LDAP необходимо заполнить соответствующие секции в elastisearch-opendistro-sec/config.yml, ссылка на официальную документацию по authentication

config:  dynamic:    authc:      # тут можно настроить авторизацию          authz:      # а здесь аутентификацию

В случае с Active Directory, необходимо будет изменить конфигурационный файл примерно так:

      # тут можно настроить авторизацию          ldap:        ...            hosts:              - ldaphost:389            bind_dn: cn=LDAP,ou=Example,dc=example,dc=ru            password: CHANGEME            userbase: 'DC=example,DC=ru'            usersearch: '(sAMAccountName={0})'            username_attribute: sAMAccountName

Не забудьте воспользоваться securityadmin.sh после изменения конфигурации. Процедура была описана в предыдущем параграфе.

Установка EFK + Opendistro в kubernetes

Вернемся к проекту с kubernetes, установим проект командой

helm upgrade --install efk . -f values.yaml  

Нам необходимо будет

Для настройка OpenDistro Security plugin мы скопировали файл конфигурации, которые поместим в секреты kubernetes.

  extraVolumes:  - name: config    secret:      secretName: opendistro-config      items:        - key: config.yml          path: config.yml  - name: roles-mapping    secret:      secretName: opendistro-config      items:        - key: roles_mapping.yml          path: roles_mapping.yml  extraVolumeMounts:    - mountPath: /opt/bitnami/elasticsearch/plugins/opendistro_security/securityconfig/config.yml      subPath: config.yml      name: config    - mountPath: /opt/bitnami/elasticsearch/plugins/opendistro_security/securityconfig/roles_mapping.yml      subPath: roles_mapping.yml      name: roles-mapping

Чтобы настройки применялись при команде helm upgrade, мы сделали job, который будет запускаться при каждой команде helm upgrade

apiVersion: batch/v1kind: Jobmetadata:    name: opendistro-config-reload    labels:        app.kubernetes.io/managed-by: {{.Release.Service | quote }}        app.kubernetes.io/instance: {{.Release.Name | quote }}    annotations:        "helm.sh/hook": post-upgrade        "helm.sh/hook-delete-policy": hook-succeededspec:    template:        metadata:            name: config-reload            labels:                app.kubernetes.io/managed-by: {{.Release.Service | quote }}                app.kubernetes.io/instance: {{.Release.Name | quote }}        spec:            initContainers:                - name: "wait-for-db"                  image: "alpine:3.6"                  command:                      - 'sh'                      - '-c'                      - >                          until nc -z -w 2 efk-elasticsearch-coordinating-only 9300 && echo elastic is ok; do                            sleep 2;                          done;            containers:                - name: opendistro-config-reload                  image: "{{ .Values.elasticsearch.image.registry }}/{{ .Values.elasticsearch.image.repository}}:{{ .Values.elasticsearch.image.tag }}"                  imagePullPolicy: {{ .Values.elasticsearch.image.pullPolicy | quote }}                {{- if .Values.elasticsearch.master.securityContext.enabled }}                  securityContext:                    runAsUser: {{ .Values.elasticsearch.master.securityContext.runAsUser }}                 {{- end }}                  command:                    - 'bash'                    - '-c'                    - >                       "/opt/bitnami/elasticsearch/plugins/opendistro_security/tools/securityadmin.sh" -h efk-elasticsearch-coordinating-only -cd "/opt/bitnami/elasticsearch/plugins/opendistro_security/securityconfig" -icl -key "/opt/bitnami/elasticsearch/config/kirk-key.pem" -cert "/opt/bitnami/elasticsearch/config/kirk.pem" -cacert "/opt/bitnami/elasticsearch/config/root-ca.pem" -nhnv            restartPolicy: Never    backoffLimit: 1

Итоги

Если вы собираетесь организовать централизованную сборку логов для приложений под управление kubernetes, данный вариант мог бы стать вполне обоснованным решением. Все продукты поставляются под открытыми лицензиями. В статье приведена заготовка из которой можно создать production ready решение. Спасибо за внимание!

Подробнее..

Изучаем ELK. Часть II Установка Kibana и Logstash

28.01.2021 22:20:35 | Автор: admin

Вступительное слово

В предыдущей статье была описана процедура установки Elasticsearch и настройка кластера. В этой статье будет рассмотрена процедура установки Kibana и Logstash, а также их настройка для работы с кластером Elasticsearch.

План действий

  1. Скачиваем и устанавливаем Kibana.

  2. Настраиваем Kibana для работы с кластером Elasticsearch.

  3. Настраиваем балансировку нагрузки между Kibana и Elasticsearch.

  4. Настраиваем несколько экземпляров Kibana.

  5. Скачиваем и устанавливаем Logstash.

  6. Настраиваем Logstash для чтения данных из файла.

  7. Смотрим полученные данные в Kibana.

Скачиваем и устанавливаем Kibana

Установка из Deb пакета

  • Импортируем PGP ключ:

wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
  • Устанавливаем apt-transport-https пакет:

sudo apt-get install apt-transport-https
  • Перед установкой пакета необходимо добавить репозиторий Elastic:

echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-7.x.list
  • Устанавливаем Kibana:

sudo apt-get update && sudo apt-get install kibana
  • Настраиваем Kibana для автоматического запуска при старте системы:

sudo /bin/systemctl daemon-reload && sudo /bin/systemctl enable kibana.service

Так же возможен вариант установки из скаченного Deb пакет с помощью dpkg

wget https://artifacts.elastic.co/downloads/kibana/kibana-7.10.2-amd64.debsudo dpkg -i kibana-7.10.2-amd64.deb

Установка из RPM пакета

  • Импортируем PGP ключ

sudo rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch
  • В директории /etc/yum.repos.d/ создаем файл репозитория kibana.repo для CentOS или Red Hat. Для дистрибутива OpenSUSE в директории /etc/zypp/repos.d/:

[kibana-7.x]name=Kibana repository for 7.x packagesbaseurl=https://artifacts.elastic.co/packages/7.x/yumgpgcheck=1gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearchenabled=1autorefresh=1type=rpm-md
  • Устанавливаем Kibana c помощью пакетного менеджера в зависимости от операционной системы,yumилиdnfдляCentOS,Red Hat,FedoraилиzypperдляOpenSUSE:

# Yumsudo yum install kibana # Dnfsudo dnf install kibana # Zyppersudo zypper install kibana
  • Настраиваем Kibana для автоматического запуска при старте системы:

sudo /bin/systemctl daemon-reload && sudo /bin/systemctl enable kibana.service

Так же возможен вариант установки из скаченного RPM пакет с помощью rpm

wget https://artifacts.elastic.co/downloads/kibana/kibana-7.10.2-x86_64.rpmsudo rpm --install kibana-7.10.2-x86_64.rpm

Установка из архива tar.gz

  • Скачиваем архив c Kibana:

curl -O https://artifacts.elastic.co/downloads/kibana/kibana-7.10.2-linux-x86_64.tar.gz
  • Извлекаем данные и переходим в директорию с Kibana:

tar -xzf kibana-7.10.2-linux-x86_64.tar.gzcd kibana-7.10.2-linux-x86_64/

Текущий каталог считается как $KIBANA_HOME.

Конфигурационные файлы находятся в каталоге$KIBANA_HOME/config/.

Для запускаKibanaможно создать отдельного пользователя предоставив все необходимые права к каталогу сKibana.

Настраиваем Kibana для работы с кластером Elasticsearch

Для настройки Kibana используется YAML файл, который лежит по следующему пути /etc/kibana/kibana.yml при установке из Deb и RPM пакетов или $KIBANA_HOME/config/kibana.yml при установке из архива.

  • Определяем адрес и порт, на которых будет работать Kibana (по умолчанию localhost:5601):

server.host: 10.0.3.1server.port: 5601
  • Указываем узлы кластера Elasticsearch:

elasticsearch.hosts:  - http://10.0.3.11:9200  - http://10.0.3.12:9200  - http://10.0.3.13:9200

В случае недоступности узла, с которым Kibana установила соединение, произойдет переключение на другой узел кластера, указанный в конфигурационном файле.

  • Указываем, где Kibana будет хранить свои логи (по умолчанию stdout):

logging.dest: /var/log/kibana/kibana.log

Необходимо предоставить доступ на запись к данному каталогу, чтобы Kibana писала логи. В случае установки из пакетов Dep или RPM доступ предоставляется пользователю или группе kibana, а для установки из архива - пользователю, который осуществляет запуск Kibana.

  • Настраиваем частоту опроса Elasticsearch для получения обновлённого списка узлов кластера:

elasticsearch.sniffInterval: 600000
  • Определяем, запрашивать ли обновленный список узлов кластера Elasticsearch в случае сбоя соединения с кластером:

elasticsearch.sniffOnConnectionFault: true

На выходе получаем конфигурационный файл:

# Адрес и портserver.host: 10.0.3.1server.port: 5601# Узлы кластера Elasticsearchelasticsearch.hosts:  - http://10.0.3.11:9200  - http://10.0.3.12:9200  - http://10.0.3.13:9200# Частота запросов обновления узлов кластера# Запрос обновлений в случае сбоя подключенияelasticsearch.sniffInterval: 60000elasticsearch.sniffOnConnectionFault: true# Логи Kibanalogging.dest: /var/log/kibana/kibana.log

По умолчанию Kibana имеет ограничение на использование памяти в размере 1,4 Гб. Для изменения этого значения необходимо в файле node.options указать новые значения для параметра --max-old-space-size. Значения указываются в мегабайтах.

Данный файл находится в каталоге /etc/kibana/ при установке из Deb и RPM пакетов или $KIBANA_HOME/config/ - при установке из архива

  • Запускаем службу kibana:

sudo systemctl start kibana.service

Для установки из архива используем:

$KIBANA_HOME/bin/kibana

Для выключения службы запущенной из архива используйтеCtrl-C.

В браузере набираем IP адрес и порт (в примере выше это http://10.0.3.1:5601), который указывали в конфигурации Kibana. В результате должна открыться приветственная страница.

Приветственная страница KibanaПриветственная страница Kibana

Настраиваем балансировку нагрузки между Kibana и Elasticsearch

Для организации балансировки между Kibana и узлами Elastcisearch в Elastcisearch имеется встроенный механизм. На хост c установленной Kibana, ставится Elasticsearch с ролью Coordinating only. Узел Elasticsearch с данной ролью обрабатывает HTTP запросы и распределяет их между узлами кластера.

Установка и настройка Elasticsearch

  • Устанавливаем Elasticseach на узел с Kibana. Как это сделать описано в предыдущей статье.

  • Настраиваем новому узлу роль Coordinating only. Для этого для ролей master, data и ingest указываем параметр false:

node.master: falsenode.data: falsenode.ingest: false

ingest роль позволяет построить конвейер дополнительной обработки данных до их индексирования. Выделения отдельных узлов с этой ролью снижает нагрузку на другие узлы. Узел с ролью master и/или data имеют эту роль по умолчанию.

  • Указываем имя Elasticsearch кластера:

cluster.name: es_cluster  # Имя кластера
  • Указываем адреса узлов текущего кластера. Для этого создадим файл unicast_hosts.txt с перечнем узлов в директории с конфигурационными файлами Elasticsearch. Для установки из Deb и RPM пакетов это /etc/elasticsearch/ или $ES_HOME/config/ при установке из архива:

# Список узлов кластера10.0.3.1110.0.3.1210.0.3.13
  • Указываем, что адреса узлов кластера нужно брать из файла:

discovery.seed_providers: file

Данный метод имеет преимущество над методом из предыдущей статьи (discovery.seed_hosts). Elasticsearch следит за изменением файла и применяет настройки автоматически без перезагрузки узла.

  • Настраиваем IP адрес и порт для приема запросов от Kibana (network.host и http.port) и для коммуникации с другими узлами кластера Elasticsearch(transport.host и transport.tcp.port). По умолчанию параметр transport.host равен network.host:

network.host: 10.0.3.1          # Адрес узлаhttp.port: 9200          # Портtransport.host: 10.0.3.1          # Адрес для связи с кластеромtransport.tcp.port: 9300-9400   # Порты для коммуникации внутри кластера

Итоговый конфигурационный файл:

# ------------------------------------ Node ------------------------------------# Имя узлаnode.name: es-nlb01# Указываем роль Coordinating onlynode.master: falsenode.data: falsenode.ingest: false## ---------------------------------- Cluster -----------------------------------#cluster.name: es_cluster  # Имя кластера## --------------------------------- Discovery ----------------------------------discovery.seed_providers: file                       ## ---------------------------------- Network -----------------------------------#network.host: 10.0.3.1          # Адрес узлаhttp.port: 9200          # Портtransport.host: 10.0.3.1          # Адрес для связи с кластеромtransport.tcp.port: 9300-9400     # Порты для коммуникации внутри кластера## ----------------------------------- Paths ------------------------------------#path.data: /var/lib/elasticsearch # Директория с даннымиpath.logs: /var/log/elasticsearch # Директория с логами
  • Запускаем Elasticsearch и проверяем, что узел присоединился к кластеру:

curl -X GET "http://10.0.3.1:9200/_cluster/health?pretty"{  "cluster_name" : "es_cluster",  "status" : "green",  "timed_out" : false,  "number_of_nodes" : 4,  "number_of_data_nodes" : 3,  "active_primary_shards" : 6,  "active_shards" : 12,  "relocating_shards" : 0,  "initializing_shards" : 0,  "unassigned_shards" : 0,  "delayed_unassigned_shards" : 0,  "number_of_pending_tasks" : 0,  "number_of_in_flight_fetch" : 0,  "task_max_waiting_in_queue_millis" : 0,  "active_shards_percent_as_number" : 100.0}

Теперь в кластере 4 узла, из них 3 с ролью data.

Настраиваем Kibana

  • В конфигурации Kibana указываем адрес Coordinating only узла:

elasticsearch.hosts:  - http://10.0.3.1:9200
  • Перезапускаем Kibana и проверяем, что служба запустилась, а UI Kibana открывается в браузере.

Настраиваем несколько экземпляров Kibana

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

  • Настроить уникальное имя:

    • server.name уникальное имя экземпляра. По умолчанию имя узла.

В документации к Kibana указана необходимость настройки server.uuid, однако, в списке параметров конфигурации данный параметр отсутствует. На практике uuid генерируется автоматически и хранится в директории, в которой Kibana хранит свои данные. Данная директория определяется параметром path.data. По умолчанию для установки из Deb и RPM пакетов это /var/lib/kibana/ или $KIBANA_HOME/data/ для установки из архива.

  • Для каждого экземпляра в рамках одного узла необходимо указать уникальные настройки:

    • logging.dest директория для хранения логов;

    • path.data директория для хранения данных;

    • pid.file файл для записи ID процесса;

    • server.port порт, который будет использовать данный экземпляр Kibana ;

  • Указать следующие параметры одинаковыми для каждого экземпляра:

    • xpack.security.encryptionKey произвольный ключ для шифрования сессии. Длина не менее 32 символов.

    • xpack.reporting.encryptionKey произвольный ключ для шифрования отчетов. Длина не менее 32 символов.

    • xpack.encryptedSavedObjects.encryptionKey ключ для шифрования данных до отправки их в Elasticsearch. Длина не менее 32 символов.

    • xpack.encryptedSavedObjects.keyRotation.decryptionOnlyKeys список ранее использованных ключей. Позволит расшифровать ранее сохраненные данные.

Настройки безопасности(xpack) ELK будут рассмотрены в отдельной статье.

Чтобы запустить несколько экземпляров Kibana на одном узле, необходимо указать путь к файлу конфигурации каждого из них. Для этого используется ключ -c:

bin/kibana -c <путь_к_файлу_конфигурации_#1>bin/kibana -c <путь_к_файлу_конфигурации_#2>

Скачиваем и устанавливаем Logstash

Установка из Deb пакета

  • Импортируем GPG ключ:

wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
  • Устанавливаем apt-transport-https пакет:

sudo apt-get install apt-transport-https
  • Добавляем репозиторий Elastic:

echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-7.x.list
  • Устанавливаем Logstash:

sudo apt-get update && sudo apt-get install logstash
  • Настраиваем Logstash для автоматического запуска при старте системы:

sudo /bin/systemctl daemon-reload && sudo /bin/systemctl enable logstash.service

Установка из RPM пакета

  • Импортируем PGP ключ

sudo rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch
  • В директории /etc/yum.repos.d/ создаем файл репозитория logstash.repo для CentOS или Red Hat. Для дистрибутива OpenSUSE - в директории /etc/zypp/repos.d/

[logstash-7.x]name=Elastic repository for 7.x packagesbaseurl=https://artifacts.elastic.co/packages/7.x/yumgpgcheck=1gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearchenabled=1autorefresh=1type=rpm-md
  • Устанавливаем Logstash c помощью пакетного менеджера в зависимости от операционной системы,yumилиdnfдляCentOS,Red Hat,FedoraилиzypperдляOpenSUSE:

# Yumsudo yum install logstash # Dnfsudo dnf install logstash # Zyppersudo zypper install logstash
  • Настраиваем Logstash для автоматического запуска при старте системы:

sudo /bin/systemctl daemon-reload && sudo /bin/systemctl enable logstash.service

Установка из архива

  • Скачиваем архив с Logstash:

curl -O https://artifacts.elastic.co/downloads/logstash/logstash-7.10.2-linux-x86_64.tar.gz
  • Извлекаем данные и переходим в директорию с Logstash:

tar -xzf logstash-7.10.2-linux-x86_64.tar.gzcd logstash-7.10.2/

Текущий каталог считается как $LOGSTASH_HOME.

Конфигурационные файлы находятся в каталоге$LOGSTASH_HOME/config/.

Помимо архива сайта можно скачать Deb или RPM пакет и установить с помощью dpkg или rpm.

Настраиваем Logstash для чтения данных из файла

В качестве примера настроим считывание собственных логов Logstash из директории /var/log/logstash/. Для этого необходимо настроить конвейер (pipeline).

Logstash имеет два типа файлов конфигурации. Первый тип описывает запуск и работу Logstash (settings files).

Второй тип отвечает за конфигурацию конвейера (pipeline) обработки данных. Этот файл состоит из трех секций: input, filter и output.

  • Чтобы описать конвейер создаем файл logstash.conf в директории /etc/logstash/conf.d/, если установка была из Deb и RPM, или в директории $LOGSTASH_HOME/conf.d/ для установки из архива, предварительно создав эту директорию.

Для установки из архива необходимо в конфигурационном файле $LOGSTASH_HOME/config/pipelines.yml указать путь до директории с настройками конвейера:

- pipeline.id: main  path.config: "./conf.d/*.conf"

Для установки из архива также требуется указать, где хранить логи в файле конфигурации $LOGSTASH_HOME/config/logstash.yml:

path.logs: /var/log/logstash/# логи Logstash

Не забудьте предоставить доступ на запись к данному каталогу пользователю, который осуществляет запуск Logstash.

  • В файле logstash.conf настроим плагин file в секции input для чтения файлов. Указываем путь к файлам через параметр path, а через параметр start_position указываем, что файл необходимо читать с начала:

input {  file {    path => ["/var/log/logstash/*.log"]    start_position => "beginning"  }}

Каждое событие журнала логов будет представлять собой JSON документ и будет записано целиком в поле с ключом message. Чтобы из каждого события извлечь дату, время, источник и другую информацию, необходимо использовать секцию filter.

  • В секции filter с помощью плагина grok и встроенных шаблонов извлекаем из каждой записи (message) журнала логов необходимую информацию:

filter {  grok {    match => { "message" => "\[%{TIMESTAMP_ISO8601:timestamp}\]\[%{DATA:severity}%{SPACE}\]\[%{DATA:source}%{SPACE}\]%{SPACE}%{GREEDYDATA:message}" }    overwrite => [ "message" ]  }}

Шаблон имеет формат %{SYNTAX:SEMANTIC} и по сути это оболочка над регулярным выражением, соответственно шаблон можно описать регулярным выражением. С перечнем всех встроенных шаблоном можно ознакомится тут.

SEMANTIC - это ключ поля с данными, которые извлекаются с помощью шаблона, и под этим ключом будут храниться в JSON документе.

С помощью параметра match указываем, из какого поля (message) извлекаем данные по описанным шаблонам. Параметр overwrite сообщает, что оригинальное поле message необходимо перезаписать в соответствии с теми данными, которые мы получили с помощью шаблона %{GREEDYDATA:message}.

  • Для сохранения данных в Elasticsearch настраиваем плагин elasticsearch в секции output. Указываем адреса узлов кластера Elasticseach и имя индекса.

Индекс (index) - оптимизированный набор JSON документов, где каждый документ представляет собой набор полей ключ - значение. Каждый индекс сопоставляется с одним или более главным шардом (primary shard) и может иметь реплики главного шарда (replica shard).

Что такое индекс, шард и репликация шардов рассмотрю в отдельной статье.

output {  elasticsearch {    hosts => ["http://10.0.3.11:9200","http://10.0.3.12:9200","http://10.0.3.13:9200"]    index => "logstash-logs-%{+YYYY.MM}"  }}

К названию индекса добавлен шаблон %{+YYYY.MM}, описывающий год и месяц. Данный шаблон позволит создавать новый индекс каждый месяц.

Итоговый файл:

# Читаем файлinput {  file {    path => ["/var/log/logstash/*.log"]    start_position => "beginning"  }}# Извлекаем данные из событийfilter {  grok {    match => { "message" => "\[%{TIMESTAMP_ISO8601:timestamp}\]\[%{DATA:severity}%{SPACE}\]\[%{DATA:source}%{SPACE}\]%{SPACE}%{GREEDYDATA:message}" }    overwrite => [ "message" ]  }}# Сохраняем все в Elasticsearchoutput {  elasticsearch {    hosts => ["http://10.0.3.11:9200","http://10.0.3.12:9200","http://10.0.3.13:9200"]    index => "logstash-logs-%{+YYYY.MM}"  }}
  • Запускаем Logstash:

sudo systemctl start logstash.service

Для установки из архива:

$LOGSTASH_HOME/bin/logstash

Смотрим полученные данные в Kibana

Открываем Kibana, в верхнем левом углу нажимаем меню и в секции Management выбираем Stack Management. Далее слева выбираем Index patterns и нажимаем кнопку Create Index Patern. В поле Index pattern name описываем шаблон logstash* , в который попадут все индексы, начинающиеся с logstash.

Создание шаблона индексаСоздание шаблона индекса

Жмем Next step и выбираем Time field поле timestamp, чтобы иметь возможность фильтровать данные по дате и времени. После жмем Create index pattern:

Выбор Time fieldВыбор Time field

Logstash при анализе событий добавил поле @timestamp, в результате получилось 2 поля с датой и временем. Это поле содержит дату и время обработки события, следовательно, эти даты могут различаться. Например, если анализируемый файл имеет старые записи, то поле timestamp будет содержать данные из записей, а @timestamp текущее время, когда каждое событие были обработано.

После создания шаблона индексов Kibana покажет информацию об имеющихся полях, типе данных и возможности делать агрегацию по этим полям.

Чтобы посмотреть полученные данные на основе созданного шаблона нажимаем меню и в секции Kiban выбираем Discover.

Kibana DiscoverKibana Discover

В правой части экрана можно выбрать интервал в рамках которого отображать данные.

Выбор временного интервалаВыбор временного интервала

В левой часте экрана можно выбрать шаблон индекса или поля для отображения из списка Available fields. При нажатии на доступные поля можно получить топ-5 значений.

Шаблон индекса и доступные поляШаблон индекса и доступные поля

Для фильтрации данных можно использовать Kibana Query Language (KQL). Запрос пишется в поле Search. Запросы можно сохранять, чтобы использовать их в будущем.

Фильтрация данных с помощью KQLФильтрация данных с помощью KQL

Для визуализации полученных данных нажимаем меню и в секции Kiban выбираем Visualize. Нажав Create new visualization , откроется окно с перечнем доступных типов визуализации.

Типы визуализации KibanaТипы визуализации Kibana

Для примера выбираем Pie, чтобы построить круговую диаграмму. В качестве источника данных выбираем шаблон индексов logstash*. В правой части в секции Buckets жмем Add , далее - Split slices. Тип агрегации выбираем Terms, поле severity.keyword. Жмем Update в правом нижнем углу и получаем готовую диаграмму. В секции Options можно добавить отображение данных или изменить вид диаграммы.

Если вместо графика отобразилась надпись No results found, проверьте выбранный интервал времени.

Круговая диаграммаКруговая диаграмма

Чтобы посмотреть данные в Elasticsearch необходимо сделать GET запрос /имя_индекса/_search к любому узлу кластера. Добавление параметра pretty позволяет отобразить данные в читабельном виде. По умолчанию вывод состоит из 10 записей, чтобы увеличить это количество необходимо использовать параметр size:

curl -X GET "http://10.0.3.1:9200/logstash-logs-2021.01/_search?pretty&size=100"...{        "_index" : "logstash-logs-2021.01",        "_type" : "_doc",        "_id" : "XlXeQncBKsFiW7wX45A0",        "_score" : 1.0,        "_source" : {          "path" : "/var/log/logstash/logstash-plain.log",          "@version" : "1",          "source" : "logstash.outputs.elasticsearch",          "message" : "[main] Restored connection to ES instance {:url=>\"http://10.0.3.11:9200/\"}",          "host" : "logstash01",          "timestamp" : "2021-01-27T08:03:55,979",          "@timestamp" : "2021-01-27T08:03:58.907Z",          "severity" : "WARN"        }      },...

Заключение

В рамках этой статьи была рассмотрена процедура установки и настройки Kibana и Logstash, настройка балансировки трафика между Kibana и Elasticsearch и работа нескольких экземпляров Kibana. Собрали первые данные с помощью Logstash, посмотрели на данные с помощью Kibana Discover и построили первую визуализацию.

Прежде чем углубляться в изучение плагинов Logstash, сбор данных с помощью Beats, визуализацию и анализ данных в Kibana, необходимо уделить внимание очень важному вопросу безопасности кластера. Об этом также постоянно намекает Kibana, выдавая сообщение Your data is not secure.

Теме безопасности будет посвящена следующая статья данного цикла.

Полезные ссылки

Подробнее..

Изучаем ELK. Часть III Безопасность

03.03.2021 20:06:54 | Автор: admin

Вступительное слово

В первой и второй частях данной серии статей была описана процедура установки и настройки кластера Elasticsearch, Kibana и Logstash, но не был освящен вопрос безопасности.

В этой статье я расскажу, как настроить шифрование трафика между узлами кластера Elasticsearch и его клиентам, шифрование трафика между Kibana и клиентами, покажу, как создавать роли и пользователей, а так же выдавать API ключи для доступа к кластеру Elasticsearch.

План действий

  1. "Включаем" безопасность.

  2. Настраиваем шифрование между узлами Elasticsearch.

  3. Настраиваем аутентификацию.

  4. Настраиваем шифрование клиентского трафика Elasticsearch.

  5. Подключаем Kibana к Elasticsearch.

  6. Настраиваем шифрование трафика между Kibana и клиентами.

  7. Создаем пользователей и роли.

  8. Настраиваем пользовательские сессии в Kibana.

  9. Настраиваем Logstash.

  10. Создаем API ключи.

"Включаем" безопасность

Чтобы использовать функции безопасности в Elasticsearch, их необходимо активировать. Для этого на каждом узле в файле конфигурации указывается следующая настройка:

xpack.security.enabled: true

Настраиваем шифрование между узлами Elasticsearch

Следующим шагом необходимо настроить шифрование трафика между узлами Elasticsearch. Для этого выполняем несколько шагов:

  • Создаем CA (Certificate Authority) для кластера Elasticsearch:

./bin/elasticsearch-certutil ca

Для установки из пакетов Deb и RPM исполняемые файлы Elasticsearch лежат в каталоге /usr/share/elasticsearch/bin/. Для установки из архива - в каталоге $ES_HOME/bin/.

В примерах все команды выполнены из каталога /usr/share/elasticsearch/.

Во время генерации корневого сертификата можно задать имя PKCS#12 файла, по умолчанию это elastic-stack-ca.p12 и пароль к нему.

Для получения сертификата и ключа в PEM формате укажите ключ --pem. На выходе будет ZIP архив с .crt и .key файлами.

С помощью ключа --out можно указать каталог для создаваемого файла.

Полученный корневой сертификат (для PEM формата еще и ключ) надо переместить на все узлы кластера для генерации сертификата узла.

  • Генерируем на каждом узле кластера сертификат и ключ:

./bin/elasticsearch-certutil cert --ca elastic-stack-ca.p12 --ip 10.0.3.11 --dns es-node01

Ключ --ca указывает путь к корневому сертификату CA в формате PKCS#12. Если сертификат и ключ были получены в PEM формате, то необходимо использовать ключи --ca-cert и --ca-key соответственно.

Ключи --dns и --ip добавляют проверку по имени узла и IP адресу и являются опциональными. Если вы указываете их, то укажите эти параметры для каждого узла.

Ключ --pass позволяет установить passphrase для ключа.

  • Включаем TLS в файле конфигурации Elasticsearch:

xpack.security.transport.ssl.enabled: truexpack.security.transport.ssl.verification_mode: fullxpack.security.transport.ssl.keystore.path: es-node01-cert.p12xpack.security.transport.ssl.truststore.path: elastic-stack-ca.p12

Где:

xpack.security.transport.ssl.enabled - включаем TLS/SSL

xpack.security.transport.ssl.verification_mode - режим проверки сертификатов. none - проверка не выполняется, certificate - выполняется проверка сертификата без проверки имени узла и IP адреса, full - проверка сертификата, а также имени узла и адреса указанных в сертификате.

xpack.security.transport.ssl.keystore.path - путь к файлу с сертификатом и ключем узла.

xpack.security.transport.ssl.truststore.path - путь к доверенному сертификату (CA).

Если сертификаты CA и/или узла в формате PEM, то необходимо изменить последние два параметра на следующие:

xpack.security.transport.ssl.key - путь к закрытому ключу узла

xpack.security.transport.ssl.certificate - путь к сертификату узла

xpack.security.transport.ssl.certificate_authorities - список путей к сертифкатам CA.

  • Cоздаем keystore и добавляем пароли от сертификатов(если они были заданы):

./bin/elasticsearch-keystore create -p

Ключ -p требуется для установки пароля keystone во время создания

Для PKCS#12 формата:

./bin/elasticsearch-keystore add xpack.security.transport.ssl.keystore.secure_password./bin/elasticsearch-keystore add xpack.security.transport.ssl.truststore.secure_password

Для PEM сертификата:

./bin/elasticsearch-keystore add xpack.security.transport.ssl.securekeypassphrase

Чтобы запустить Elasticsearch с keystore, на который установлен пароль, необходимо передать этот пароль Elasticsearch. Это делается с помощью файла на который будет ссылаться переменная ES_KEYSTORE_PASSPHRASE_FILE. После запуска файл можно удалить, но при каждом последующим запуске файл необходимо создавать.

echo "password" > /etc/elasticsearch/ks_secret.tmpchmod 600 /etc/elasticsearch/ks_secret.tmpsudo systemctl set-environment ES_KEYSTORE_PASSPHRASE_FILE=/etc/elasticsearch/ks_secret.tmp
  • Перезапускаем Elasticsearch

В логах Elasticsearch должны появится записи о создании кластера:

[INFO ][o.e.c.s.ClusterApplierService] [es-node01] master node changed {previous [], current [{es-node02}{L1KdSSwCT9uBFhq0QlxpGw}{ujCcXRmOSn-EbqioSeDNXA}{10.0.3.12}{10.0.3.12:9300}...

Если обратиться к API, то будет ошибка "missing authentication credentials for REST request". С момента включения функций безопасности для обращения к кластер необходимо пройти аутентификацию.

Настраиваем аутентификацию

Elasticsearch имеет несколько встроенных пользователей:

Пользователь

Описание

elastic

Суперпользователь

kibana_system

Используется для коммуникации между Kibana и Elasticsearch

logstash_system

Пользователь, которого использует Logstash сервер, когда сохраняет информацию в Elasticsearch

beats_system

Пользователь, которого использует агент Beats, когда сохраняет информацию в Elasticsearch

apm_system

Пользователь, которого использует APM сервер, когда сохраняет информацию в Elasticsearch

remote_monitoring_user

Пользователь Metricbeat, который используется при сборе и хранении информации мониторинга в Elasticsearch

Прежде чем воспользоваться перечисленными пользователями, необходимо установить для них пароль. Для этого используется утилита elasticsearch-setup-passwords. В режиме interactive для каждого пользователя необходимо ввести пароли самостоятельно, в режиме auto Elasticsearch создаст пароли автоматически:

./bin/elasticsearch-setup-passwords autoInitiating the setup of passwords for reserved users elastic,apm_system,kibana,kibana_system,logstash_system,beats_system,remote_monitoring_user.The passwords will be randomly generated and printed to the console.Please confirm that you would like to continue [y/N]yChanged password for user apm_systemPASSWORD apm_system = NtvuRYhwbKpIEVUmHsZBChanged password for user kibana_systemPASSWORD kibana_system = ycXvzXglaLnrFMdAFsvyChanged password for user kibanaPASSWORD kibana = ycXvzXglaLnrFMdAFsvyChanged password for user logstash_systemPASSWORD logstash_system = vU3CuRbjBpax1RrsCCLFChanged password for user beats_systemPASSWORD beats_system = c9GQ85qhNL59H2AXUvcAChanged password for user remote_monitoring_userPASSWORD remote_monitoring_user = wB320seihljmGsjc29W5Changed password for user elasticPASSWORD elastic = iOrMTBbfHOAkm5CPeOj7

Второй раз elasticsearch-setup-passwords запустить не получится, так как bootstrap password изменился. Чтобы изменить пароль пользователям можно воспользоваться API.

Попробуем сделатьAPI запрос к любому узлу Elasticsearch с использованием учетной записи elastic и пароля к от неё:

curl -u 'elastic' -X GET "http://10.0.3.1:9200/_cluster/health?pretty"Enter host password for user 'elastic':{  "cluster_name" : "es_cluster",  "status" : "green",  "timed_out" : false,  "number_of_nodes" : 4,  "number_of_data_nodes" : 3,  "active_primary_shards" : 9,  "active_shards" : 18,  "relocating_shards" : 0,  "initializing_shards" : 0,  "unassigned_shards" : 0,  "delayed_unassigned_shards" : 0,  "number_of_pending_tasks" : 0,  "number_of_in_flight_fetch" : 0,  "task_max_waiting_in_queue_millis" : 0,  "active_shards_percent_as_number" : 100.0}

Как видно из примера все работает, но мы обращались через http, значит трафик между клиентом и кластером Elasticsearch не шифрованный.

Настраиваем шифрование клиентского трафика Elasticsearch

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

  • Генерируем сертификат:

./bin/elasticsearch-certutil http

В процессе генерации необходимо определить:

1) Необходимо ли сгенерировать Certificate Signing Request (CSR). Потребуется, если сертификат будет выпускаться сторонним CA (Certificate Authority).

2) Использовать ли собственный CA (Certificate Authority). Если да, то указываем путь до ключа, которым будет подписаны будущие сертификаты.

3) Срок действия сертификата. По умолчанию 5 лет. Можно определить дни(D), месяцы (M), года (Y).

4) Как выпустить сертификат, на каждый узел или общий. Если все узлы имеют общий домен, то можно выпустить wildcard сертификат (например *.domain.local). Если общего домена нет и в будущем возможно добавление узлов, то необходимо генерировать на каждый узел, указав имя узла и его адрес. В будущем можно выпустить отдельный сертификат для нового узла.

На выходе получаем архив сертификатами, в моём случае со всеми сертификатам для каждого узла Elasticsearch, а так же сертификат для подключения Kibana к Elasticsearch:

. elasticsearch    es-nlb01       README.txt       http.p12       sample-elasticsearch.yml    es-node01       README.txt       http.p12       sample-elasticsearch.yml    es-node02       README.txt       http.p12       sample-elasticsearch.yml    es-node03        README.txt        http.p12        sample-elasticsearch.yml kibana     README.txt     elasticsearch-ca.pem     sample-kibana.yml

В архиве также лежит инструкция по дальнейшим действиям с сертификатом (README.txt) и пример конфигурационного файла (sample-...yml).

Сертификат elasticsearch-ca.pem из директории kibana потребуется в следующем шаге.

  • Размещаем сертификаты на узлах и добавляем необходимые настройки в файле конфигурации:

    xpack.security.http.ssl.enabled: truexpack.security.http.ssl.keystore.path: "http.p12"
    
  • Добавляем пароль от сгенерированного сертификата в keystore:

./bin/elasticsearch-keystore add xpack.security.http.ssl.keystore.secure_password
  • Проверяем, что все работает по https:

curl -u 'elastic' -k -X GET "https://10.0.3.1:9200/_cluster/health?pretty"Enter host password for user 'elastic':{  "cluster_name" : "es_cluster",  "status" : "green",  "timed_out" : false,  "number_of_nodes" : 4,  "number_of_data_nodes" : 3,  "active_primary_shards" : 9,  "active_shards" : 18,  "relocating_shards" : 0,  "initializing_shards" : 0,  "unassigned_shards" : 0,  "delayed_unassigned_shards" : 0,  "number_of_pending_tasks" : 0,  "number_of_in_flight_fetch" : 0,  "task_max_waiting_in_queue_millis" : 0,  "active_shards_percent_as_number" : 100.0}

Подключаем Kibana к Elasticsearch

Если сейчас обратиться к Kibana, то ответом будет "Kibana server is not ready yet".

Это связанно с тем, что сейчас Kibana не может получить доступ к Elasticsearch по http, для этого необходим сертификат Kibana, который был получен в предыдущем шаге, а также требуется пройти аутентификацию. Чтобы настроить работу Kibana:

  • В конфигурационном файле Kibana указываем ключ к сертификату elasticsearch-ca.pem(из предыдущего шага) и меняем протокол http на https:

elasticsearch.hosts: ['https://10.0.3.1:9200']elasticsearch.ssl.certificateAuthorities: [ "/etc/kibana/elasticsearch-ca.pem" ]

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

  • Создаем keystore для хранения пользователя и пароля:

sudo ./bin/kibana-keystore create --allow-root

Команда выполняются из директории /usr/share/kibana

Так как keystore будет создан в каталоге /etc/kibana/ , и keystone требуется файл конфигурации /etc/kibana/kibana.yml, то пользователю, запускающему команду, необходим доступ к этому каталогу и файлу. Я использую sudo и ключ --allow-root. Ключ необходим, так как запускать из под пользователя root нельзя.

Kibana keystore не имеет пароля. Для ограничения доступа используем стандартные средства Linux.

  • Добавляем пользователя kibana_system(встроенный пользователь Elasticsearch) и пароль учетной записи в Kibana keystore:

sudo ./bin/kibana-keystore add elasticsearch.username --allow-rootsudo ./bin/kibana-keystore add elasticsearch.password --allow-root 

Можно использовать так же пользователя kibana, однако, он в системе считается устаревшим (deprecated).

  • перезапускаем Kibana и проверяем открыв нужный адрес в браузере:

Kibana Kibana

Для входа используем учетную запись elastic.

Как можно заменить, трафик между браузером и Kibana не шифруется.

Настраиваем шифрование трафика между Kibana и клиентами

Данная процедура максимально похожа на ту, которую выполняли для получения сертификатов для узлов Elasticsearch.

  • Получаем сертификат при помощи elsticsearch-certutil :

./bin/elasticsearch-certutil cert  -ca /etc/elasticsearch/elastic-stack-ca.p12 -name kibana-certificate -dns kibana01,10.0.3.1,127.0.0.1,localhost -ip 10.0.3.1

При необходимости можем использовать CA (Certificate Authority). В процессе генерации сертификата указываем пароль от CA, если используется, имя будущего сертификата и пароль к нему.

Через -dns и -ip указываем DNS имена и адрес Kibana.

  • Указываем путь к сертификату в файле kibana.yml:

Так как я использовал ранее полученный CA, то указываю путь и к нему (server.ssl.truststore.path).

server.ssl.keystore.path: "/etc/kibana/kibana-certificate.p12"server.ssl.truststore.path: "/etc/elasticsearch/elastic-stack-ca.p12"

Не забывайте о правах доступа, пользователь kibana должен иметь права на чтения.

  • Включаем использование TLS:

server.ssl.enabled: true
  • Добавляем пароли от сертификатов в keystore:

sudo ./bin/kibana-keystore add server.ssl.keystore.password --allow-rootsudo ./bin/kibana-keystore add server.ssl.truststore.password --allow-root
  • Перезагружаем Kibana и проверяем:

Доступ к Kibana по httpsДоступ к Kibana по https

Теперь для подключения к Kibana используем https.

Создаем пользователей и роли

Ранее мы активировали встроенные учетные записи и сгенерировали для них пароли, но использовать пользователя elastic (superuser) не лучшая практика, поэтому рассмотрим, как создавать пользователей и роли к ним.

Для примера создадим администратора Kibana. Открываем Menu > Management > Stack Management, выбираем Users и нажимаем Create user. Заполняем все поля и жмем Create User.

Создание пользователя в KibanaСоздание пользователя в Kibana

Или же можно воспользоваться API. Делать запросы к кластеру можно через консоль Dev Tools инструмента Kibana. Для этого перейдите Menu > Management > Dev Tools. В открывшейся консоли можно писать запросы к Elasticsearch.

POST /_security/user/kibana_admin{  "password" : "password",  "roles" : [ "kibana_admin" ],  "full_name" : "Kibana Administrator",  "email" : "kibana.administrator@example.local"}
Создание пользователя kibana_admin через APIСоздание пользователя kibana_admin через API

После создания пользователя, можно его использовать.

Роль kibana_admin не может создавать пользователей и роли. Для создания пользователей и роли необходима привилегия кластера manage_security. С перечнем всех встроенных ролей можно ознакомится тут.

Далее создадим роль для работы с данными в ранее созданном индексом logstash-logs*. Открываем Menu > Management > Stack Management. Слева выбираем Roles и нажимаем Create role. Настраиваем привилегии, указав в качестве индекса logstash-logs*:

Index privileges

read

Read only права на индекс

Предоставляем пользователю доступ к Kibana, для этого ниже наживаем Add Kibana privilege и выбираем требуемые привилегии:

В поле Spaces указываю All spaces. Что такое Space (пространства) можно почитать на официальном сайте. В рамках данной серии статей Space будет описан в статье о Kibana dashboard.

Чтобы создать роль с привилегиями в Elasticsearch и Kibana через API, делаем запрос к Kibana:

curl -k -i -u 'elastic' -X PUT 'https://10.0.3.1:5601/api/security/role/logstash_reader' \--header 'kbn-xsrf: true' \--header 'Content-Type: application/json' \--data-raw '{  "elasticsearch": {    "cluster" : [ ],    "indices" : [      {        "names": [ "logstash-logs*" ],        "privileges": ["read"]      }      ]  },  "kibana": [    {      "base": [],      "feature": {       "discover": [          "all"        ],        "visualize": [          "all"        ],        "dashboard": [          "all"        ],        "dev_tools": [          "read"        ],        "indexPatterns": [          "read"        ]      },      "spaces": [        "*"      ]    }  ]}'

Создаем пользователя logstash_reader и связываем его с созданной ролью (это мы уже научились делать) и заходим данным пользователем в Kibana.

Главная страница Kibana для пользователя logstash_readerГлавная страница Kibana для пользователя logstash_reader

Как видно, у данного пользователя не так много прав. Он может просматривать индексы logstash-logs*, строить графики, создавать панели и делать GET запросы к этому индексам через Dev Tools.

Настраиваем пользовательские сессии Kibana

  • Закрываем неактивные сессии:

xpack.security.session.idleTimeout: "30m"
  • Устанавливаем максимальную продолжительность одной сессии:

xpack.security.session.lifespan: "1d"
  • Настраиваем интервал принудительной очистки данных о неактивных или просроченных сессиях из сессионного индекса:

xpack.security.session.cleanupInterval: "8h"

Для всех параметров формат времени может быть следующим: ms | s | m | h | d | w | M | Y

Данные о сессии удаляются после того, как пользователь осуществляет закрытие сессии. Если не настроить закрытие неактивных сессий или не ограничить максимальную длительность сессии, то информация об этих сессиях будет накапливаться в сессионном индексе, и Kibana не сможет автоматически удалить данные.

Настраиваем Logstash

На данный момент Logstash не отправляет данные в кластер Elasticsearch, и чтобы это исправить, сделаем несколько настроек.

  • Создаем роль для подключения к кластеру:

В Kibana открываем Menu > Management > Stack Management. Слева выбираем Roles и нажимаем Create role. Указываем имя роли и настраиваем привелегии:

Cluster privileges

manage_index_templates

Все операции над шаблонами индексов

monitor

Read-only права на получение информации о кластере

Index privileges

create_index

Создание индексов

write

Индексирование, обновление и удаление индексов

manage

Мониторинг и управление индексом

manage_ilm

Управление жизненным циклом индексов (IML)

  • Создаем пользователя для подключения к кластер:

Открываем Menu > Management > Stack Management, выбираем Users и нажимаем Create user. Заполняем требуемые данные, указав в качестве роли созданную выше роль.

Создание пользователя logstash_userСоздание пользователя logstash_user
  • Создаем Logstash keystore, и добавляем туда пользователя и пароль от него:

# Создаем keystore с паролемset +o historyexport LOGSTASH_KEYSTORE_PASS=mypasswordset -o historysudo /usr/share/logstash/bin/logstash-keystore create --path.settings /etc/logstash/# Добавляем данныеsudo /usr/share/logstash/bin/logstash-keystore add ES_USER --path.settings /etc/logstash/sudo /usr/share/logstash/bin/logstash-keystore add ES_PWD --path.settings /etc/logstash/
  • Настраиваем аутентификацию в output плагине:

output {  elasticsearch {    ...    user => "${ES_USER}"    password => "${ES_PWD}"  }}
  • Настраиваем TLS в Logstash:

Для подключения по https к Elasticsearch необходимо настроить использование ssl и установить .pem сертификат, который был получен для Kibana.

output {  elasticsearch {    ...    ssl => true    cacert => '/etc/logstash/elasticsearch-ca.pem'  }}
  • Перезагружаем Logstash и проверяем новые записи в индексе

Проверку можно сделать в Kibana через Discovery, как делали в прошлой статье, или через API:

Dev Tools - Console в KibanaDev Tools - Console в Kibana

Создание API ключей

Для работы с Elasticsearch можно не только использовать учетные записи пользователей, но и генерировать API ключ. Для этого необходимо сделать POST запрос:

POST /_security/api_key

В качестве параметров указывают:

name - имя ключа

role_descriptors - описание роли. Структура совпадает с запросом на создание роли.

expiration - Срок действия ключа. По умолчанию без срока действия.

Для примера заменим базовую аутентификацию в Logstash на API ключ.

  • Создаем API ключ в Kibana Dev Tool:

POST /_security/api_key{  "name": "host_logstash01",   "role_descriptors": {    "logstash_api_writer": {       "cluster": ["manage_index_templates", "monitor"],      "index": [        {          "names": ["logstash-logs*"],          "privileges": ["create_index", "write", "manage", "manage_ilm"]        }      ]    }  },  "expiration": "365d"}

Получаем следующий результат:

{  "id" : "979DkXcBv3stdorzoqsf",  "name" : "host_logstash01",  "expiration" : 1644585864715,  "api_key" : "EmmnKb6NTES3nlRJenFKrQ"}
  • Помещаем ключ в формате id:api_key в Keystore:

sudo /usr/share/logstash/bin/logstash-keystore add API_KEY --path.settings /etc/logstash/
  • Указываем API ключ в конфигурационном файле конвейера:

output {  elasticsearch {    hosts => ["https://10.0.3.11:9200","https://10.0.3.12:9200","https://10.0.3.13:9200"]    index => "logstash-logs-%{+YYYY.MM}"    ssl => true    api_key => "${API_KEY}"    cacert => '/etc/logstash/elasticsearch-ca.pem'  }}

Информацию по ключам можно получить в Kibana Menu > Management > API Keys или через API запрос:

GET /_security/api_key?name=host_logstash01{  "api_keys" : [    {      "id" : "9r8zkXcBv3stdorzZquD",      "name" : "host_logstash01",      "creation" : 1613048800876,      "expiration" : 1613049520876,      "invalidated" : false,      "username" : "elastic",      "realm" : "reserved"    }  ]}

Заключение

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

В следующей статье будет рассмотрена процедура создание кластера ELK с помощью Docker.

Полезные ссылки

Подробнее..

Elasticsearch сайзинг шардов как завещал Elastic анонс вебинара предложения по митапу

15.03.2021 20:13:27 | Автор: admin

Каждый индекс Elasticsearch состоит из шардов. Шарды это логическое и физическое разделение индекса. В этой статье мы расскажем о сайзинге шардов Elasticsearch важной его части, серьёзно влияющей на производительность кластера. В высоконагруженных системах выбор правильной конфигурации архитектуры хранения позволит серьёзно сэкономить на железе. Бльшая часть статьи основана на соответствующем разделе документации Elastic. Подробности под катом.

Сайзинг шардов Elasicsearch


Как Elasticsearch работает с шардами


Поисковые запросы обычно попадают в несколько шардов (в продукционных нагруженных средах рекомендуем использовать ноду с ролью coordinating). Каждый шард выполняет поисковый запрос в одном процессорном треде. Если запросов много, пул тредов поиска заканчивается (именно поиска, т.к. есть и другие), что приводит к возникновению очередей, снижению производительности и, как следствие, медленной скорости поиска.

Каждый шард использует ресурсы памяти и процессора. Небольшое количество бльших по объёму шардов использует меньше ресурсов, чем множество мелких.

Давайте теперь краем глаза взглянем на сегменты (см. картинку ниже). Каждый шард Elasticsearch является индексом Lucene. Максимальное количество документов, которое можно закинуть в индекс Lucene 2 147 483 519. Индекс Lucene разделен на блоки данных меньшего размера, называемые сегментами. Сегмент это небольшой индекс Lucene. Lucene выполняет поиск во всех сегментах последовательно. Большинство шардов содержат несколько сегментов, в которых хранятся данные индекса. Elasticsearch хранит метаданные сегментов в JVM Heap, чтобы их можно было быстро извлечь для поиска. По мере роста объёма шарда его сегменты объединяются в меньшее количество более крупных сегментов. Это уменьшает количество сегментов, что означает, что в динамической памяти хранится меньше метаданных (см. также forcemerge, к которому мы вернемся чуть дальше в статье).

Еще стоит сказать о ребалансировке кластера. Если добавляется новая нода или одна из нод выходит из строя, происходит ребалансировка кластера. Ребалансировка сама по себе недешёвая с точки зрения производительности операция. Кластер сбалансирован, если он имеет равное количество шардов на каждой ноде и отсутствует концентрация шардов любого индекса на любой ноде. Elasticsearch запускает автоматический процесс, называемый ребалансировкой, который перемещает шарды между узлами в кластере, чтобы его сбалансировать. При перебалансировке применяются заранее заданные правила выделения сегментов (об allocation awareness и других правилах мы подробнее расскажем в одной из следующих статей). Если вы используете data tiers, Elasticsearch автоматически разместит каждый шард на соответствующем уровне. Балансировщик работает независимо на каждом уровне.

Как заставить Elasticsearch ещё лучше работать с шардами


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

Создавать шарды размером от 10 до 50 ГБ. Elastic говорит, шарды размером более 50 ГБ потенциально могут снизить вероятность восстановления кластера после сбоя. Из-за той самой ребалансировки, о которой мы говорили в начале статьи. Ну, и большие шарды накладнее передавать по сети. Предел в 50 ГБ выглядит, конечно, как сферический конь в вакууме, поэтому мы сами больше склоняемся к 10 ГБ. Вот тут человек советует 10 ГБ и смотреть на размер документов в следующем плане:

  • От 0 до 4 миллионов документов на индекс: 1 шард.
  • От 4 до 5 миллионов документов на индекс: 2 шарда.
  • Более 5 миллионов документов считать по формуле: (количество документов / 5 миллионов) + 1 шард.

20 или менее шардов на 1 ГБ JVM Heap. Количество шардов, которыми может жонглировать нода, пропорциональны объему JVM Heap ноды. Например, нода с 30 ГБ JVM Heap должна иметь не более 600 шардов. Чем меньше, тем, скорее всего, лучше. Если это пропорция не выполняется можно добавить ноду. Посмотрим сколько там используется JVM Heap на каждой ноде:



А теперь посмотрим сколько шардов на каждой ноде и видим, что с нашим тестовым стендов всё в порядке. Жить будет.



Количество шардов на узле можно ограничить при помощи опции index.routing.allocation.total_shards_per_node, но если их уже много, присмотритесь к Shrink API.

Совсем необязательно создавать индексы размером в 1 день. Часто встречали у заказчиков подход, при котором каждый новый день создавался новый индекс. Иногда это оправдано, иногда можно и месяц подождать. Ролловер ведь можно запускать не только с max_age, но и с max_size или max_docs. На Хабре была статья, в которой Адель Сачков, в ту пору из Яндекс Денег (сейчас уже нет), делился полезным лайфхаком: создавал индексы не в момент наступления новых суток, а заранее, чтобы этот процесс не аффектил на производительность кластера, но у него там были микросервисы.
каждые сутки создаются новые индексы по числу микросервисов поэтому раньше каждую ночь эластик впадал в клинч примерно на 8 минут, пока создавалась сотня новых индексов, несколько сотен новых шардов, график нагрузки на диски уходил в полку, вырастали очереди на отправку логов в эластик на хостах, и Zabbix расцветал алертами как новогодняя ёлка. Чтобы этого избежать, по здравому размышлению был написан скрипт на Python для предварительного создания индексов.

С новогодней ёлкой неплохой каламбурчик получился.

Не пренебрегайте ILM и forcemerge. Индексы должны плавно перетекать между соответствующими нодами согласно ILM. В OpenDistro есть аналогичный механизм.



С индексами, в которые уже не ведется запись можно выполнить forcemerge слияние меньших по размеру сегментов в более крупные. Это в итоге снизит накладные расходы на эксплуатацию шардов и повысит скорость поиска. Forcemerge требует значительных ресурсов, поэтому лучше это делать к какие-то в непиковые часы. Добавим, что forcemerge это фактические создание нового сегмента из двух старых, поэтому свободное место на диске лишним точно не будет.

Приходите в комментарии и расскажите о своём опыте с раскладыванием шардов по нодам. Было бы интересно узнать о том, что работает в вашем случае.

Анонс вебинара. Elastic приглашает посетить 17 марта в 12 часов по московскому времени вебинар Elastic Telco Day: Applications and operational highlights from telco environments. Эксперты расскажут о применении в решений Elastic в телекоме. Регистрация.

Предложения по митапу. Планируем проведение онлайн-митап по Elastic в апреле. Напишите в комментариях или в личку какие темы вам было бы интересно разобрать, каких спикеров услышать. Если бы вы хотели сами выступить и у вас есть что рассказать, тоже напишите. Вступайте в группу Elastic Moscow User Group, чтобы не пропустить анонс митапа.

Канал в телеге. Подписывайтесь на наш канал Elastic Stack Recipes, там интересные материалы и анонсы мероприятий.

Читайте наши другие статьи:




Если вас интересуют услуги внедрения, администрирования и поддержки Elastic Stack, вы можете оставить заявку в форме обратной связи на специальной странице.
Подробнее..

Разбираемся, безопасно ли стрелять по проду и чем могут быть полезны дашборды

24.12.2020 14:22:40 | Автор: admin
На подходе полезные видео с конференции ЮMoneyDay от специалистов по тестированию. Если заглянете под кат, то узнаете:

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




Стрельбы по проду. Как реализовали и что получили


Виктор Бодров, исследователь производительности
Какие задачи помогают решить исследования производительности, и как их результаты влияют на развитие ЮMoney.

0:54 О спикере и работе команды
1:24 Почему мы стреляем не по стенду, а по проду
2:37 Чем стрелять? Как мониторить
4:07 Как все начиналось
6:55 Нам понадобились свои пользователи
8:14 А что там с платежами?
11:37 Платежи картами
15:08 Работа с контрагентами
18:47 Стрельбы по компонентам
21:01 Capacity control
23:38 Автострельбы




Почему дашборды могут быть полезны

Егор Иванов, старший специалист по автоматизации тестирования

Спикер рассказывает, для чего команда интеграционного тестирования стала использовать дашборды, какую пользу ребята получили от инструмента и почему считают его важным.

1:04 Что такое дашборд? Примеры из жизни. Определение термина, основные типы.
3:01 Знакомство с командой интеграционного тестирования. Схема взаимодействия инструментов: Jira, Autorun, Locker, Pinger, Jenkins
6:36 Что делать, когда что-то идет не так роль дежурного
9:49 Дашборд дежурного: мастштабирование задач, использование Grafana
10:58 Как происходит отсылка метрик. Типы метрик.
12:20 Процесс отправки метрик из Java и sh
13:03 Как построить дашборд? Как можно использовать дашборды?
13:23 Пример 1 дашборд как визуализатор метрик
17:00 Пример 2 дашборд как мотиватор
20:34 Пример 3 дашборд для анализа
24:00 Пример 4 дашборд для экономии времени
25:59 Подведение итогов: что мы получили от внедрения дашбордов

Дополнительно
Расшифровка доклада Сила дашбордов



Все доклады с большой ИТ-конференции ЮMoneyDay. На подходе материалы про PM, тестирование и мобильную разработку.

Подробнее..

Новый подход к просмотру логов

25.01.2021 00:11:48 | Автор: admin

Одно время, приходилось много работать с логами. Они могли быть большими и находиться на разных серверах. Требовалось не найти что-то конкретное, а понять почему система ведёт себя не так как надо. По некоторым причинам, лог-агрегатора не было.

Хотелось иметь просмотрщик логов, позволяющий, в любой момент, открыть любой файл, без скачивания на локальную машину, как команда less в linux консоли. Но при этом, должна быть удобная подсветка текста, как в IDE, и фильтрация записей по различным параметрам. Фильтрация и поиск должны работать по событиям в логе, а не по строкам, как grep, это важно когда есть многострочные записи, например ошибки со стектрейсами. Так же должна быть возможность просматривать записи сразу из нескольких файлов на одной странице, смёржив их по таймстемпу, даже если файлы находятся на разных нодах.

И я придумал как сделать такую утилиту!

Log Viewer - это небольшое web-приложение, которое работает на нодах, где лежат логи, и показывает эти логи через Web интерфейс. Это именно просмотрщик, а не агрегатор, нет никакой индексации или считывания всего лога в память, читается только та часть лога, которую пользователь смотрит в текущий момент. Такой подход позволяет почти не занимать ресурсов.

Предвижу вопросы опроизводительности типа Разве можно быстро фильтровать записи без индексации? Вплохих случаях придётся остcканировать весь лог чтобы найти хоть одну запись подходящую под фильтр. Вопервых, сканирование лога работает довольно быстро, 1Гб читается около 3,5сек, это терпимо. Вовторых, обычно известен временной интервал, вкотором ищем проблему, если задан фильтр подате, тобудет сканироваться только тачасть файла, вкоторой находятся записи относящиеся ктому времени. Найти границу временного интервала вфайле можно очень быстро бинарным поиском.

Отображение лога

Чтобы легче различать границы одной записи, запись под курсором подсвечивается прямоугольником; поле severity подсвечивается различными цветами в зависимости от значения, парные скобки подсвечиваются когда наводишь курсор на одну из них.

Обратите внимание настектрейс эксепшена, показаны только самые интересные строки, остальные сфолжены под + и , интересными строками считаются классы изпакетов принадлежащий главному приложению, соседнии сними, ипервая строка. Пакеты главного приложения задаются вконфигурации. Втаком виде стектрейс занимает намного меньше места наэкране иего удобней смотреть. Возможно такая идея понравится разработчикам Java IDE.

Имя логгера тоже сокращено: ~.SecurityManager. Показывается только имя класса, апакет сворачивается в ~.

Фолдинг влияет только на отображение, поиск работает по оригинальному тексту. Если совпадение найдётся в сокращённой части текста, то эта часть текста автоматически появится. Также, если пользователь выделит текст и нажмёт Ctrl+C, в буфер скопируется исходный текст, без всяких сокращений.

Архитектура позволяет легко навешивать на текст подсветку или всплывающие подсказки, благодаря этому, сделаны разные приятные мелочи типа показа даты в человеческом формате, если она напечатана в виде числа:

Фильтрация

Набор фильтров зависит от формата лога. Некоторые фильтры доступны всегда, например фильтр по подстроке, а некоторые появляются если в логе присутствует поле определённого типа. Это позволяет создавать специализированные фильтры для некоторых типов полей. Например, если в логе есть поле severity, то в верхней панельке появится такой UI компонент:

Severity filter

Очень удобно добавлять фильтры изконтекстного меню. Можно выделить текст, кликнуть правой кнопкой мыши ивыбрать Непоказывать записи стаким текстом. Напанельку сфильтрами автоматически добавится фильтр потексту, скрывающий записи стаким текстом. Помогает когда лог завален однообразными записями, неинтересными вданный момент.

Добавление фильтров из контекстного меню

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

Для сложных случаев можно задать фильтр с условием написанным на JavaScript. Такой фильтр представляет из себя функцию принимающую одну записи и возвращающую true или false.

Пример фильтра на JavaScript
function isVisibleEvent(text, fields) {    var match = text.match(/Task completed, elapsed time: (\d+)ms$/)    if (!match)        return false // Don't show events not matched the pattern            var time = parseInt(match[1])    return time > 500 // Show only events where elapsed time is more than a threshold}

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

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

Мелкие, но полезные фичи

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

Если сервер расположен в другой таймзоне, над текстом с датой будет всплывающая подсказка с датой в таймзоне пользователя.

Конфигурация

Я старался сделать конфигурацию как можно проще, чтобы всё работало из коробки. Если попросить пользователя задать формат лога, то большинство просто закроют приложение и пойдут смотреть по старинке. Поэтому формат лога распознаётся автоматически. Конечно, это работает не всегда и часто не точно. Для таких случаев можно задать формат лога вручную в файле конфигурации. Можно использовать паттерны log4j, logback или просто регексп. Если ваш лог не распознался, но вам кажется что должен создайте issue на GitHub, этим вы поможете проекту.

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

logs = [  {    path: "/opt/my-app/logs/*.log"  },  {    path: ${HOME}"/work/**"  }]

Пользователю будут доступны только .log файлы в директории /opt/my-app/logs и любые файлы в директории ~/work и её поддиректориях.

Более подробная информация в документации на GitHub.

Работа с несколькими нодами

Мёрж файлов, расположенных наразных нодах это киллер фича, ради которой изатевался проект. Как яуже говорил, файл никогда нескачивается полностью содной ноды надругую инеиндексируется. Поэтому, накаждой изнод должен быть запущен Log Viewer. Пользователь открывает webUI наодной изнод, указывает расположение логов, иLog Viewer коннектится кдругим инстансам LogViewer чтобы подгружать содержимое лога через них. Записи извсех открытых файлов мёржатся потаймстемпу ипоказываются как буд-то это один файл.

Вкрадце опишу как это работает под капотом. Когда пользователь открывает страницу, надо показать конец лога, для этого накаждую ноду отправляется запрос дай последниеN записей, где N количество строк помещающихся наэкран. Полученные записи сортируются потаймстемпу, берутся последниеN записей ипоказываются пользователю. Когда пользователь скролит страницу вверх, навсе ноды посылается запрос дай последниеN записей стаймстемпом меньшеT, где T таймстемп самой верхней записи наэкране. Полученные записи сортируются идобавляются настраницу. При скроле вниз происходит тоже самое, только вдругую сторону. Поиск позиции вфайле, где находятся записи старше/младше T,работает очень быстро, так как записи отсортированы потаймстемпу иможно использовать бинарный поиск. Там есть много нюансов, нообщая схема такая. Мёрж работает только если система смогла определить фомат лога ивкаждой записи задан полный тайстемп.

Наданный момент, нетUI для выбора файлов наразных нодах, приходится прописывать файлы впараметрах URL втаком виде:
http://localhost:8111/log?path=/opt/my-app/logs/a.log@hostname1&path=/opt/my-app/logs/b.log@hostname1&path=/opt/my-app/logs/c.log@hostname2
здесь каждый параметр "path" задаёт один файл, после "@" указывается хост, накотором лежит файл изапущен инстанс просмотрщика логов. Можно указать несколько хостов через запятую. Если "@" отсутствует файл находится натекущей ноде. Чтобы неиметь дела согромными URL, есть возможность задать короткие ссылки вконфигурации, вразделе log-paths = { }.

Встраивание просмотрщика в своё приложение

Log Viewer можно подключить ксвоему Java Web приложению как библиотеку, чтобы оно могло показывать пользователю свои логи. Иногда это удобней чем запуск отдельным приложением. Достаточно просто добавить зависимость на библиотеку библиотеку черезMaven/Gradle иподключить один конфигурационный класс вspring context. Всё остальное сконфигурится автоматически, log viewer сам распознает какая система логгирования используется ивозьмёт изеёконфигурации расположение иформат логов. ПоумолчаниюUI маппится на/logs, новсё можно кастомизировать. Пока автоматическая конфигурация работает только сLog4j иLogback.

Это тестировалось на маленьком количестве приложений, если у вас возникнут проблемы смело пишите в discussions на GitHub.

Что планируется сделать в будущем

Было бы удобно, если бы была возможность оставлять комментарии к записям. Например, прикрепить номер тикита к сообщению об ошибке. Комментарий должен быть виден всем пользователям и, когда такая же ошибка вылетит в следующий раз, будет понятно что с ней делать.

Есть много идей по мелкому улучшению UI. Например, если в тексте встретился кусок JSON, то хочется чтобы просмотрщик умел показывать его в отформатированном виде, а не одной строкой. Хочется иметь возможность задать фильтр по severity для отдельного класса, а не сразу для всех.

Иногда нет возможности открыть порт на сервере для просмотра логов, есть только SSH доступ. Можно сделать поддержку работы через SSH. Web UI будет подниматься на локальной машине, коннектиться через SSH к серверу и запускать там специального агента. Агент будет принимать команды через input stream и возвращать нужные части лога через output stream.

Буду рад услышать фидбэк.

Подробнее..

Парсинг логов при помощи Fluent-bit

25.03.2021 18:04:40 | Автор: admin

Не так давно передо мной встала задача организации логгирования сервисов, разворачиваемых с помощью docker контейнеров. В интернете нашел примеры простого логгирования контейнеров, однако хотелось большего. Изучив возможности Fluent-bit я собрал рабочий пайплайн трансформации логов. Что в сочетании с Elasticsearch и Kibana, позволило быстро искать и анализировать лог-сообщения.

Цель туториала: организовать логгирование docker контейнеров. Также необходимо структурировать записи логов, и обеспечить поиск и фильтрацию по их полям.

Кому интересно, добро пожаловать под кат)

Необходимы базовые знания bash, docker-compose, Elasticsearch и Kibana.

Обзор используемого стека

Тестовое приложение будем запускать с помощьюdocker-compose.

Для организации логгирования воспользуемся следующими технологиями:

  • fluent-bit- осуществляет сбор, обработку и пересылку в хранилище лог-сообщений.

  • elasticsearch- централизованно хранит лог-сообщения, обеспечивает их быстрый поиск и фильтрацию.

  • kibana- предоставляет интерфейс пользователю, для визуализации данных хранимых в elasticsearch

На Хабре естьобзор стековтехнологий, используемых для логгирования контейнеров. Прежде чем идти дальше предварительно можно с ней ознакомиться.

Подготовка тестового приложения

Для примера организуем логгирование веб-сервера Nginx.

Подготовка Nginx

  1. Создадим директорию с проектом и добавим в нее docker-compose.yml, в котором будем задавать конфигурацию запуска контейнеров приложения.

  2. Определим формат логов Nginx. Для этого создадим директорию nginx c файлом nginx.conf. В нем переопределим стандартный формат логов:

    user  nginx;worker_processes  1;error_log  /var/log/nginx/error.log warn;pid        /var/run/nginx.pid;events {    worker_connections  1024;}http {    include       /etc/nginx/mime.types;    default_type  application/octet-stream;log_format  main  'access_log $remote_addr "$request" '                  '$status "$http_user_agent"';access_log  /var/log/nginx/access.log  main;sendfile        on;keepalive_timeout  65;include /etc/nginx/conf.d/*.conf;}
    
  3. Добавим сервисwebв docker-compose.yml:

    version: "3.8"services:  web:    container_name: nginx    image: nginx    ports:      - 80:80    volumes:      # добавляем конфигурацию в контейнер      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
    

Подготовка fluent-bit

Для начала организуем самый простой вариант логгирования. Создадим директорию fluent-bit c конфигурационным файлом fluent-bit.conf. Про формат и схему конфигурационного файла можно прочитатьздесь.

  1. Fluent-bit предоставляет большое количество плагинов для сбора лог-сообщений из различных источников. Полный список можно найтиздесь. В нашем примере мы будем использовать плагинforward.

    Плагин выводаstdoutпозволяет перенаправить лог-сообщения в стандартный вывод (standard output).

    [INPUT]    Name              forward[OUTPUT]    Name stdout    Match *
    
  2. Добавим в docker-compose.yml сервисfluent-bit:

    version: "3.8"services:  web:    ...  fluent-bit:    container_name: fluent-bit    image: fluent/fluent-bit    ports:      # необходимо открыть порты, которые используются плагином forward      - 24224:24224      - 24224:24224/udp    volumes:      # добавляем конфигурацию в контейнер      - ./fluent-bit/fluent-bit.conf:/fluent-bit/etc/fluent-bit.conf
    
  3. Добавим настройки логгирования для сервисаweb:

    version: "3.8"services:  web:    ...    depends_on:      - fluent-bit    logging:      # используемый драйвер логгирования      driver: "fluentd"      options:        # куда посылать лог-сообщения, необходимо что бы адрес         # совпадал с настройками плагина forward        fluentd-address: localhost:24224        # теги используются для маршрутизации лог-сообщений, тема         # маршрутизации будет рассмотрена ниже        tag: nginx.logs  fluent-bit:    ...
    
  4. Запустим тестовое приложение:

    docker-compose up
    

    Сгенерируем лог-сообщение, откроем еще одну вкладку терминала и выполним команду:

    curl localhost
    

    Получим лог-сообщение в следующем формате:

    [    1616473204.000000000,    {"source"=>"stdout",    "log"=>"172.29.0.1 "GET / HTTP/1.1" 200 "curl/7.64.1"",    "container_id"=>"efb81a754706b1ece6948072934df85ea44466305b326cd45",    "container_name"=>"/nginx"}]
    

    Сообщение состоит из:

    • временной метки, добавляемой fluent-bit;

    • лог-сообщения;

    • мета данных, добавляемых драйвером fluentd.

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

 docker-compose.yml fluent-bit    fluent-bit.conf nginx     nginx.conf

Кратко о маршрутизации лог-сообщиний в fluent-bit

Маршрутизация в fluent-bit позволяет направлять лог-сообщения через различные фильтры, для их преобразования, и в конечном итоге в один или несколько выходных интерфейсов. Для организации маршрутизации используется две основные концепции:

  • тег (tag) - человеко читаемый индикатор, позволяющий однозначно определить источник лог-сообщения;

  • правило сопоставления (match) - правило, определяющее куда лог-сообщение должно быть перенаправлено.

Выглядит все следующим образом:

  1. Входной интерфейс присваивает лог-сообщению заданные тег.

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

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

Очистка лог-сообщений от мета данных.

Мета данные для нас не представляют интерес, и только загромождают лог сообщение. Давайте удалим их. Для этого воспользуемся фильтромrecord_modifier. Зададим его настройки в файле fluent-bit.conf:

[FILTER]    Name record_modifier    # для всех лог-сообщений    Match *    # оставить только поле log    Whitelist_key log

Теперь лог-сообщение имеет вид:

[    1616474511.000000000,    {"log"=>"172.29.0.1 "GET / HTTP/1.1" 200 "curl/7.64.1""}]

Отделение логов запросов от логов ошибок

На текущий момент логи посылаемые Nginx можно разделить на две категории:

  • логи с предупреждениями, ошибками;

  • логи запросов.

Давайте разделим логи на две группы и будем структурировать только логи запросов. Все логи-сообщения от Nginx помечаются тегом nginx.logs. Поменяем тег для лог-сообщений запросов на nginx.access. Для их идентификации мы заблаговременно добавили в начало сообщения префикс access_log.

Добавим новый фильтрrewrite_tag. Ниже приведена его конфигурация.

[FILTER]    Name rewrite_tag    # для сообщений с тегом nginx.logs    Match nginx.logs    # применить правило: для лог-сообщений поле log которых содержит строку    # access_log, поменять тег на nginx.access, исходное лог-сообщение отбросить.    Rule $log access_log nginx.access false

Теперь все лог-сообщения запросов будут помечены тегом nginx.access, что в будущем позволит нам выполнять фильтрацию логов описанным выше категориям.

Парсинг лог-сообщения

Давайте структурируем наше лог-сообщение. Для придания структуры лог-сообщению его необходимо распарсить. Это делается с помощью фильтраparser.

  1. Лог-сообщение представляет собой строку. Воспользуемся парсеромregex, который позволяет с помощью регулярных выражений определить пары ключ-значение для информации содержащейся в лог-сообщении. Зададим настройки парсера. Для этого в директории fluent-bit создадим файл parsers.conf и добавим в него следующее:

    [PARSER]    Name   nginx_parser    Format regex    Regex  ^access_log (?<remote_address>[^ ]*) "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<status>[^ ]*) "(?<http_user_agent>[^\"]*)"$    Types  status:integer
    
  2. Обновим конфигурационный файл fluent-bit.conf. Подключим к нему файл с конфигурацией парсера и добавим фильтр parser.

    [SERVICE]    Parsers_File /fluent-bit/parsers/parsers.conf[FILTER]    Name parser    # для сообщений с тегом nginx.access    Match nginx.access    # парсить поле log    Key_Name log    # при помощи nginx_parser    Parser nginx_parser
    
  3. Теперь необходимо добавить файл parsers.conf в контейнер, сделаем это путем добавления еще одного volume к сервису fluent-bit:

    version: "3.8"services:  web:    ...  fluent-bit:    ...    volumes:      - ./fluent-bit/fluent-bit.conf:/fluent-bit/etc/fluent-bit.conf
    
  4. Перезапустим приложение, сгенерируем лог-сообщение запроса. Теперь оно имеет следующую структуру:

    [  1616493566.000000000,  {    "remote_address"=>"172.29.0.1",    "method"=>"GET",    "path"=>"/",    "status"=>200,    "http_user_agent"=>"curl/7.64.1"  }]
    

Сохранение лог-сообщений в elasticsearch

Теперь организуем отправку лог-сообщений на хранения в elasticsearch.

  1. Добавим два выходных интерфейса в конфигурацию fluent-bit, один для лог-сообщений запросов, другой для лог-сообщений ошибок. Для этого воспользуемся плагиномes.

    [OUTPUT]    Name  es    Match nginx.logs    Host  elasticsearch    Port  9200    Logstash_Format On    # Использовать префикс nginx-logs для логов ошибок    Logstash_Prefix nginx-logs[OUTPUT]    Name  es    Match nginx.access    Host  elasticsearch    Port  9200    Logstash_Format On    # Использовать префикс nginx-access для логов запросов    Logstash_Prefix nginx-access
    
  2. Добавим в docker-compose.yml сервисы elasticsearch и kibana.

    version: "3.8"services:  web:    ...  fluent-bit:    ...    depends_on:      - elasticsearch  elasticsearch:    container_name: elasticsearch    image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2    environment:      - "discovery.type=single-node"  kibana:    container_name: kibana    image: docker.elastic.co/kibana/kibana:7.10.1    depends_on:      - "elasticsearch"    ports:      - "5601:5601"
    

На текущем этапе структура проекта выглядит следующим образом:

 docker-compose.yml fluent-bit    fluent-bit.conf    parsers.conf nginx     nginx.conf

Финальную версию проекта можно найти в репозитории.

Результаты

Благодаря структурированию лог-сообщений мы можем фильтровать их по различным полям, к примеру:

  • показать только лог-сообщения запросов;

  • показать лог-сообщения запросов с http статусом 404;

  • отображать не все поля лог-сообщения.

Пример фильтрации логов. Выполнена фильтрация по значению поля "status", так же выбраны только необходимые в данный момент поля.Пример фильтрации логов. Выполнена фильтрация по значению поля "status", так же выбраны только необходимые в данный момент поля.

Всем спасибо! Надеюсь туториал был полезен.

Подробнее..

Трассировка и логирование в микросервисах как мы втаскивали единый стандарт на 30 независимых команд

20.01.2021 12:12:03 | Автор: admin
Сервисы падали, падают и будут падать

Когда вы быстро растете, микросервисы начинают появляться буквально по щелчку пальцев и в самых неожиданных местах. В таких условиях каждая команда обычно на ходу решает, где, как и какие логи будет складывать. Когда сначала 10, потом 20, а там и более команд логируют по-своему, начинается хаос.



Например, наша команда сопровождения маркетинга в Skyeng знала: пользователь с таким-то айдишником нажал в личном кабинете кнопку Сменить преподавателя постучался в наш сервис, дальше ушло три сообщения, в очереди было 2 вызова сервисов и эти сервисы ответили 200. Но на самом деле, что было у команд сопровождения учителей или биллинга, к которым мы стучались, не знал никто

Тогда мы придумали инструмент, чтобы маркировать трафик


В компании есть стандарт окружения: PHP 7.x, Symfony 4.x, RabbitMQ для системы сообщений, GuzzleHTTP для внешних и своих ip, Docker. Благодаря тому, что нам более-менее известно, что будет в каждой команде, мы написали библиотеку, которая помогла бы сделать трассировку запроса по всей системе с первого клика.

У нас два основных транспорта HTTP и RabbitMQ. Запрос приходит или от пользователя, или по cron.

  • Мы берем любой HTTP-запрос, а прежде чем прокинуть дальше, добавляем заголовок request-id от NGINX, у которого возможность генерации вшита прямо в модуле.
  • В случае с cron, сами генерируем request-id внутри нашего бандла.

Дальше прокидываем request-id всем следующим получателям в нашем облаке:

  • Автоматически добавляем в Guzzle-клиент для продолжения передачи request-id через HTTP при синхронных запросах к нашим сервисам.
  • Автоматически добавляем request-id ко всем AMQP-продюсерам для асинхронных запросов к нашим сервисам.
  • Также во всех местах, куда мы вклиниваемся для отправки, прикручен Jaeger opentracing это поможет построить всё дерево/карту запросов. Таким образом наш внутренний request-id в качестве атрибута уходит в трейсы opentracing.

Opentracing, маркировка через request-id и складывание в правильные места первые шаги к тому, чтобы в компании появились хорошие логи. Когда команды подключат нашу библиотеку, схема выше начнет работать: request-id начнет передаваться по HTTP и AMQP, каждый сервис будет знать, в рамках какого глобального запроса он сейчас работает. И мы увидим, как запросы расползаются по нашей инфраструктуре.

Логирование inspired by Java


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

В PHP нет таких аннотаций, поэтому многие прокидывают в конструктор логеры, как дополнительную зависимость. Нам не нравился такой подход, поэтому мы сделали trait, который служит почти как аннотация (т.к. мы используем Symfony, то trait опирается на функционал autowiring в результате получается практически как в Java).

Что мы логируем? Помимо request-id, это:

  • runtime-id и process-id идентификаторы текущего потока и процесса, внутри которых может обслуживаться несколько request-id,
  • user-id так как в приложениях есть авторизация, этот идентификатор должен быть везде,
  • имя канала канал можно использовать как бэкап для пользователя, если отвалилась база данных и что-то не записалось.
  • id контейнера, id сервиса, id задачи и прочее все возможные мета-данные о Docker-контейнере. Зачем? У нас был момент, когда приложение было раскатано на 3 контейнера, а взял и сглючил один конкретный, потому что он был развернут на глючном воркере.
  • Цепочки исключений на уровне базы, сервиса, всегда создаем исключения более высокого уровня, потому что часто именно в последнем исключении и кроется А что было-то?.
  • имя приложения в процессе оказалось, что многие команды ориентируются на имя репозитория, а приложение внутри не знает, как его зовут: пришлось дособирать эту информацию и дописывать upname в yaml-файл.
  • плюс служебные команды и переменные окружения.

Также есть вещи, которые можно записать заранее: запуск контроллера, запуск консьюмера. Можно заранее проставить уровень debug он не будет попадать никуда, но если нужно, сможете включить на тестинге или на проде, посмотреть, что у вас происходит вплоть до запросов в базу.

В чем хранить логи на проде и тестингах


На приложения у нас заводится New Relic, но мы дополнительно остановились на разделении записей между Sentry и Kibana.

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



Наша панелька с небоскребами если они растут, значит, кто-то сегодня закончит работу попозже.

Если ткнуть глубже, видно, какие пользователи были затронуты, графики, какой браузер, теги, версия PHP статистики очень много. Плюс можно сразу сделать таску в Jira из ошибки, настроить алерты, назначить ответственных, которым придет оповещение.



Самое главное не класть ошибки, которые вы не собираетесь править. Например, access denied сюда не летит.

Но в Sentry есть и свой минус он не очень хорошо справляется с большим потоком. Если вы, например, поделили на 0 и выкатили в прод, хранилище может лечь. Плюс надо помнить о том, что ошибка в одном сервисе может породить вал ошибок в другом сервисе. Решение этой проблемы выходит за тему статьи, но в целом смотрите в сторону паттерна circuit breaker.

Лог всего, что не ошибки, мы прокидываем как JSON в Kibana. Для этого сборщик Beats ходит, собирает файлы, наш модуль для Filebeat отправляет их в Elasticsearch, а дальше мы уже в Kibana все вычитываем. Правильнее было бы вычитывать логи с вывода контейнера и местами мы так и делаем.



Наша Kibana Выглядит она как Kibana хороший полнотекстовый поиск, свой язык запросов, всякие поля.

Хранится все: лог действий пользователя в контроллерах, начало и конец запроса в консьюмере, реббитовые запросы, работа бизнес-логики. А сбоку есть Grafana, по ней можно построить разные метрики.

Итак, мы молодцы. Сделали полезную вещь. Что должно было быть результатом этих действий? Все команды начнут использовать единообразные библиотеки как часть ядра. Все, от саппорта до CTO, будут знать, где, как искать и что искать в логах. А единая система алертов сделает жизнь еще прекраснее Внедряем? Да, но есть нюанс.

Куда вас пошлют Пошаговый разбор, как внедрить у себя


Зато понимающие люди будут говорить: Он внедрил логи по всей компании

Внедрение это не про технологии и код. А про политику. Ситуация, когда одна из команд сделала что-то, что неплохо-было-бы затащить к себе и другим, встречается часто. Но у других уже планы и приоритеты на месяцы вперед. У нас тут демократия кроме критичных вещей вроде единого окружения никто никому ничего не навязывает.

Чтобы логи стали единообразными, их идею надо продать. Вот какую многоходовочку соорудили мы.

Шаг 0. Начните с себя. Чтобы показать другим, как это классно, легко и красиво, вам нужно тестовое внедрение. Мы начали с собственной команды в маркетинге как раз было около 20 сервисов. Заодно поняли, какие вопросы и сложности скорее всего возникнут и начали готовиться к ним.

  • Например, сделали документацию с примерами и типовыми кейсами: как искать по логам, что делать, если нужен свой канал. Часть кейсов оказалось удобнее показать на уровне видео. Да, это значит, нужно делать презентацию, писать видео но в итоге оно того стоит.

Шаг 1. Вы идете к CTO и тимлидам. Вы думаете на языке PHP, они уже бизнесом, фичами, деньгами. Аргументируйте на их языке:

  • С библиотекой все будет быстрее подниматься, снизим шанс падения по той же причине, в бизнесе заложено, что что-то упало. Теперь заложим, с какой скоростью оно встает: performance, скорость восстановления это бизнес-метрики.
  • Будет проще новичкам, бизнесу зачастую проще нанять дополнительных разработчиков, чем перекидывать людей с других проектов. Но когда компания построена на микросервисах, часто получается, что единообразия в версиях ядра нет. Библиотека дает хотя бы частичное единообразие.

Шаг 2. Ок, зашли к начальству и возбудили его. Теперь приходим к командам. Их первая и естественная реакция тебя послать, потому что ты вроде как принес им дополнительной работы, а начальство теперь может спрашивать про логи.

  • Красота и удобство Sentry продают. Начните с них.
  • Минимизируйте телодвижения разработчиков. Именно поэтому мы выбрали уровень библиотеки. Если делать здоровые конфиги или правила, из-за которых придётся менять код, никто этого делать не будет. А здесь мы сами написали бандлы, которые в большинстве своем конфигурируют себя сами и сами встраиваются, куда им надо. Их можно встраивать без конфигурации вообще но если надо, их конфигурацию можно перекрыть.
  • Плюс удобный trait для добавления логера, документация с заранее объявленными каналами, готовыми примерами доработок и расширения конфигов. Так, чтобы не надо было городить что-то свое при внедрении.

Да, часть рабочего времени в ближайшие месяцы вы все равно будете просто ходить по командам, спрашивать А как оно там?, делать ревью внедрения и так далее. Но поверьте, оно того стоит.

p.s. Пост основан на опыте и рассказах Вани, Макса и Димы, которые вместе делали этот проект. Мы не придумали, от чьего аккаунта это публиковать, и залили от аккаунта компании. В комментариях ребята готовы ответить от своих аккаунтов.

p.p.s. В посте использованы цитаты из докладов Макса и Вани про этот проект.
Подробнее..

5 причин, которые заставят тебя использовать Kibana

19.06.2021 02:15:45 | Автор: admin

Во многих компаниях для сбора и анализа логов используют такой инструмент как Kibana. Но существует проблема которая выражается в том, что этим инструментом редко или почти не пользуются. Почему же так происходит? Дело в том, что человек привык анализировать логи непосредственно на инстансе. Читать логи так сказать из первоисточника. Безусловно это самый лучший способ. И мало кто не любит менять свои привычки. Потому что это своего рода выход из зоны комфорта и к этому не все и не всегда готовы.

Кейсы чтения логов

Но бывают ситуации, когда нет возможности зайти непосредственно на инстанс. Например необходимо проанализировать инцидент случившийся на продакшене и у нас нет доступа к этому окружению по известным всем причинам. Другая ситуация, если сервис работает на операционной системе Windows, а доступ нужен для трех и более сотрудников одновременно. Как мы все хорошо знаем у компании Windows есть политика одновременной работы не более двух человек при входе по RDP (Remote Desktop Protocol). Для того чтобы получить одновременный доступ по RDP большему количеству сотрудников, необходимо купить лицензию, а на это готова пойти далеко не каждая компания.

Стек ELK

Таким образом мы возвращаемся к нашему замечательному инструменту Kibana. Kibana это часть стека ELK, в который помимо неё входят Elasticsearch и Logstash. Kibana используется не только для визуализации данных в различных форматах, но также и для быстрого поиска и анализа логов. И сегодня речь пойдет о том, как комфортно перейти на этот инструмент и какие у него есть скрытые возможности для этого.

Способы и лайфхаки

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

Так же можно составлять сложные поисковые запросы. Существует специальный язык запросов, называемый KQL (Kibana Query Language). С помощью этого языка можно составлять многоуровневые запросы, которые помогают отфильтровывать нужную информацию. Например можно выбрать тестовое окружение и задать конкретное его имя. Если необходимо найти какое-нибудь словосочетание, то нам на помощь приходят двойные кавычки. При заключении двух и более слов в двойные кавычки происходит поиск всей фразы целиком.

Более подробную информацию по составлению сложных запросов можно найти на официальном сайте elastic. Для тех кто привык изучать логи в хронологическом порядке, в Kibana тоже есть такая возможность. При нахождении конкретной ошибки в нашем логе, хотелось бы увидеть что происходило до этого и после. Для этого необходимо кликнуть на найденный фрагмент лога и далее нажать на Просмотр. Перед вами откроется список логов, в котором ваш запрос будет подсвечен серым цветом. И будет загружено несколько строчек лога которые предшествовали нашей ошибке.

Эти логи будут внизу. И несколько строчек которые были после нашей ошибки. Эти строчки будут выше нашей ошибки. В Kibana логи читаются снизу вверх в отличии от логов на инстансе, где логи идут сверху вниз. По умолчанию загружаются 5 строчек до и 5 после, но это значение можно изменить и затем нажать кнопку Загрузка. После чего произойдет загрузка указанного количества строк лога выше нашей ошибки. Тоже самое можно сделать и с предыдущими логами.

Дефолтное значение 5 можно изменить в настройках системы перейдя Stack Management > Advanced Settings

Заключение

В данной статье я не преследовал цель научить пользоваться инструментом Kibana. В интернете очень много подробных статей и видео об этом. Да и на официальном сайте elastic есть предостаточно информации. Мне хотелось показать, как комфортно и без особых усилий можно начать пользоваться другим способом чтения логов. И при этом можно решить одновременно несколько задач, начиная от выхода из зоны комфорта и заканчивая сложнейшими запросами в совокупности с быстродействием получения результата.

Подробнее..

Перевод Использование JSON в Kibana поиске

24.04.2021 02:16:28 | Автор: admin

При поиске из Kibana вы обычно вводите фактическую строку запроса в верхнюю панель, как мы видели это в уроке. Если строки запроса недостаточно для того, что вам нужно, у вас также есть возможность написать JSON в этой строке.

Вы можете записать JSON-объект, который вы бы прикрепили к ключу "query (запрос)" при взаимодействии с Elasticsearch в этом поле, например:

{ "range": { "numeric": { "gte": 10 } } }

Это было бы эквивалентно записи numeric:>=10 в это поле. Чаще всего это имеет смысл только в том случае, если вам нужен доступ к опциям, которые доступны только в JSON-запросе, но не в строке запроса.

Предупреждение: если вы впишете JSON query_string в это поле (например, потому что хотите иметь доступ к lowercase_expanded_terms), Kibana сохранит правильный JSON для запроса, но снова покажет вам (после нажатия клавиши enter) только часть запроса вашего JSON. Это может быть очень запутанным и, конечно, если Вы сейчас введете текст и нажмете enter еще раз, он также потеряет параметры, которые Вы установили через JSON, так что это действительно должно быть использовано с осторожностью.

Особые случаи

В этом разделе должны быть затронуты еще несколько особых случаев, о которых можно подумать: "Я прочитал весь учебник, я все понял, но все равно мой запрос не находит тех данных, которые я ожидал от него получить".

Elasticseach не находит термины в длинных полях.

Это, по моему опыту, довольно распространенная проблема, и ее непросто решить, если вы не знаете, что ищете.

Elasticsearch имеет параметр ignore_above, который вы можете установить в отображении для каждого поля. Это числовое значение, которое приведет к тому, что Elasticsearch НЕ будет индексировать значения дольше, чем задано значением ignore_above, когда будет вставлен документ. Значение все равно будет сохранено, поэтому при просмотре документа вы его увидите, но не сможете найти.

Как проверить, установлено ли это значение в поле? Вам нужно получить отображение из Elasticsearch, вызвав <your-elasticsearch-domain>/<your-index-name>/_mapping. В возвращаемом JSON где-то будет отображение для искомого поля, которое может выглядеть следующим образом:

"fieldName": {  "type": "string",  "ignore_above": 15}

В этом случае значения выше 15 символов не индексируются, и их поиск невозможен.

Пример: Используя вышеприведенное отображение, давайте вставим два документа в этот Elasticsearch:

{ "fieldName": "short string" }{ "fieldName": "a string longer as ignore_above" }

Если вы теперь перечислите все документы (в Kibana или Elasticsearch), то увидите, что оба документа находятся там и значение обоих полей - это то, что вы вставили в строку. Но если вы теперь будете искать fieldName:longer, вы не получите никаких результатов (в то время как fieldName:short вернет первый документ). Elasticsearch обнаружил, что значение "строка длиннее чем ignore_above" длиннее 15 символов, и поэтому оно сохраняет его только в документе, но не индексирует его, поэтому вы не сможете искать в нем ничего, так как в инвертированном индексе для этого поля не будет содержимого этого значения.

Поиск требует определенного поля, без которого он не работает.

Если вы можете выполнить поиск, например, для author:foo, но не для foo, то, скорее всего, это "проблема" с вашим default_field. Elasticsearch предваряет поле по умолчанию перед foo. Это поле можно настроить так, чтобы оно отличалось от _all.

Возможно, настройка поля index.query.default_field была установлена на что-то другое, и Elasticsearch не использует поле _all, что может привести к проблеме.

Также возможно, что поле _all ведет себя не так, как вы ожидали, потому что оно было настроено каким-то другим образом. Вы можете исключить конкретные поля из поля _all (например, в приведенном выше примере fieldName могло быть исключено из индексации в поле _all) или были изменены опции анализа/индексации в отображении поля _all.


Уже сейчас в OTUS открыт набор на новый поток курса "DevOps практики и инструменты". Перевод данного фрагмента статьи был подготовлен в рамках набора на курс.

Также приглашаем всех желающих посетить бесплатный вебинар, на котором эксперты OTUS расскажут о ситуации на рынке DevOps и карьерных перспективах.

ЗАПИСАТЬСЯ НА ВЕБИНАР

Подробнее..
Категории: Devops , Json , Kibana , Блог компании otus

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru