Разберём как при помощи VictoriaMetrics замониторить kubernetes. Откуда собирать метрики и как автоматически обнаруживать новые цели. Черная магия релейблинга и как она работает. Аннотации для мониторинга приложений и что делать когда их гибкости не хватает




Всем привет! Меня зовут Николай Храмчихин. Я работаю разработчиком в компании VictoriaMetrics.


VistoriaMetrics – это быстрая и простая в установке база данных временных рядов с открытым исходным кодом



Сегодня я расскажу:


  • О сборе метрик из Kubernetes,


  • О том, как это устроено у нас изнутри,


  • И о том, как это можно использовать вам.




Есть небольшие requirements для базового знания Kubernetes. Я на слайде привел картинку из официальной документации.


Что такое Kubernetes в двух словах? Kubernetes – это открытое программное обеспечение для автоматизации развертывания, масштабирования и управления контейнеризированными приложениями.


Он состоит из рабочих уpлов – worker nodes, на которых запускаются пользовательские приложения и Kubernetes Control Plane, который отвечает за работу кластера.



Что там можно мониторить? В первую очередь это сам Kubernetes Control Plane. Центральным его узлом является API-сервер, который хранит свое состояние в базе данных etcd. И к нему подключаются разнообразные системные компоненты. Это Controller Manager, Kebelet, Scheduler и прочее.



Для мониторинга рабочих узлов решения из коробки нет. Kubernetes предоставляет базовую информацию о том, сколько там приложение запрашивает оперативной памяти и CPU, но это не отражает реальную ситуацию. Поэтому самым популярным решением для сбора данных метрик является запуск node-exporter на каждом из worker nodes, который предоставляет эту информацию, собирая ее с самого сервера. Это использование CPU, памяти и прочих разнообразных параметров.



Достаточно важным системным компонентом в Kubernetes Control Plane является Kubelet, который запускается на каждом сервере. Он является связующим звеном между API-сервером и Container Runtime Interface, такими как Docker, Podman. Их сейчас достаточно много появилось. А Container Runtime Interface запускает уже сами контейнеры.


Интересны метрики, которые предоставляет Kubelet находятся на двух API.


  1. Это /metrics, который показывает информацию о взаимодействии с API-сервером, разнообразно примонтированных volumes к этому серверу.


  2. И /metrics/cadvisor, который предоставляет информацию непосредственно по самим контейнерам, т. е. сколько они используют CPU, оперативной памяти в файловой системе, в сетевой системе.




И конечно это сами пользовательские приложения, которые запускаются в кластере Kubernetes. Их тоже можно и нужно мониторить.



Я буду рассматривать сбор метрик с приложений, экспортирующих сами метрики в prometheus text формате.


В этом случае приложение запускает у себя web-сервер, один из endpoint’ов, который отдает эти метрики. А коллектор приходит к этому приложению и http-запросом их забирает.


В control-plane Kubernetes все компоненты отдают метрики в prometheus text формате.



И с помощью VictoriaMetrics Single версии, которая при помощи конфигурационного файла, задаваемым флагом --promscrape.config, будет это собирать.


Но приведенная информация справедлива не только для VictoriaMetrics, но и для vmagent и Prometheus, с которым VictoriaMetrics совместима, можно использовать один и тот же конфигурационный файл.



Небольшой пример. Важная секция – это scrape_configs, в котором описывается каждая из параметров jobs, которые будут забирать эти метрики.


Можно использовать как статичные configs, которые никогда не поменяются, просто задать IP-адрес хоста или его DNS-имя.


Также можно использовать Service Discovery Configs, которые будут динамически получать метрики из Kubernetes и как-то взаимодействовать с этими всеми объектами.



Нужен ли Service Discovery или нет? По идее самым простым способом сбора метрик из Kubernetes – это просто перечислить все нужные targets через static_configs. Это, в принципе, даже будет работать. Вы не каждый день добавляете новый API-сервер или удаляете старый. И в целом адреса для Controller Managers достаточно статичны. А у серверов можно руками поправить, если что.



