Вивчення конфігурацій збору метрик Prometheus за допомогою подів Kubernetes.
Передумови
Якщо ви хочете слідувати за інструкцією, вам потрібно мати доступ до кластеру Kubernetes (v1.19+). Також вам потрібно встановити Helm (v3.7+) на вашому робочому комп’ютері.
Встановлення прикладного додатку
Ми будемо використовувати прикладний додаток, наданий Google, як джерело метрик.
Встановлюємо його за допомогою наступної команди.
$ kubectl -n default apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/prometheus-engine/v0.13.0/examples/example-app.yaml
Ось ми бачимо три працюючі поди.
Ми можемо підтвердити, що метрики доступні на подах на порту 1234 і кінцевій точці /metrics, використовуючи порт-форвардинг.
$ kubectl port-forward pod/prom-example-7dfd68fd5-nhnrd 8080:1234 -n default
Forwarding from 127.0.0.1:8080 -> 1234
Forwarding from [::1]:8080 -> 1234
І потім, використовуючи браузер, ми дійсно можемо побачити метрики.
Встановлення Prometheus
Хоча можна побудувати власні маніфести Kubernetes для Docker-образу prom/prometheus, це виглядало б як знову винаходити колесо.
Тут я натрапив на Prometheus Operator.
Prometheus Operator — це Kubernetes Operator, що забезпечує нативне розгортання і керування Prometheus та супутніми компонентами моніторингу в Kubernetes.
Дивлячись на це, здалося, що для вивчення нових абстракцій на базі Prometheus знадобиться великий час, а зараз я шукаю простіше рішення.
Зрештою я знайшов, що виглядає як відносно авторитетний Helm чарт — Prometheus, який здалося буде кращим варіантом; він надає всі маніфести для Kubernetes, але ви все ще можете безпосередньо налаштовувати сервер Prometheus.
Дотримуючись наданих інструкцій, ми почнемо з додавання Helm репозиторію.
$ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
$ helm repo update
Ми дійсно можемо здійснити пошук у репозиторії і побачити Helm чарт і версію (використовуючи параметр -l, можна побачити всі версії).
$ helm search repo prometheus-community
...
prometheus-community/prometheus 26.0.1 v3.0.1 Prometheus is a monitoring system and time seri...
...
Замість того, щоб встановлювати Helm чарт з усіма за замовчуванням, ми можемо побачити всі опції конфігурації за допомогою наступної команди.
$ helm show values prometheus-community/prometheus
Вау… Там дуже багато всього.
Переглядаючи варіанти, ми вирішуємо внести дві зміни:
- За замовчуванням конфігурації збору метрик дуже складні; ми почнемо з того, щоб спростити їх до збору метрик тільки з самого сервісу Prometheus.
- Вимикаємо всі підчарти, оскільки ми зосереджені лише на Prometheus.
Для цього створюємо файл values.yaml з наступним вмістом.
serverFiles:
prometheus.yml:
scrape_configs:
- job_name: prometheus
static_configs:
- targets:
- localhost:9090
alertmanager:
enabled: false
kube-state-metrics:
enabled: false
prometheus-node-exporter:
enabled: false
prometheus-pushgateway:
enabled: false
Далі встановлюємо Prometheus за допомогою наступної команди:
helm install myprom prometheus-community
--namespace=monitoring \
--values=values.yaml
Виведення після встановлення зручно надає команду, яку ми можемо використати для підключення до інтерфейсу Prometheus через браузер на нашій робочій станції.
$ export POD_NAME=$(kubectl get pods --namespace monitoring -l "app.kubernetes.io/name=prometheus,app.kubernetes.io/instance=myprom" -o jsonpath="{.items[0].metadata.name}")
$ kubectl --namespace monitoring port-forward $POD_NAME 9090
Ми підтверджуємо, що метрики збираються, виконавши запит up з відповіддю нижче.
Збір метрик з прикладного додатку
Тепер ми переходимо до збору метрик з трьох подів, що працюють у default просторі імен. Оглядаючи розгортання prom-example (а отже, й поди), ми бачимо, що кожен под має лише один контейнер з одним зазначеним портом (1234).
$ kubectl get deployment prom-example -n default -o yaml
...
ports:
- containerPort: 1234
name: metrics
protocol: TCP
...
Також, у нашому тестовому кластері (принаймні у моєму) є лише три поди з розгортання prom-example в default просторі імен.
Рішення полягає в тому, щоб додати другий job у файл values.yaml, який ми створили раніше.
- job_name: 'default-namespace-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_namespace]
action: keep
regex: default
Заглиблюючись у це, ми використовуємо конфігурацію Kubernetes SD:
Конфігурації Kubernetes SD дозволяють отримувати цілі для збору метрик через REST API Kubernetes і постійно бути синхронізованими зі станом кластера.
З роллю pod.
Роль pod виявляє всі поди та виставляє їх контейнери як цілі. Для кожного оголошеного порту контейнера генерується окрема ціль. Якщо контейнер не має зазначених портів, створюється ціль без порту для кожного контейнера, який можна додати вручну через relabeling.
Далі ми використовуємо конфігурацію relabeling:
Relabeling — потужний інструмент для динамічного переписування набору міток цілі перед її збором. Для кожної конфігурації збору метрик можна налаштувати кілька кроків relabeling. Вони застосовуються до набору міток кожної цілі в порядку їхнього появлення в конфігураційному файлі.
І мітку, додану через конфігурацію Kubernetes SD:
_metakubernetes_namespace: Простір імен об'єкта поду.
Значення source_labels тут таке:
Source labels вибирають значення з існуючих міток. Їхній вміст об’єднується
використовуючи вказаний роздільник і порівнюється з вказаним регулярним виразом
для дій replace, keep та drop.
[source_labels: ‘[‘ [, …] ‘]’ ]
та дія keep.
keep: Відкидає цілі, для яких регулярний вираз не збігається з конкатенованими source_labels.
З цією зміною ми можемо оновити реліз Helm.
helm upgrade myprom prometheus-community/prometheus \
--version=26.0.1 \
--namespace=monitoring \
--values=values.yaml
Як і раніше, ми використовуємо браузер для підключення до інтерфейсу Prometheus і, переходячи через меню Status > Target health, можемо побачити три нові очікувані цілі.
Одне важливе зауваження: багато міток, наприклад, __metakubernetesnamespace, не потрапили до збережених міток для кінцевої точки (і, отже, до часових рядів). Це тому, що мітки, що починаються з подвійного підкреслення, не зберігаються; тут є певна тонка магія.
Покращення збору метрик з прикладного додатку
Попереднє рішення вимагало, щоб ми знали багато деталей про поди, з яких ми збираємо метрики, наприклад, серед іншого, нам потрібно було знати, що поди мають лише один контейнер з одним зазначеним портом, на якому доступні метрики за шляхом /metrics.
Покращене рішення полягає в тому, щоб анотувати поди, з яких ми хочемо збирати метрики, достатньою кількістю інформації для правильного збору метрик Prometheus. Хороша новина в тому, що ми можемо повернутися до стандартних значень для scrapeconfigs_ в Helm chart і знайти приклад job, який робить саме це.
Ось коментар, який описує поведінку job kubernetes-pods.
$ helm show values prometheus-community/prometheus
...
# Приклад конфігурації збору метрик для подів
#
# Конфігурація relabeling дозволяє налаштувати фактичну кінцеву точку збору метрик для подів через
# наступні анотації:
#
# * `prometheus.io/scrape`: Збирати метрики тільки з подів, що мають значення `true`,
# якщо тільки `prometheus.io/scrape-slow` не встановлено в `true`.
# * `prometheus.io/scheme`: Якщо кінцева точка метрик захищена, то потрібно встановити значення `https`
# і, ймовірно, налаштувати `tls_config` для конфігурації збору метрик.
# * `prometheus.io/path`: Якщо шлях до метрик не є `/metrics`, потрібно це перекрити.
# * `prometheus.io/port`: Збирати метрики з пода на вказаному порту замість стандартного `9102`.
Для підготовки до використання покращеного рішення нам потрібно повернутися і додати наступні анотації до шаблону поду розгортання.
prometheus.io/scrape: "true"
prometheus.io/port: "1234"
Найпростіший спосіб зробити це — просто відредагувати розгортання:
$ kubectl edit deployment prom-example -n default
Примітка: Після зміни шаблону поду в розгортанні, поди будуть замінені (з анотаціями).
Нарешті, ми замінюємо job default-namespace-pods, який ми створили в останньому розділі, на приклад kubernetes-job, наданий у стандартних значеннях Helm chart (див. нижче).
Як і раніше, ми робимо це, редагуючи файл values.yaml і використовуючи helm upgrade.
Так, це здається надзвичайно складним на перший погляд; ми детальніше розглянемо цю конфігурацію нижче.
- job_name: 'kubernetes-pods'
honor_labels: true
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape_slow]
action: drop
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scheme]
action: replace
regex: (https?)
target_label: __scheme__
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_port, __meta_kubernetes_pod_ip]
action: replace
regex: (\d+);(([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})
replacement: '[$2]:$1'
target_label: __address__
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_port, __meta_kubernetes_pod_ip]
action: replace
regex: (\d+);((([0-9]+?)(\.|$)){4})
replacement: $2:$1
target_label: __address__
- action: labelmap
regex: __meta_kubernetes_pod_annotation_prometheus_io_param_(.+)
replacement: __param_$1
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: namespace
- source_labels: [__meta_kubernetes_pod_name]
action: replace
target_label: pod
- source_labels: [__meta_kubernetes_pod_phase]
regex: Pending|Succeeded|Failed|Completed
action: drop
- source_labels: [__meta_kubernetes_pod_node_name]
action: replace
target_label: node
Як і раніше, ми використовуємо браузер для підключення до інтерфейсу Prometheus і, переходячи через меню Status > Target health, можемо побачити три нові очікувані цілі, і вони тепер мають більше міток.
Давайте детальніше розглянемо це підтвердження. З документації Prometheus Configuration ми дізнаємося, що робить параметр honorlabels_.
honor_labels визначає, як Prometheus обробляє конфлікти між мітками, що вже є в даних,
які зібрані, і мітками, які Prometheus додасть з серверної сторони
(мітки “job” та “instance”, мітки цілей, налаштовані вручну,
та мітки, згенеровані реалізаціями виявлення сервісів).
Якщо honor_labels встановлений в "true", конфлікти міток вирішуються шляхом збереження значень міток
з даних, зібраних під час скрапінгу, та ігнорування конфліктуючих міток серверної сторони.
У цьому прикладі, я не вважаю, що будь-які мітки в зібраних метриках конфліктують з тими, які додаються Prometheus.
Перша конфігурація relabel має дію keep, яку ми бачили раніше; вона зберігає лише ті контейнери, які мають анотацію prometheus.io/scrape, встановлену в true.
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
Тут ми використовуємо той факт, що Kubernetes SD конфігурація додає мітки на основі анотацій Pod; документація пропускає той момент, що неподтримувані символи перетворюються на підкреслення.
_metakubernetespodannotation_: Кожна анотація з об'єкта pod.
Друга конфігурація relabel з дією drop досить зрозуміла; залишаю це для читача для інтерпретації.
Наступні чотири конфігурації relabel використовують дію replace; зосередимося на одній з більш складних, що має відношення до нашого прикладу навантаження.
Зокрема, ця конфігурація дозволяє Prometheus зрозуміти, що треба скрапити порт 1234 на основі анотації pod: prometheus.io/port: "1234".
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_port, __meta_kubernetes_pod_ip]
action: replace
regex: (\d+);((([0-9]+?)(\.|$)){4})
replacement: $2:$1
target_label: __address__
Як і з подібними мітками, які ми спостерігали раніше, дві мітки, що вказані в source_labels, походять від Kubernetes SD конфігурації.
Тут є дія replace.
replace: Співвіднесіть regex з конкатенованими sourcelabels. Потім встановіть targetlabel у значення replacement, замінюючи посилання на групи збігів (${1}, ${2}, …) в replacement їхніми значеннями. Якщо regex не збігається, заміна не виконується.
Дивлячись на регулярний вираз, він створений для збігу рядків типу [PORT];[IPV4_ADDRESS], наприклад, у нашому випадку 1234;10.244.0.34, і збереження порту у змінній $1 і IPv4-адреси в змінній $2.
Є деякі спеціальні мітки, додані Prometheus; одна з них — address, на яку ми звертаємо увагу в цьому прикладі.
Спочатку, окрім налаштованих для кожної цілі міток, мітка job цілі встановлюється у значення jobname відповідної конфігурації скрапінгу. Мітка _address__ встановлюється в : адресу цілі. Після relabeling мітка instance за замовчуванням встановлюється у значення address, якщо не була задана під час relabeling.
Мітки scheme і metrics_path встановлюються відповідно на схему та шлях до метрик цілі, як зазначено в scrape_config.
Тут важливо знати, що змінивши мітки address, scheme та metrics_path, ми фактично вказуємо Prometheus на правильний ендпоінт для скрапінгу.
Наступні дві конфігурації relabel використовують дію labelmap; давайте зосередимося на другій, оскільки вона має відношення до нашого прикладу навантаження.
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
Давайте розглянемо, що робить дія labelmap.
labelmap: Співвіднесіть regex з усіма іменами міток джерела, а не лише з тими, що зазначені в source_labels.
Тепер скопіюємо значення відповідних міток до імен міток, зазначених у replacement, де посилання на групи збігів (${1}, ${2}, …) в replacement замінюються на їхні значення.
У нашому прикладі, контейнери мають дві мітки:
labels:
app.kubernetes.io/name: prom-example
pod-template-hash: 56d645c759
Як зазначено в Kubernetes SD конфігурації:
_metakubernetespodlabel_: Кожна мітка з об'єкта pod, з будь-якими неподтримуваними символами, що замінюються на підкреслення.
Це означає, що ми маємо такі мітки:
- __metakubernetespodlabelappkubernetesioname_
- __metakubernetespodlabelpodtemplatehash
Регулярний вираз фактично зберігає лише те, що йде після metakubernetespodlabel, і ми можемо побачити ці мітки, appkuberenetesioname_ і podtemplatehash, в UI Prometheus.
Залишкова конфігурація relabel використовує знайомі дії replace та drop; залишаю це для читача для інтерпретації.
Уф… Це було багато.
Перекладено з: Prometheus Scraping Configurations by Example