В начале не было ничего. И создал DevOps кластер Kubernetes и сказал, что это есть хорошо. Но пришли злые программисты и начали требовать информацию о том, сколько ресурсов потребляют их контейнеры.
Привет, Хабр! Меня зовут Юра, я DevOps-инженер команды разработчиков платформы контейнеризации dBrain. В этой статье рассмотрим различия между статической и динамической конфигурацией в vmagent от Victoria Metrics (как мы собирали свой универсальный стек системы мониторинга, читайте здесь).
Если имеешь маленький кластер, то хочется схитрить и сделать его обслуживание быстрым и легким, но как говорится, всегда есть нюанс. Когда наши кластеры состояли всего из нескольких нод, конфигурация для сбора метрик была статической. Это казалось удобным и простым, но все рано или поздно приходится пересматривать.
Начнем с технической части. Стек Victoria Metrics в кластерной версии выглядит следующим образом: vmagent, vminsert, vmselect, vmstorage, vmalert, vmauth (опционально).
Конечно, найдутся те, кто спросит: “А как же vmgateway, vmrestore, vmbackup, vmmanager и прочие vm’ы”? Мы им ответим, что шекели не бесконечные и их нужно экономить.
Приступим к обзору. На мой взгляд, архитектура стека Victoria Metrics больше укладывается в современные реалии, чем стандартный Prometheus, где сбор, хранение и пересылка метрик заложены внутри самой системы мониторинга.
vmagent - сбор, релейблинг и пересылка метрик;
vminsert - прием метрик (если хотите отказоустойчивость, то репликация и запись в базу);
vmselect - чтение из базы метрик;
vmstorage - база метрик;
vmalert - алертинг и рекординг (легальный способ сделать мультиретеншен, но об этом в следующих статьях);
vmauth - auth прокси.
Этого набора компонентов достаточно для покрытия уймы требований к стеку мониторинга. Осталось только заставить их работать сообща.
Статическая или динамическая конфигурация?
Сегодня разберем vmagent. Статическая конфигурация:
- job_name: foo
static_configs:
- targets: ["x.x.x.1:8429"]
Простейшая джоба для сбора метрик с vmagent с условным адресом x.x.x.1. Выглядит круто: три строки - и готово. Здесь я, конечно, согласен. А если у нас появится еще парочка vmagent’ов? Мы просто добавим их в конфигурацию. Допустим, появился vmagent-1 и vmagent-2.
- job_name: foo
static_configs:
- targets: ["x.x.x.1:8429", "x.x.x.2:8429", "x.x.x.3:8429"]
Что ж, ничего сложного пока нет. Идем дальше. С тремя vmagent’ами справились, но как быть с пользовательской нагрузкой?
Добавим джобу и для пользовательской нагрузки:
- job_name: client-1
static_configs:
- targets: ["x.x.x.y:8429"]
- job_name: client-2
static_configs:
- targets: ["x.x.x.z:8429"]
- job_name: foo
static_configs:
- targets: ["x.x.x.1:8429", "x.x.x.2:8429", "x.x.x.3:8429"]
Тоже кажется, что проблем нет. Подумаешь, пару секций, все же здорово, зачем нам хваленая динамическая конфигурация?
Тогда смоделируем более приближенную к реальной ситуацию. Например, нужно мониторить поды, которые при рестартах меняют свои ip, скажем, их будет 20. Что же делать в этой ситуации? Ответ один: переходить на динамическую конфигурацию - kubernetes_sd_config.
Статическая конфигурация хороша, когда целей немного и адреса не меняются. К плюсам статической конфигурации можно отнести простоту и удобство. Нужно добавить на тестовом окружении стороннюю точку сбора метрик, временный сервер для тестов, url на проверку? Добро пожаловать в статическую конфигурацию.
При настройке мониторинга внутри Kubernetes будем разбираться с динамической конфигурацией. Суть проста. Берем целевой ресурс (сервисы, поды, ноды или что-нибудь другое из доступных опций конфига) и фильтруем по заданным правилам. Выполняем несколько магических манипуляций с релейблингом, редактируем адреса - и готово: получаем только нужные нам для сбора цели.
Для разнообразия вставлю список vmagent динамических конфигураций:
azure_sd_configs is for scraping the targets registered in Azure Cloud. See these docs.
consul_sd_configs is for discovering and scraping targets registered in Consul. See these docs.
consulagent_sd_configs is for discovering and scraping targets registered in Consul Agent. See these docs.
digitalocean_sd_configs is for discovering and scraping targets registered in DigitalOcean. See these docs.
dns_sd_configs is for discovering and scraping targets from DNS records (SRV, A and AAAA). See these docs.
docker_sd_configs is for discovering and scraping Docker targets. See these docs.
dockerswarm_sd_configs is for discovering and scraping Docker Swarm targets. See these docs.
ec2_sd_configs is for discovering and scraping Amazon EC2 targets. See these docs.
eureka_sd_configs is for discovering and scraping targets registered in Netflix Eureka. See these docs.
file_sd_configs is for scraping targets defined in external files (aka file-based service discovery). See these docs.
gce_sd_configs is for discovering and scraping Google Compute Engine targets. See these docs.
http_sd_configs is for discovering and scraping targets provided by external http-based service discovery. See these docs.
kubernetes_sd_configs is for discovering and scraping Kubernetes targets. See these docs.
kuma_sd_configs is for discovering and scraping Kuma targets. See these docs.
nomad_sd_configs is for discovering and scraping targets registered in HashiCorp Nomad. See these docs.
openstack_sd_configs is for discovering and scraping OpenStack targets. See these docs.
static_configs is for scraping statically defined targets. See these docs.
yandexcloud_sd_configs is for discovering and scraping Yandex Cloud targets. See these docs.
Cntrl+C, Cntrl +V из официальной документации.
Вернемся к нашему старому примеру с vmagent, переведем статическую конфигурацию в динамическую.
Статическая конфигурация:
- job_name: foo
static_configs:
- targets: ["vmagent:8429"]
Динамическая:
- job_name: monitoring
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [ __meta_kubernetes_pod_annotation_monitoring_scrape ]
action: keep
regex: "true"
О чудо, проблема со скейлингом и плавающими адресами решена. Каждый под, который содержит аннотацию monitoring/scrape: true, будет помечен как цель для сбора.
Навешиваем аннотацию на все поды Victoria Metrics и радуемся жизни? Не так быстро.
Внимательные читатели уже видят проблему. Если мы пометим этой аннотацией все компоненты мониторинга, а не только vmagent, то возникнет проблема с портами и путями сбора метрик - где-то /metrics, где-то actuator/prometheus и т.д.
Давайте решать это как раз с помощью манипуляций над релейблингом. На этом стейдже мы можем не только фильтровать, но и править :) Добавим в наши аннотации два компонента - поле, содержащее порт, и путь сбора метрик.
Приведу сразу готовую конфигурацию, но отмечу, что есть много вариантов сделать такую джобу, вплоть до regex по имени сервиса из неймспейса мониторинга и сбор по endpoint’ам на порте, помеченном для мониторинга. У нас же просто конфиг для подов с аннотацией:
- job_name: monitoring
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [ __meta_kubernetes_pod_annotation_monitoring_scrape ]
action: keep
regex: "true"
- source_labels: [__address__, __meta_kubernetes_pod_annotation_port]
action: replace
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
target_label: __address__
- source_labels: [__meta_kubernetes_pod_node_name]
target_label: hostname
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: kubernetes_namespace
- source_labels: [__meta_kubernetes_pod_name]
action: replace
target_label: kubernetes_pod_name
- source_labels: [__meta_kubernetes_pod_annotation_metric_path]
action: replace
target_label: __metrics_path__
regex: (.+)
Теперь разберем по частям что, куда и зачем.
- source_labels: [ __meta_kubernetes_pod_annotation_monitoring_scrape ]
action: keep
regex: "true"
Данную часть мы уже разобрали - это фильтр. Остаются только поды с аннотацией. Но где же мы решаем проблему с портами? Тут все просто, нужно немного магии. Следите за руками, как говорится :)
- source_labels: [__address__, __meta_kubernetes_pod_annotation_port]
action: replace
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
target_label: __address__
Здесь есть внутренне поле __address__, которое как раз и отвечает за адрес:порт. При помощи нехитрой регулярки (или хитрой, если не знать регулярки) мы вытаскиваем из адреса непосредственно порт и заменяем его на тот, который был в аннотации пода.
Идем дальше.
- source_labels: [__meta_kubernetes_pod_node_name]
target_label: hostname
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: kubernetes_namespace
- source_labels: [__meta_kubernetes_pod_name]
action: replace
target_label: kubernetes_pod_name
Здесь из меты Kubernetes мы просто проставляем лейбл хостнейма, неймспейса и названия пода на метрику.
Потом тем же способом, что и с адресом, во внутреннюю переменную __metrics_path__ пишем то, что было в аннотации пути сбора.
- source_labels: [__meta_kubernetes_pod_annotation_metric_path]
action: replace
target_label: __metrics_path__
regex: (.+)
Таким образом, с помощью одной джобы мы всегда будем собирать метрики с компонентов стека Victoria Metrics. При этом не важно поменялись ли адреса или стало больше или меньше реплик какого-нибудь сервиса. У нас всегда будет актуальная конфигурация.
Чем хороша динамическая конфигурация? Да просто это удобно, ведь сокращается количество действий для поддержания ее в актуальном состоянии и еще много прочих плюшек. А избавление от кейсов, когда разработчики что-то изменили, а тебе приходится руками менять пути, адреса, количество - всегда хорошо. Экономьте свое время и занимайтесь полезными вещами.
И небольшой бонус в конце - ссылка на сообщество Victoria Metrics. Здесь много интересного о системе мониторинга, а участники сообщества могут помочь решить вопрос по мониторингу просто так, за плюсик в карму.