Но для пользовательских приложений это не работает. Если мы пытаемся описать каждое наше приложение через вычисления его IP-адреса и порта, откуда нужно забирать метрики, то у нас это не очень сильно получится, потому что приложения обновляются. Они могут меняться, и нам нужно будет каждый раз обновлять конфигурационный файл. Это не очень удобно. А на больших объемах это даже может быть невозможно.



Поэтому нам пригодится Service Discovery, который решает эту задачу, автоматически обнаруживая изменения в Kubernetes. Он запускает и останавливает сбор метрик с targets.



Как это происходит. VictoriaMetrics использует Kubernetes watch API, подписываясь на изменение объектов в API Kubernetes и как-то на это реагирует.



Например, если мы подписываемся на изменение подов.


Под – это, наверное, самая маленькая единица API в Kubernetes, которая объединяет несколько контейнеров.


На примере у нас под с именем app-1. Он в каком-то namespace, там есть какие-то labels. И него есть один 80 порт.


После того, как VictoriaMetrics получает ответ от Kubernetes API, она преобразует полученную сущность, в данном случае под, в специальный список labels вида _meta_kubernetes с какими-то параметрами. Например, _meta_kubernetes_pod_name: app-1. Это имя пода. А label из metadata env будет в _meta_kubernetes_pod_label_env: dev с каким-то значением.


И также присутствует специальный label address, куда записывается ip пода и, соответственно, контейнер порт, с которого собирать метрики.



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



Что такое Relabeling, что это за магия? В интернете часто можно встретить гигантские relabeling_configs и как они работают не всегда понятно.


Relabel_cjonfigs – это набор правил, позволяющий выполнять различные операции над labels и их значениями. Каждое из правил выполняется последовательно и зависит от результатов предыдущего.



Что там доступно? Доступная секция – это source_labels, т. е. те labels, над какими нужно проводить операции. Может быть не одна, а несколько labels.


Есть action, который надо выполнить.


Modulus – это специальный модуль для action hashmod. Но он редко используется. Используется в основном для масштабирования и кластеризации собираемых целей.


Regex – это регулярное выражение, по которым должен происходить matching. Возможно использование группы захвата. Например, как здесь. И можно использовать в replacement в специальном поле, где можно поменять значение label.


Separator – это разделитель, потому что для большинства actions, при использовании несколько source_labels они конкатенируются в одну строку с заданным separator’ом. Разделитель по умолчанию – это точка с запятой.


Target_label – это название того label, куда нужно записать результат action.



Какие нам доступны actions? Они делятся на две группы.


  1. Это actions, которые есть в VM и Prometheus:

  • Replace,


  • Keep,


  • Drop,


  • Labelmap,


  • Labelkeep,


  • Labeldrop,


  • Hashmod.



  1. И actions, которые есть исключительно в VM. Они немного расширяют функционал и делают его более удобным. Например, keep_if_equal. Я покажу дальше, как можно его использовать на примере match по порту.


Relabeling-правила можно использовать для:


  • Фильтрации обнаружения targets,


  • Изменения названия labels,


  • Изменения значения labels,


  • Добавления новых labels,


  • Удаления ненужных labels.




Пара простых примеров, как можно использовать relabel_configs.


Мы можем оставить из всех обнаруженных под в кластере Kubernetes только те, которые находятся в namespace default. Для этого мы используем sourcelabels: [ _meta_kubernetes_pod_namespace]. В action мы используем keep – это значит, что нужно отфильтровать только те, которые попадают под нужные нам условия. И в регулярном выражении namespace default.



Также можно обогатить все метрики, которые мы собираем с самого приложения, полезной информацией. Например, из label пода можно достать окружение, в котором он запущен и, например, namespace, в котором он запускается. Для этого нужно использовать source_labels и target_label, куда нужно это написать.



Более подробно ознакомиться с тем, как работает relabeling и на хороших примерах, можно по ссылочке: https://medium.com/@valyaya/cs-8b90fc22c4b2.



Вернемся к Service Discovery. После фазы relabeling, все labels с прификсом __ meta отбрасываются.


Это нужно для того, чтобы снизить нагрузку на базу данных и уменьшить объем информации, которую нужно хранить. Kubernetes экспортирует достаточно большой объем metadata. И если записывать все, то будет 40-60 labels на 1 deploy, что достаточно много. И в 90 % случаев вы их никогда не будете использовать.


Оставить нужные вам labels можно во время relabeling, убрав у них префикс или поменяв на имя, нужное вам.



Какие можно выбирать объекты из API Kubernetes? Они определяются специальной настройкой role.


Это может быть:


  • Pod,


  • Service,


  • Endpoints,


  • Endpointslice,


  • Node,


  • Ingress.



В зависимости от role, VM подписывается на изменение разных объектов и возвращает разные labels.



Давайте рассмотрим, какие role что возвращают.


Первая из них – это pod, которую мы видим на примере. Она возвращает список с элементами labels для каждого container port с ip-адресом этого пода.


На примере есть некий под, у которого 3 порта, один из которых находится в initContainer. И в статусе находится его ip-адрес.


Соответственно, VM на relabeling 3 элемента в списке с ip-адресом этого контейнера и с каждым из портов. Там дополнительная мета-информация из metadata и еще некоторая другая будет.



Role: service тоже достаточно простой. Он подписывается на изменения сервиса. И для каждого из портов этого сервиса создает label c мета-датой сервиса и адресом. Это доменное имя данного сервиса в формате: имя сервиса.namespace.svc и номер порта в порт секции.



Далее идет достаточно интересный role: endpoint. Здесь нужно небольшое дать объяснение, что такое endpoint, потому что обычно руками их никто не создает.


Это специальная сущность в API Kubernetes, которая нужна для связи сервисов и подов. Она отображает состояние подов, насколько они работоспособны, а также позволяет направлять трафик только на работоспособные поды.



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


Это service. Здесь есть его definition, endpoints и сам непосредственно под.


В приведенном примере на сервисе только один порт заэксплужен, это 8429. Соответственно, в endpoint’е он тоже один, а в контейнере два порта.



И это преобразуется в список labels с двумя элементами. Здесь используется не только тот порт, который есть в endpoints, service, но и порт контейнера дополнительный 2003, который нигде не был указан, но у него не будет мета-информации по endpoint.



Endpointslice – это оптимизированная версия endpoints с точки зрения Kubernetes API. Технически она никак не отличается от endpoints, только там меняются названия префиксов для labels с meta_kubernetes_endpoint на meta_kubernetes_endpointslice.


Какие могут быть подводные камни не использования endpoint? Если у вас очень много endpoints, по-моему, больше 1 000, то Kubernetes их обрезает. Соответственно, вы не получите часть endpoints. Насколько я знаю, в следующей версии VM будет логировать данное сообщение с WARN ошибкой, если такое случается.



Следующая роль – это node. Соответственно, worker node в Kubernetes, для которой используется в качестве адреса первый ip-адрес worker node. В нашем случае – это InternalIP. И порт Kubelet, который указан в описании этой ноды. И дополнительная metadata-информация тоже добавляется. Это annotations: some-annotation: value labels. Ее можно использовать.



Наверное, самая мало встречаемая роль – это ingresses. Она в основном нужна для мониторинга. Я много видел примеров с Blackbox Exporter, который мониторил состояние ingresses через Service Discovery.


И она возвращает комбинацию из хостов в rules с каждым из их путей. Соответственно, в адресе остается только host name, а сам path записывается в специальную _ _meta_kubernetes_ingress_path, как видно на примере.



Полное описание для каждой роли и о том, какие labels она возвращает, можно найти на сайте Prometheus.io. Там достаточно хорошая документация на этот счет и много примеров того, что возвращается.



Service Discovery возвращает все поды, но нам не обязательно собирать с них метрики, а, может, они их и не отдают.


Самым популярным решением для фильтрации данных подов является добавление специальной аннотации Prometheus.io/scrape: “true” в metadata.annotations объекта. В данном случае это в template пода в deployment указывается, что нужно собирать метрики.



Магическим образом это не работает. Kubernetes не знает про это ничего, поэтому нужно использовать специальный конфигурационный файл для scraping, в котором можно фильтровать по мета-информации из annotation. Мы используем _ _meta_kubernetes_pod_annotation_prometheus_io_scrape с regex: true.



Дополняют эту аннотацию две другие аннотации. Это prometheus.io/port с номером порта, который нужно использовать для scraping. И prometheus.io/path, откуда эти метрики нужно забирать.


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


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



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


Если мы будем использовать эту аннотацию, то будут собираться метрики с трех портов, хотя initContainer уже не работает. И будет возвращаться ошибка.



К сожалению, prometheus.io/port тоже не сильно здесь поможет, потому что он будет фильтровать только по одному порту, а с другого мы уже данные получать не можем. В Prometheus есть интересный issues по этому поводу. К сожалению, здесь у меня ссылочки нет.



Как это можно решить? Можно использовать кастомные аннотации, т. е. создать prometheus.io/scrape: “true”, который будет собирать все метрики только с контейнеров, у которых один порт экспортирует метрики и отдельную config-секцию, которая будет по другой аннотации собирать либо с нескольких портов по их номерам, либо со всех, которые доступны. Это может быть не совсем удобно.



А можно создать под каждое приложение в конфигурационном файле отдельную секцию с именем этого приложения, с фильтрацией по какому-то из его labels для имени. И, соответственно, с указанием того порта, откуда нужно собирать метрики.


В примере используется endpoints, соответственно, с endpoints, на который экспортирует сервис.



Как можно решить еще? VictoriaMetrics operator – это последний подход. Он автоматизирует процесс генерации таких конфигурационных файлов для ваших приложений и дописывает нужные relabeling-правила, обогащая мета-информацией метрики с собираемого приложения. Ссылочка на него здесь есть.



Как он работает? Он использует Custom Resource Definitions. Это специальные объекты, расширяющие API Kubernetes через Custom Resource. И уже нужно описывать мониторинг в самом приложении через этот Custom Resource, и у вас все будет работать.



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



И посмотрим, как это можно сделать.


Слева пример deployment, который описывает состояние самого приложения с именованием портов.


Справа пример VMPodScrape, который позволяет также в YAML-формате описать то, откуда мы будем забирать метрики. Соответственно, здесь у нас есть два порта: http и backup-metrics.



В результате у нас будет сгенерировано две секции scrape в конфигурационном файле, который будет выполнять matching по source_labels с названием того, который есть в deployments, и с именем порта, который указан в самом приложении.



Это только один из примеров использования VMPodScrape. Он также позволяет гибко настроить мониторинг приложения и делегировать эту конфигурацию владельцу приложения.


Таким образом можно построить Git-ops-подход для мониторинга.


Единственное, этот конфигурационный файл генерируется только для VMagent, который управляется оператором. Это нужно знать, это одно из ограничений.



Сегодня мы узнали:


  • Основные цели, с которых можно собирать метрики в Kubernetes.


  • Что такое Service Discovery.


  • Какие проблемы решает relabeling_congig.


  • Как они работают, что для них доступно и как их использовать.


  • Про аннотацию prometheus.io/scrape – ее плюсы и минусы.


  • И кратко рассказал про VM operator, о том, как можно декларативно описывать мониторинг приложения.




Всем, спасибо! Ваши вопросы.


Спасибо большое! Как грамотно интегрировать мониторинг Kubernetes, например, с Service Management, либо с Service Desk для того, чтобы заводить тикеты на те или иные события, в том числе нас интересует мониторинг самого Kubernetes и также master nodes? Вы очень подробно нам рассказали о подах, а как мониторить master nodes и сам Kubernetes как инфраструктуру, чтобы заводить тикеты?


Как я вижу, здесь есть две части. Первая – это та, которая непосредственно собирает метрики. Вторая часть – это та, которая с ними взаимодействует. Под мониторингом этих метрик я подразумеваю какие-то правила, которые выполняются, т. е. насколько этот API-сервер жив или нет.


В экосистеме VM есть vmalert, который выполняет эти правила. И результат он отправляет в Alertmanager. У Alertmanager уже есть достаточно много интеграций, куда дальше передавать эти события, где их можно визуализировать и как ими можно управлять.


Лично я пробовал комбинацию из Alertmanager и alerta, где можно уже assign (назначать) все эти события, нездоровости API-сервера и как-то с ними уже взаимодействовать.


Мы можем интегрировать, например, метрики и события в Zabbix? Либо, к примеру, в Аксиусе напрямую? Kubernetes очень мониторится Prometheus’ом. Можно ли какую-нибудь использовать связку, чтобы эти события продублировать в Zabbix для того, чтобы удобнее было заводить заявки, например, в Аксиусе?


Я понял вопрос. Насколько я знаю, есть проект Glaber. Это практически Zabbix, только лучше. И он дает возможность получать различные бэкенды для хранения и можно интегрировать в VM через Glager для мониторинга.


Понял, большое спасибо!


Привет! Спасибо за доклад! У меня, может быть, вопрос не совсем по теме доклада, но все-таки задам. Какие планы у VM по downsampling?


Я ждал этого вопроса. Спасибо большое! Нам его очень часто задают. Мы над ним работаем. Я надеюсь, сделаем его в каком-то виде к концу года. Пока более точных сроков у меня нет.


Когда появится web-интерфейсы у ваших продуктов?


Он уже есть. Вы можете ознакомиться с документацией. Там есть Web UI. Он достаточно красивым в последнем релизе стал. Там можно скролить, листать, визуализировать метрики. И даже у VMalert появился отдельный UI. Мы над этим работаем, они развиваются.


Здравствуйте! Спасибо за доклад! Как у вас дела обстоят с OpenShift? Есть у вас с ним интеграция?


Лично я тестировал интеграцию с OpenShift при помощи оператора deployment. И он из коробки понимает все то, что генерирует OpenShift и можно это все мониторить, использовать. Насчет визуализации через графический интерфейс OpenShift – я не в курсе. Я не смотрел, но было бы достаточно интересно.


Расскажи, как Виктория падает? Какие есть самые яркие, запоминающиеся кейсы?


В основном пример, когда падает и плохо работает, это кластерная версия. Когда выходит из строя одна из storage node и кластер сильно утилизирован, то он какое-то время может не справляться с нагрузкой, потому что нужно зарегистрировать временные ряды на других storage nodes. Такое бывает, мы с этим работаем. Надеюсь, что все в будущем будет хорошо.


P.S. Чат по VictoriaMetrics https://t.me/VictoriaMetrics_ru1


Немного рекламы: На платформе https://rotoro.cloud/ вы можете найти курсы с практическими занятиями:


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


  1. Nastradamus
    29.10.2021 11:54
    +1

    Спасибо за статью! Отлично подходит как справочник-напоминалка и для тех, кто это уже всё настраивал :)


  1. dlazerka
    01.11.2021 19:55

    После того, как VictoriaMetrics получает ответ от Kubernetes API, она преобразует полученную сущность, в данном случае под, в специальный список labels вида _meta_kubernetes с какими-то параметрами. 

    Так а где узнать список всех доступных _meta_* лейблов?



  1. valyala
    02.11.2021 12:45
    +1

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

    Эта проблема бывает только при условии, если в кластере недостаточно свободных ресурсов для быстрой регистрации новых временных рядов, "переехавших" с вышедшей из строя storage node на оставшиеся в живых storage nodes. Поэтому, чтобы избежать этой проблемы, нужно оставить в кластере достаточно свободных ресурсов (CPU, RAM). См. https://docs.victoriametrics.com/Cluster-VictoriaMetrics.html#capacity-planning