Зараз маємо VictoriaMetrics + Grafana на звичайному EC2-інстансі, запущені з Docker Compose – то був Proof of Concept, прийшов час запускати “по-дорослому” – в Kubernetes, і всі конфіги вже винести в GitHub.
У VictoriaMetrics є чарти під кожен компонент, див. Victoria Metrics Helm Charts, і є чарти для запуску VictoriaMetrics Operator та victoria-metrics-k8s-stack – аналог Kuber Prometheus Stack, який я використовував раніше.
Використовувати будемо саме victoria-metrics-k8s-stack, який “під капотом” запустить VictoriaMetrics Operator, Grafana та kube-state-metrics, див. dependencies.
Матеріал вийшов досить великий, але наче описав всі цікаві моменти по розгортанню повноцінного стеку моніторингу з VictoriaMetrics Kubernetes Monitoring Stack.
UPD: робив документацію по нашому моніторингу, вийшла ось така схема того, про що буде в цьому пості:
Зміст
Планування
Отже, що треба буде зробити:
- перевірити деплой чарту
victoria-metrics-k8s-stack - подивитись і подумати, як запускати існуючі експортери – частина мають чарти, але ми маємо і самописні (див. – Prometheus: GitHub Exporter – пишемо власний експортер для GitHub API), тож їх треба буде пушити в Elastic Container Service і думати, як звідти пулити і запускати в Kubernetes
- секрети для моніторингу – паролі Grafana і все таке інше
- IRSA для експортерів – створити IAM Policy та ролі для ServiceAccounts
- перенесення алертів
- конфіг для VMAgent – збір метрик с експортерів
- запустити Grafana Loki
Стосовно логів – так, нещодавно вийшла VictoriaLogs, але вона ще в preview, не має підтримки збегірання в AWS S3, не має інтеграції з Grafana, та й взагалі поки не хочеться витрачати зайвий час, а Loki я вже більш-менш знаю. Можливо, запущу VictoriaLogs окремо, “погратись-подивитись”, а коли її вже інтегрують з Grafana – то заміню Loki на VictoriaLogs, бо зараз ми вже маємо дашборди з графіками з логів Loki.
Ще окремо треба буде глянути як там з persistance у VictoriaMetrics в Kubernetes – розмір, типи дисків і так далі. Можливо, подумати про їхні бекапи (VMBackup?).
На існуючому моніторингу маємо досить багато всього:
[simterm]
root@ip-172-31-89-117:/home/admin/docker-images/prometheus-grafana# tree . . ├── alertmanager │ ├── config.yml │ └── notifications.tmpl ├── docker-compose.yml ├── grafana │ ├── config.monitoring │ └── provisioning │ ├── dashboards │ │ └── dashboard.yml │ └── datasources │ └── datasource.yml ├── prometheus │ ├── alert.rules │ ├── alert.templates │ ├── blackbox-targets │ │ └── targets.yaml │ ├── blackbox.yml │ ├── cloudwatch-config.yaml │ ├── loki-alerts.yaml │ ├── loki-conf.yaml │ ├── prometheus.yml │ ├── promtail.yaml │ └── yace-config.yaml └── prometheus.yml
[/simterm]
Яке взагалі деплоїти? Через AWS CDK та його cluster.add_helm_chart() – чи робити окремий степ в GitHub Actions з Helm?
Нам в будь-якому разі буде потрібен CDK – створити сертифікати з ACM, Lambda для логів в Loki, S3-корзини, IAM-ролі для експортерів тощо.
Але чомусь зовсім не хочеться тягнути в CDK деплой чартів, бо краще всеж відокремити деплой інфрастуктурних об’єктів від деплою самого стеку моніторинга.
Добре – зробимо окремо: CDK буде створювати ресурси в AWS, Helm буде деплоїти чарти. Чи чарт? Може – просто зробити власний чарт, а йому вже сабчартами підключити і VictoriaMetrics Stack, и експортери? Виглядає наче непоганою ідею. “Мінуси будуть?” (с)
Також нам треба буде створити Kubernetes Secrets та ConfigMaps з конфігами для VMAgent, Loki (див. Loki: збір логів з CloudWatch Logs з використанням Lambda Promtail), Alertmanager тощо. Робити їх з Kustomize? Чи просто YAML-маніфестами в директорії templates нашого чарту?
Подивимось. Поки думаю, що таки Kustomize.
Тепер по порядку – що треба буде зробити:
- запустити експортери
- підключити конфіг до VMAgent, щоб почати збирати метрики з експортерів
- перевірити, як налаштовуються ServiceMonitors (VMServiceScrape у VictoriaMetrics)
- Grafana:
- датасорси
- дашборди
- додати Loki
- алерти
Поїхали. Почнемо з перевірки самого чарту victoria-metrics-k8s-stack.
Встановлення VictoriaMetrics Stack Helm Chart
Додаємо репозиторії с залежностями:
[simterm]
$ helm repo add grafana https://grafana.github.io/helm-charts "grafana" has been added to your repositories $ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts "prometheus-community" has been added to your repositories
[/simterm]
І саму VictoriaMetrics:
[simterm]
$ helm repo add vm https://victoriametrics.github.io/helm-charts/ "vm" has been added to your repositories $ helm repo update Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "vm" chart repository ...Successfully got an update from the "grafana" chart repository ...Successfully got an update from the "prometheus-community" chart repository Update Complete. ⎈Happy Helming!⎈
[/simterm]
Перевіряємо версії чарту victoria-metrics-k8s-stack:
[simterm]
$ helm search repo vm/victoria-metrics-k8s-stack -l NAME CHART VERSION APP VERSION DESCRIPTION vm/victoria-metrics-k8s-stack 0.17.0 v1.91.3 Kubernetes monitoring on VictoriaMetrics stack.... vm/victoria-metrics-k8s-stack 0.16.4 v1.91.3 Kubernetes monitoring on VictoriaMetrics stack.... vm/victoria-metrics-k8s-stack 0.16.3 v1.91.2 Kubernetes monitoring on VictoriaMetrics stack.... ...
[/simterm]
Всі values можна взяти так:
[simterm]
$ helm show values vm/victoria-metrics-k8s-stack > default-values.yaml
[/simterm]
Або просто в репозиторії – values.yaml.
Мінімальний values для VictoriaMetrics chart
У VictoriaMetrics взагалі гарна документація, тож по ходу діла часто будемо користоватись API Docs.
Використаємо VMSingle замість VMCluster – проект у нас маленький, з VictoriaMetrics я тільки знайомлюсь, не хочеться ускладнювати систему.
Створюємо мінімальний конфіг:
# to confugire later
victoria-metrics-operator:
serviceAccount:
create: false
# to confugire later
alertmanager:
enabled: true
# to confugire later
vmalert:
annotations: {}
enabled: true
# to confugire later
vmagent:
enabled: true
grafana:
enabled: true
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/scheme: internet-facing
hosts:
- monitoring.dev.example.co
Деплоїмо в новий неймспейс:
[simterm]
$ helm upgrade --install victoria-metrics-k8s-stack -n dev-monitoring-ns --create-namespace vm/victoria-metrics-k8s-stack -f atlas-monitoring-dev-values.yaml
[/simterm]
Перевіряємо поди:
[simterm]
$ kk -n dev-monitoring-ns get pod NAME READY STATUS RESTARTS AGE victoria-metrics-k8s-stack-grafana-76867f56c4-6zth2 0/3 Init:0/1 0 5s victoria-metrics-k8s-stack-kube-state-metrics-79468c76cb-75kgp 0/1 Running 0 5s victoria-metrics-k8s-stack-prometheus-node-exporter-89ltc 1/1 Running 0 5s victoria-metrics-k8s-stack-victoria-metrics-operator-695bdxmcwn 0/1 ContainerCreating 0 5s vmsingle-victoria-metrics-k8s-stack-f7794d779-79d94 0/1 Pending 0 0s
[/simterm]
Та Ingress:
[simterm]
$ kk -n dev-monitoring-ns get ing NAME CLASS HOSTS ADDRESS PORTS AGE victoria-metrics-k8s-stack-grafana <none> monitoring.dev.example.co k8s-devmonit-victoria-***-***.us-east-1.elb.amazonaws.com 80 6m10s
[/simterm]
Чекаємо оновлення DNS, або просто відкриваємо доступ до Grafana Service – знаходимо його:
[simterm]
$ kk -n dev-monitoring-ns get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE victoria-metrics-k8s-stack-grafana ClusterIP 172.20.162.193 <none> 80/TCP 12m ...
[/simterm]
І виконуємо port-forward:
[simterm]
$ kk -n dev-monitoring-ns port-forward svc/victoria-metrics-k8s-stack-grafana 8080:80 Forwarding from 127.0.0.1:8080 -> 3000 Forwarding from [::1]:8080 -> 3000
[/simterm]
В браузері переходимо до http://localhost:8080/
Username по дефолту admin, отримуємо його згенерований пароль:
[simterm]
$ kubectl -n dev-monitoring-ns get secret victoria-metrics-k8s-stack-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
1Ev***Ko2
[/simterm]
Маємо вже готові дашборди (параметр defaultDashboardsEnabled у values):
Тепер можна думати про інші налаштування.
Створення власного чарту для моніторинг-стеку
Отже, зробимо такий собі “umbrella chart“, який буде запускати і сам стек VictoriaMetrics, і експортери, і створювати всі необхідні Secrets/ConfgiMaps тощо.
Як воно буде працювати?
- створимо чарт
- йому в
dependenciesвписуємо VictoriaMetrics - через тіж
dependenciesдодамо запуск екпортерів - в каталозі
templatesопишемо наші кастомні ресурси (ConfigMaps, VMRules, etc)
Згадаємо, як воно взагалі робиться – Helm Create, Helm: dependencies aka subcharts – обзор и пример, How to make a Helm chart in 10 minutes, One Chart to rule them all – How to implement Helm Subcharts.
Замість helm create – зробимо все руками, бо він нагенерує забагато зайвих файлів.
В своєму репозиторії моніторингу створюємо каталоги:
[simterm]
$ mkdir -p victoriametrics/{templates,charts,values}
[/simterm]
Перевіряємо структуру:
[simterm]
$ tree victoriametrics victoriametrics ├── charts ├── templates └── values
[/simterm]
Переходимо в каталог victoriametrics, створюємо файл Chart.yaml:
apiVersion: v2 name: atlas-victoriametrics description: A Helm chart for Atlas Victoria Metrics kubernetes monitoring stack type: application version: 0.1.0 appVersion: "1.16.0"
Додавання subcharts
Далі додаємо dependencies, починаємо з victoria-metrics-k8s-stack.
Версії вже знаходили, згадаємо яка там була остання:
[simterm]
$ helm search repo vm/victoria-metrics-k8s-stack -l NAME CHART VERSION APP VERSION DESCRIPTION vm/victoria-metrics-k8s-stack 0.17.0 v1.91.3 Kubernetes monitoring on VictoriaMetrics stack.... vm/victoria-metrics-k8s-stack 0.16.4 v1.91.3 Kubernetes monitoring on VictoriaMetrics stack.... ...
[/simterm]
Додаємо з ~ в номері версії, щоб включити патчі до версії 0.17 (див. Dependencies):
apiVersion: v2 name: atlas-victoriametrics description: A Helm chart for Atlas Victoria Metrics kubernetes monitoring stack type: application version: 0.1.0 appVersion: "1.16.0" dependencies: - name: victoria-metrics-k8s-stack version: ~0.17.0 repository: https://victoriametrics.github.io/helm-charts/
Values для сабчартів
Далі, створюємо каталоги для values:
[simterm]
$ mkdir -p values/{dev,prod}
[/simterm]
Копіюємо наш мінімальний конфіг у values/dev/:
[simterm]
$ cp ../atlas-monitoring-dev-values.yaml values/dev/
[/simterm]
Потім всі загальні параметри винесемо в якійсь common-values.yaml, а значення, которі будуть різні для Dev/Prod – по окремим файлам.
Оновлюємо наш values – додаємо блок victoria-metrics-k8s-stack, бо він у нас тепер буде сабчартом:
victoria-metrics-k8s-stack:
# no need yet
victoria-metrics-operator:
serviceAccount:
create: true
# to confugire later
alertmanager:
enabled: true
# to confugire later
vmalert:
annotations: {}
enabled: true
# to confugire later
vmagent:
enabled: true
grafana:
enabled: true
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/scheme: internet-facing
hosts:
- monitoring.dev.example.co
Загружаємо чарти з dependencies:
[simterm]
$ helm dependency update Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "vm" chart repository ...Successfully got an update from the "grafana" chart repository ...Successfully got an update from the "prometheus-community" chart repository Update Complete. ⎈Happy Helming!⎈ Saving 1 charts Downloading victoria-metrics-k8s-stack from repo https://victoriametrics.github.io/helm-charts/ Deleting outdated charts
[/simterm]
Перевіряємо каталог charts:
[simterm]
$ ls -1 charts/ victoria-metrics-k8s-stack-0.17.0.tgz
[/simterm]
І робимо helm template нового Helm-чарту з нашим VictoriaMetrics Stack, щоб перевірити, що сам чарт, його dependencies і values працюють:
[simterm]
$ helm template . -f values/dev/atlas-monitoring-dev-values.yaml
---
# Source: victoriametrics/charts/victoria-metrics-k8s-stack/charts/grafana/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
helm.sh/chart: grafana-6.44.11
app.kubernetes.io/name: grafana
app.kubernetes.io/instance: release-name
...
[/simterm]
Наче ОК – спробуємо задеплоїти – видаляємо старий реліз:
[simterm]
$ helm -n dev-monitoring-ns uninstall victoria-metrics-k8s-stack release "victoria-metrics-k8s-stack" uninstalled
[/simterm]
Service Invalid value: must be no more than 63 characters
Деплоїмо новий:
[simterm]
$ helm -n dev-monitoring-ns upgrade --install atlas-victoriametrics . -f values/dev/atlas-monitoring-dev-values.yaml
Release "atlas-victoriametrics" does not exist. Installing it now.
Error: 10 errors occurred:
* Service "atlas-victoriametrics-victoria-metrics-k8s-stack-kube-controlle" is invalid: metadata.labels: Invalid value: "atlas-victoriametrics-victoria-metrics-k8s-stack-kube-controller-manager": must be no more than 63 characters
[/simterm]
Перевіряємо довжину імені:
[simterm]
$ echo atlas-victoriametrics-victoria-metrics-k8s-stack-kube-controller-manager | wc -c 73
[/simterm]
Щоб вирішити це – додаємо до values параметр fullnameOverride зі скороченим іменем:
victoria-metrics-k8s-stack: fullnameOverride: "vm-k8s-stack" ...
Деплоїмо ще раз:
[simterm]
$ helm -n dev-monitoring-ns upgrade --install atlas-victoriametrics . -f values/dev/atlas-monitoring-dev-values.yaml Release "atlas-victoriametrics" has been upgraded. Happy Helming! ...
[/simterm]
Перевіряємо ресурси:
[simterm]
$ kk -n dev-monitoring-ns get all NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/atlas-victoriametrics-grafana ClusterIP 172.20.93.0 <none> 80/TCP 0s service/atlas-victoriametrics-kube-state-metrics ClusterIP 172.20.113.37 <none> 8080/TCP 0s ...
[/simterm]
Наче все є – давайте додамо експортери.
Prometheus CloudWatch Exporter subchart
Для аутентифікації експортів в AWS використаємо IRSA, але тут описувати не буду, бо вже є у AWS: CDK та Python, IAM OIDC Provider, та Kubernetes Controllers, та й навряд чи ви це будете робити з AWS CDK та Python.
Тож будемо вважати, що IAM Role для експортера вже є – нам треба тільки встановити prometheus-cloudwatch-exporter чарт і вказати ARN IAM-ролі.
Знову перевіряємо доступні версії:
[simterm]
$ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts $ helm search repo prometheus-community/prometheus-cloudwatch-exporter NAME CHART VERSION APP VERSION DESCRIPTION prometheus-community/prometheus-cloudwatch-expo... 0.25.1 0.15.4 A Helm chart for prometheus cloudwatch-exporter
[/simterm]
Додаємо його до нашого Chart.yaml у dependencies:
... dependencies: - name: victoria-metrics-k8s-stack version: ~0.17.0 repository: https://victoriametrics.github.io/helm-charts/ - name: prometheus-cloudwatch-exporter version: ~0.25.1 repository: https://prometheus-community.github.io/helm-charts
До файлу values/dev/atlas-monitoring-dev-values.yaml додаємо параметр prometheus-cloudwatch-exporter.serviceAccount.annotations з ARN нашої IAM-ролі і блок config з метриками, які будемо збирати:
prometheus-cloudwatch-exporter:
serviceAccount:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::492***148:role/atlas-monitoring-dev-CloudwatchExporterRole0613A27-EU5LW9XRWVRL
config: |-
region: us-east-1
metrics:
- aws_namespace: AWS/Events
aws_metric_name: FailedInvocations
aws_dimensions: [RuleName]
aws_statistics: [Sum, SampleCount]
- aws_namespace: AWS/Events
aws_metric_name: Invocations
aws_dimensions: [EventBusName, RuleName]
aws_statistics: [Sum, SampleCount]
Хоча якщо конфіг великий – то мабуть краще його робити через створення власного ConfigMap для експортеру.
Оновлюємо залежності:
[simterm]
$ helm dependency update
[/simterm]
Деплоїмо:
[simterm]
$ helm -n dev-monitoring-ns upgrade --install atlas-victoriametrics . -f values/dev/atlas-monitoring-dev-values.yaml
Перевіряємо под:
[simterm]
$ kk -n dev-monitoring-ns get pod | grep cloud atlas-victoriametrics-prometheus-cloudwatch-exporter-564ccfjm9j 1/1 Running 0 53s
[/simterm]
Та ServiceAccount:
[simterm]
$ kk -n dev-monitoring-ns get pod atlas-victoriametrics-prometheus-cloudwatch-exporter-64b6f6b9rv -o yaml
...
- name: AWS_ROLE_ARN
value: arn:aws:iam::492***148:role/atlas-monitoring-dev-CloudwatchExporterRole0613A27-EU5LW9XRWVRL
- name: AWS_WEB_IDENTITY_TOKEN_FILE
value: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
...
[/simterm]
Робимо port-forward:
[simterm]
$ kk -n dev-monitoring-ns port-forward svc/atlas-victoriametrics-prometheus-cloudwatch-exporter 9106
[/simterm]
І з cURL глянемо, чи пішли метрики:
[simterm]
$ curl -s localhost:9106/metrics | grep aws_
# HELP aws_events_invocations_sum CloudWatch metric AWS/Events Invocations Dimensions: [EventBusName, RuleName] Statistic: Sum Unit: Count
# TYPE aws_events_invocations_sum gauge
aws_events_invocations_sum{job="aws_events",instance="",event_bus_name="***-staging",rule_name="***_WsConnectionEstablished-staging",} 2.0 1689598980000
aws_events_invocations_sum{job="aws_events",instance="",event_bus_name="***-prod",rule_name="***_ReminderTimeReached-prod",} 2.0 1689598740000
aws_events_invocations_sum{job="aws_events",instance="",event_bus_name="***-prod",rule_name="***_PushNotificationEvent-prod",} 2.0 1689598740000
[/simterm]
Є, чудово.
Тепер нам треба налаштувати VMAgent, щоб він почав збирати ці метрики з цього експортеру.
Збір метрик з експортерів: VMAgent && scrape_configs
Звична з Kube Prometheus Stack схема – це просто включити servicemonitor.enabled=true в вальюсах чарту експотера, і Prometheus Operator створить ServiceMonitor та почне збирати метрики.
Проте з VictoriaMetrics це не спрацює, бо ServiceMonitor CRD є частиною kube-prometheus-stack, і ресурс ServiceMonitor просто не буде створено.
Натомість у VictoriaMetrics є власний аналог – VMServiceScrape, який можна створити з маніфесту, і йому вказати з якого ендпоінту збирати метрики. До того ж, VictoriaMetrics вміє створювати VMServiceScrape з існуючих ServiceMonitor, але це потребує установки самого ServiceMonitor CRD.
Також ми можемо передати список таргетів через inlineScrapeConfig або additionalScrapeConfigs, див. VMAgentSpec.
Скоріш за все, у нас поки що буде inlineScrapeConfig, бо конфіг не надто великий.
Ще цікаво взагалі глянути VMAgent values.yaml – наприклад, там є дефолтні scrape_configs.
Ще один нюанс, которий треба мати на увазі – VMAgent не перевіряє конфіги таргетів, тобто якщо є помилка в YAML – то VMAgent просто ігнорує зміни, і не перезавантажує файл, при цьому в лог нічого не пише.
VMServiceScrape
Спочатку створимо VMServiceScrape вручну, щоб подивитись як воно взагалі працює.
Перевіряємо лейбли у CloudWatch Exporter Service:
[simterm]
$ kk -n dev-monitoring-ns describe svc atlas-victoriametrics-prometheus-cloudwatch-exporter
Name: atlas-victoriametrics-prometheus-cloudwatch-exporter
Namespace: dev-monitoring-ns
Labels: app=prometheus-cloudwatch-exporter
app.kubernetes.io/managed-by=Helm
chart=prometheus-cloudwatch-exporter-0.25.1
heritage=Helm
release=atlas-victoriametrics
...
[/simterm]
Описуємо VMServiceScrape з matchLabels, де вказуємо лейбли сервісу експортера:
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMServiceScrape
metadata:
name: prometheus-cloudwatch-exporter-vm-scrape
namespace: dev-monitoring-ns
spec:
selector:
matchLabels:
app: prometheus-cloudwatch-exporter
endpoints:
- port: http
Деплоїмо:
[simterm]
$ kubectl apply -f vmsvcscrape.yaml vmservicescrape.operator.victoriametrics.com/prometheus-cloudwatch-exporter-vm-scrape created
[/simterm]
Перевіряємо всі vmservicescrape – тут вже є пачка дефолтних, які створив сам VictoriaMetrics Operator:
[simterm]
$ kk -n dev-monitoring-ns get vmservicescrape NAME AGE prometheus-cloudwatch-exporter-vm-scrape 6m45s vm-k8s-stack-apiserver 4d22h vm-k8s-stack-coredns 4d22h vm-k8s-stack-grafana 4d22h vm-k8s-stack-kube-controller-manager 4d22h ...
[/simterm]
Конфіг VMAgent створюється в поді у файл /etc/vmagent/config_out/vmagent.env.yaml.
Глянемо, чи додався там наш CloudWatch Exporter:
[simterm]
$ kk -n dev-monitoring-ns exec -ti vmagent-vm-k8s-stack-98d7678d4-cn8qd -c vmagent -- cat /etc/vmagent/config_out/vmagent.env.yaml
global:
scrape_interval: 25s
external_labels:
cluster: eks-dev-1-26-cluster
prometheus: dev-monitoring-ns/vm-k8s-stack
scrape_configs:
- job_name: serviceScrape/dev-monitoring-ns/prometheus-cloudwatch-exporter-vm-scrape/0
honor_labels: false
kubernetes_sd_configs:
- role: endpoints
namespaces:
names:
- dev-monitoring-ns
...
[/simterm]
І тепер маємо побачити метрики в самій VictoriaMetrics.
Відкриваємо порт:
[simterm]
$ kk -n dev-monitoring-ns port-forward svc/vmsingle-vm-k8s-stack 8429
[/simterm]
В браузері заходимо на http://localhost:8429/vmui/ і для перевірки робимо запит на будь-яку метрику від CloudWatch Exporter:
Добре – побачили, як вручну створити VMServiceScrape. Але що там з автоматизацією цього процесу? Бо якось не дуже хочеться через Kustomize свторювати VMServiceScrape для кожного сервісу.
VMServiceScrape з ServiceMonitor та VictoriaMetrics Prometheus Converter
Тож як вже писалось, для того, щоб в кластері створився об’єкт ServiceMonitor нам потрібен Custom Resource Definition з ServiceMonitor.
Можемо встановити його прямо з маніфесту в репозиторії kube-prometheus-stack:
[simterm]
$ kubectl apply -fhttps://raw.githubusercontent.com/prometheus-community/helm-charts/main/charts/kube-prometheus-stack/charts/crds/crds/crd-servicemonitors.yaml customresourcedefinition.apiextensions.k8s.io/servicemonitors.monitoring.coreos.com created
[/simterm]
Оновлюмо наш values – додаємо serviceMonitorenabled=true:
...
prometheus-cloudwatch-exporter:
serviceAccount:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::492***148:role/atlas-monitoring-dev-CloudwatchExporterRole0613A27-EU5LW9XRWVRL
eks.amazonaws.com/sts-regional-endpoints: "true"
serviceMonitor:
enabled: true
...
І у вальюсах victoria-metrics-k8s-stack додаємо параметр operator.disable_prometheus_converter=false:
victoria-metrics-k8s-stack:
fullnameOverride: "vm-k8s-stack"
# no need yet
victoria-metrics-operator:
serviceAccount:
create: true
operator:
disable_prometheus_converter: false
...
Деплоїмо та перевіряємо, чи створено servicemonitor:
[simterm]
$ kk -n dev-monitoring-ns get servicemonitors NAME AGE atlas-victoriametrics-prometheus-cloudwatch-exporter 2m22s
[/simterm]
І автоматом мав з’явитись vmservicescrape:
[simterm]
$ kk -n dev-monitoring-ns get vmservicescrape NAME AGE atlas-victoriametrics-prometheus-cloudwatch-exporter 2m11s ...
[/simterm]
Глянемо targets:
Все є.
Єдиний тут нюанс в тому, что при видалені ServiceMonitor – відповідний vmservicescrape залишиться. Плюс сама необхідність в становленні стороннього CRD, який з часом треба буде якось оновлювати, бажано автоматично.
inlineScrapeConfig
Найбільш мабуть простий варіант – це описати конфіг через inlineScrapeConfig прямо в values нашого чарту:
...
vmagent:
enabled: true
spec:
externalLabels:
cluster: "eks-dev-1-26-cluster"
inlineScrapeConfig: |
- job_name: cloudwatch-exporter-inline-job
metrics_path: /metrics
static_configs:
- targets: ["atlas-victoriametrics-prometheus-cloudwatch-exporter:9106"]
...
Деплоймо і перевіряємо сам vmagent:
[simterm]
$ kk -n dev-monitoring-ns get vmagent -o yaml
apiVersion: v1
items:
- apiVersion: operator.victoriametrics.com/v1beta1
kind: VMAgent
...
inlineScrapeConfig: |
- job_name: cloudwatch-exporter-inline-job
metrics_path: /metrics
static_configs:
- targets: ["atlas-victoriametrics-prometheus-cloudwatch-exporter:9106"]
...
[/simterm]
Ще раз глянемо таргети:
additionalScrapeConfigs
Більш безпечний варіант, якщо в параметрах є якісь токени/ключі доступу, але потребує створення окремого об’єкту Kubernetes Secret.
В принципі не проблема, бо ConfigMaps/Secrets все одно доведеться створювати, і якщо захочется винести конфіг таргетів окремим файлом – то, скоріш за все, перероблю на additionalScrapeConfigs.
Зараз створимо вручну, просто глянути як воно буде працювати – беремо приклад прямо з документації:
apiVersion: v1
kind: Secret
metadata:
name: additional-scrape-configs
stringData:
prometheus-additional.yaml: |
- job_name: cloudwatch-exporter-secret-job
metrics_path: /metrics
static_configs:
- targets: ["atlas-victoriametrics-prometheus-cloudwatch-exporter:9106"]
Не забуваємо його задеплоїти 🙂
[simterm]
$ kubectl -n dev-monitoring-ns apply -f vmagent-targets-secret.yaml secret/additional-scrape-configs created
[/simterm]
Оновлюємо вальюси VMAgent – додаємо блок additionalScrapeConfigs:
...
vmagent:
enabled: true
spec:
externalLabels:
cluster: "eks-dev-1-26-cluster"
additionalScrapeConfigs:
name: additional-scrape-configs
key: prometheus-additional.yaml
inlineScrapeConfig: |
- job_name: cloudwatch-exporter-inline-job
metrics_path: /metrics
static_configs:
- targets: ["atlas-victoriametrics-prometheus-cloudwatch-exporter:9106"]
...
Оновлюємо деплой, та перевіряємо таргети:
Тепер, як маємо метрики – можемо переходити до Grafana.
Grafana provisioning
Що нам треба для Grafana? Плагіни, датасорси та дашборди.
Спершу додамо Data Sources, див. документацію.
Підключення Data Sources && Plugins
Якщо з дашбордами все більш-менш просто, то з Data Sources є питання: як в них передавати якісь секрети? Наприклад – для датасорсу Sentry треба задати токен, який в вальюсах чарту світити зовсім не хочеться, бо дані в GitHub ми не шифруємо, хоч репозиторії і приватні (див. git-crypt – на минулому проекті був, в приципі робоче рішення).
Давайте спершу поглянемо як воно працює взагалі, потім подумаємо, як нам передати токен.
Будемо додавати Senrty Data Source, див. grafana-sentry-datasource. Токен вже маємо – створено в sentry.io > User settings > User Auth Tokens.
В вальюси Grafana додаємо plugins, де вказуємо ім’я плагіну grafana-sentry-datasource (значення поля type в документації вище) і описуємо блок additionalDataSources з полем secureJsonData, в якому вказуємо сам токен:
...
grafana:
enabled: true
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/scheme: internet-facing
hosts:
- monitoring.dev.example.co
plugins:
- grafana-sentry-datasource
additionalDataSources:
- name: Sentry
type: grafana-sentry-datasource
access: proxy
orgId: 1
version: 1
editable: true
jsonData:
url: https://sentry.io
orgSlug: ***
secureJsonData:
authToken: 974***56b
...
Деплоїмо, перевіряємо плагін:
Та Data Source:
Окей, це працює.
Токен для Data Source через envFromSecret
Тепер спробуємо через змінну, значення для якої отримаємо з Kubernetes Secret за допомогою envFromSecret.
Створимо Secret:
--- apiVersion: v1 kind: Secret metadata: name: grafana-datasource-sentry-token stringData: SENTRY_TOKEN: 974***56b
Оновлюємо вальюси Grafana – додаємо envFromSecret, за допомогою якого отримаємо $SENTRY_TOKEN, та використовуємо його у additionalDataSources:
...
grafana:
...
envFromSecret: grafana-datasource-sentry-token
additionalDataSources:
- name: Sentry
type: grafana-sentry-datasource
access: proxy
orgId: 1
version: 1
editable: true
jsonData:
url: https://sentry.io
orgSlug: ***
secureJsonData:
authToken: ${SENTRY_TOKEN}
...
Деплоїмо, і перевіряємо змінну в поді Grafana:
[simterm]
$ kk -n dev-monitoring-ns exec -ti atlas-victoriametrics-grafana-64d9db677-g7l25 -c grafana -- printenv | grep SENTRY_TOKEN SENTRY_TOKEN=974***56b
[/simterm]
Перевіряємо конфіг датасорсів:
[simterm]
$ kk -n dev-monitoring-ns exec -ti atlas-victoriametrics-grafana-64d9db677-bpkw8 -c grafana -- cat /etc/grafana/provisioning/datasources/datasource.yaml
...
apiVersion: 1
datasources:
- name: VictoriaMetrics
type: prometheus
url: http://vmsingle-vm-k8s-stack.dev-monitoring-ns.svc:8429/
access: proxy
isDefault: true
jsonData:
{}
- access: proxy
editable: true
jsonData:
orgSlug: ***
url: https://sentry.io
name: Sentry
orgId: 1
secureJsonData:
authToken: ${SENTRY_TOKEN}
type: grafana-sentry-datasource
version: 1
[/simterm]
І ще раз тестуємо датасорс:
Тож при такому підході ми можемо використати AWS Secrets and Configuration Provider (ASCP) (див. AWS: Kubernetes – інтеграція AWS Secrets Manager та Parameter Store):
- створити секрет в GitHub Actions Secrets
- при деплої AWS CDK взяти значення у змінну через
os.env("SECRET_NAME_VAR")і створити секрет в AWS Secrets Manager - в
templatesнашого чарту створитиSecretProviderClassз полемsecretObjects.secretNameдля створення Kubernetes Secret
При запуску поду з Grafana вона цей секрет підключить до поду:
[simterm]
$ kk -n dev-monitoring-ns get pod atlas-victoriametrics-grafana-64d9db677-dlqfr -o yaml
...
envFrom:
- secretRef:
name: grafana-datasource-sentry-token
...
[/simterm]
І передасть значення до самої Grafana.
Окей, це може працювати, хоча виглядає трохи заплутано.
Але є ще один варіант – з sidecar.datasources.
Kubernetes Secret для всього Data Source і sidecar.datasources
Є другий варіант – створювати дата-сорси через sidecar container: можемо створити Kubernetes Secret з потрібною labels, і в цьому сікреті додати датасорс. Див. Sidecar for datasources
В принципі – цілком робоча схема: створити маніфест секрету в каталозі templates, і при виклику helm install в GitHub Actions передати значення з --set, а значення взяти з GitHub Actions Secrets. І виглядає простішою. Спробуємо.
У файлу templates/grafana-datasources-secret.yaml описуємо Kubernetes Secret:
apiVersion: v1
kind: Secret
metadata:
name: grafana-datasources
labels:
grafana_datasource: 'true'
stringData:
sentry.yaml: |-
apiVersion: 1
datasources:
- name: Sentry
type: grafana-sentry-datasource
access: proxy
orgId: 1
version: 1
editable: true
jsonData:
url: https://sentry.io
orgSlug: ***
secureJsonData:
authToken: {{ .Values.grafana.sentry_token }}
Деплоїмо з --set:
[simterm]
$ helm -n dev-monitoring-ns upgrade --install atlas-victoriametrics . -f values/dev/atlas-monitoring-dev-values.yaml --set grafana.sentry_token="974***56b"
[/simterm]
Перевіряємо конфіги датасорсів в поді Grafana:
[simterm]
$ kk -n dev-monitoring-ns exec -ti atlas-victoriametrics-grafana-5967b494f6-5zmjb -c grafana -- ls -l /etc/grafana/provisioning/datasources total 8 -rw-r--r-- 1 grafana 472 187 Jul 19 13:36 datasource.yaml -rw-r--r-- 1 grafana 472 320 Jul 19 13:36 sentry.yaml
[/simterm]
Зміст файлу sentry.yaml:
[simterm]
$ kk -n dev-monitoring-ns exec -ti atlas-victoriametrics-grafana-5967b494f6-5zmjb -c grafana -- cat /etc/grafana/provisioning/datasources/sentry.yaml
apiVersion: 1
datasources:
- name: Sentry
type: grafana-sentry-datasource
access: proxy
orgId: 1
version: 1
editable: true
jsonData:
url: https://sentry.io
orgSlug: ***
secureJsonData:
authToken: 974***56b
[/simterm]
І ще раз датасорс в самій Grafana:
It’s a magic!
Підключення Dashboards
Отже, ми вже маємо Графану, і там є дашборди, які нам треба перенести в новий стек моніторингу, і деплоїти з GitHub-репозиторію.
Документація по імпорту дашборд – Import dashboards.
Для створення дашборд через Helm-чарт маємо аналогічний до grafana-sc-datasources сайдкар-контейнер grafana-sc-dashboard, який буде перевіряти всі ConfigMaps з лейблою, і підключати їх до поду. Див. Sidecar for dashboards.
Майте на увазі рекомендацію:
A recommendation is to use one configmap per dashboard, as a reduction of multiple dashboards inside one configmap is currently not properly mirrored in grafana.
Тобто – один ConfigMap на кожну дашборду.
Тож що нам треба зробити – це описати ConfigMap для кожної дашборди, і Grafana сама додасть їх до /tmp/dashboards.
Експорт існуючої dashboard та Data Source UID not found
Щоб уникнути помилки з UID (“Failed to retrieve datasource Datasource f0f2c234-f0e6-4b6c-8ed1-01813daa84c9 was not found”) – йдемо до дашборди в існуючому інстансі Grafana, і додаємо нову змінну з типом Data Source:
Повторюємо для Loki, Sentry:
Та оновлюємо панелі – задаємо датасорс зі змінної:
Повторюємо теж саме для всіх запитів у Annotations та Variables:
Створюємо каталог для файлів, які потім будемо імпортити в Kubernetes:
[simterm]
$ mkdir -p grafana/dashboards/
[/simterm]
Та робимо Export дашборди в JSON і зберігаємо як grafana/dashboards/overview.json:
Dashboard ConfigMap
В каталозі templates створюємо маніфест для ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: overview-dashboard
labels:
grafana_dashboard: "1"
data:
overview.json: |
{{ .Files.Get "grafana/dashboards/overview.json" | indent 4 }}
Тепер всі файли нашого проекту виглядають так:
Деплоїмо чарт та перевіряємо ConfigMap:
[simterm]
$ kk -n dev-monitoring-ns get cm overview-dashboard -o yaml | head
apiVersion: v1
data:
overview.json: |
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
[/simterm]
І перевіряємо в поді – чи додався файл до /tmp/dashboards:
[simterm]
$ kubectl -n dev-monitoring-ns exec -ti atlas-victoriametrics-grafana-5967b494f6-gs4jm -c grafana -- ls -l /tmp/dashboards total 1032 ... -rw-r--r-- 1 grafana 472 74821 Jul 19 10:31 overview.json ...
[/simterm]
Та в самій Grafana:
І маємо наши графіки – поки не всі, бо запущено тільки один експортер:
Поїхали далі.
Що нам залишилось?
- GitHub exporter – зробити чарт, додати до загального чарту (чи просто створити маніфест з Deployment? там один под, нічного більше йому не треба)
- Loki
- алерти
GitHub exporter мабуть таки просто з Deployment зроблю – маніфест у templates основного чарту, та й все – окремий чарт там не потрібен. Тут описувати не буду, бо це просто.
Тож давайте тоді зараз загадаємо, як там запускається Loki, бо коли робив це восени – то було трохи геморно. Сподіваюсь, нічого особливо не змінилося, і зможу просто взяти конфіг з Grafana Loki: архітектура та запуск в Kubernetes з AWS S3 storage та boltdb-shipper.
Запуск Grafana Loki з AWS S3
Що нам тут треба?
- створити S3
- IAM Policy && IAM Role для доступу до бакету
- ConfigMap з конфігом Loki
- додати чарт Loki сабчартом нашого основного чарту
AWS CDK для S3 та IAM Role
S3 та IAM описуємо з AWS CDK:
...
##################################
### Grafana Loki AWS resources ###
##################################
### AWS S3 to store logs data and indexes
loki_bucket_name = f"{environment}-grafana-loki"
bucket = s3.Bucket(
self, 'GrafanaLokiBucket',
bucket_name=loki_bucket_name,
block_public_access=s3.BlockPublicAccess.BLOCK_ALL
)
# Create an IAM Role to be assumed by Loki
grafana_loki_role = iam.Role(
self,
'GrafanaLokiRole',
# for Role's Trust relationships
assumed_by=iam.FederatedPrincipal(
federated=oidc_provider_arn,
conditions={
'StringEquals': {
f'{oidc_provider_url.replace("https://", "")}:sub': f'system:serviceaccount:{monitoring_namespace}:loki'
}
},
assume_role_action='sts:AssumeRoleWithWebIdentity'
)
)
# Attach an IAM Policies to that Role
grafana_loki_policy = iam.PolicyStatement(
actions=[
"s3:ListBucket",
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject"
],
resources=[
f"arn:aws:s3:::{loki_bucket_name}",
f"arn:aws:s3:::{loki_bucket_name}/*"
]
)
grafana_loki_role.add_to_policy(grafana_loki_policy)
...
CfnOutput(
self,
'GrafanaLokiRoleArn',
value=grafana_loki_role.role_arn
)
...
Деплоїмо:
[simterm]
$ cdk deploy atlas-monitoring-dev ... Outputs: atlas-monitoring-dev.CloudwatchExporterRoleArn = arn:aws:iam::492***148:role/atlas-monitoring-dev-CloudwatchExporterRole0613A27-EU5LW9XRWVRL atlas-monitoring-dev.GrafanaLokiRoleArn = arn:aws:iam::492***148:role/atlas-monitoring-dev-GrafanaLokiRole27EECE19-1HLODQFKFLDNK ...
[/simterm]
Можемо додавати чарт.
Деплой Loki Helm chart
Додаємо репозиторій, шукаємо останню версію чарту:
[simterm]
$ helm repo add grafana https://grafana.github.io/helm-charts $ helm search repo grafana/loki NAME CHART VERSION APP VERSION DESCRIPTION grafana/loki 5.8.9 2.8.2 Helm chart for Grafana Loki in simple, scalable... grafana/loki-canary 0.12.0 2.8.2 Helm chart for Grafana Loki Canary grafana/loki-distributed 0.69.16 2.8.2 Helm chart for Grafana Loki in microservices mode grafana/loki-simple-scalable 1.8.11 2.6.1 Helm chart for Grafana Loki in simple, scalable... grafana/loki-stack 2.9.10 v2.6.1 Loki: like Prometheus, but for logs.
[/simterm]
Тут знов купа чартів, коротко:
loki-canary: система для аудіту роботи самої Lokiloki-distributed: Loki у microservices modesimple-scalable: deprecated, тепер це просто lokiloki-stack: тут відразу все – Grafana, Promtail, etc
Ми візьмемо grafana/loki 5.8.9. Додаємо в залежності нашого чарту у Chart.yaml:
apiVersion: v2 name: atlas-victoriametrics description: A Helm chart for Atlas Victoria Metrics kubernetes monitoring stack type: application version: 0.1.0 appVersion: "1.16.0" dependencies: - name: victoria-metrics-k8s-stack version: ~0.17.0 repository: https://victoriametrics.github.io/helm-charts/ - name: prometheus-cloudwatch-exporter version: ~0.25.1 repository: https://prometheus-community.github.io/helm-charts - name: loki version: ~5.8.9 repository: https://grafana.github.io/helm-charts
Всі дефолтні values – тут>>>, я брав зі свого старого конфігу – все завелося:
...
loki:
loki:
auth_enabled: false
commonConfig:
path_prefix: /var/loki
replication_factor: 1
storage:
bucketNames:
chunks: dev-grafana-loki
type: s3
schema_config:
configs:
- from: "2023-07-20"
index:
period: 24h
prefix: loki_index_
store: boltdb-shipper
object_store: s3
schema: v12
storage_config:
aws:
s3: s3://us-east-1/dev-grafana-loki
insecure: false
s3forcepathstyle: true
boltdb_shipper:
active_index_directory: /var/loki/index
shared_store: s3
rulerConfig:
storage:
type: local
local:
directory: /var/loki/rules
serviceAccount:
create: true
annotations:
eks.amazonaws.com/role-arn: "arn:aws:iam::492***148:role/atlas-monitoring-dev-GrafanaLokiRole27EECE19-1HLODQFKFLDNK"
write:
replicas: 1
read:
replicas: 1
backend:
replicas: 1
test:
enabled: false
monitoring:
dashboards:
enabled: false
rules:
enabled: false
alerts:
enabled: false
serviceMonitor:
enabled: false
selfMonitoring:
enabled: false
grafanaAgent:
installOperator: false
lokiCanary:
enabled: false
...
Ще треба буде прикрутити алерти Loki, але це вже окремо (див. Grafana Loki: алерти з Ruler та labels з логів)
Деплой Promtail Helm chart
Запустимо в кластері Promtail, щоб по-перше перевірити роботу Loki, по-друге – всеж мати логи з кластеру.
Знаходимо версії чарта:
[simterm]
$ helm search repo grafana/promtail -l | head NAME CHART VERSION APP VERSION DESCRIPTION grafana/promtail 6.11.7 2.8.2 Promtail is an agent which ships the contents o... grafana/promtail 6.11.6 2.8.2 Promtail is an agent which ships the contents o... grafana/promtail 6.11.5 2.8.2 Promtail is an agent which ships the contents o... ...
[/simterm]
Додаємо сабчарт в dependencies в нашому Chart.yaml:
apiVersion: v2 name: atlas-victoriametrics description: A Helm chart for Atlas Victoria Metrics kubernetes monitoring stack type: application version: 0.1.0 appVersion: "1.16.0" dependencies: - name: victoria-metrics-k8s-stack version: ~0.17.0 repository: https://victoriametrics.github.io/helm-charts/ - name: prometheus-cloudwatch-exporter version: ~0.25.1 repository: https://prometheus-community.github.io/helm-charts - name: loki version: ~5.8.9 repository: https://grafana.github.io/helm-charts - name: promtail version: ~6.11.7 repository: https://grafana.github.io/helm-charts
Знаходимо Service для Loki:
[simterm]
$ kk -n dev-monitoring-ns get svc | grep loki-gateway loki-gateway ClusterIP 172.20.102.186 <none> 80/TCP 160m
[/simterm]
Додаємо вальюси для Promtail:
...
promtail:
loki:
serviceName: "loki-gateway"
Деплоїмо, перевіряємо поди:
[simterm]
$ kk -n dev-monitoring-ns get pod | grep 'loki\|promtail' atlas-victoriametrics-promtail-cxwpz 0/1 Running 0 17m atlas-victoriametrics-promtail-hv94f 1/1 Running 0 17m loki-backend-0 0/1 Running 0 9m55s loki-gateway-749dcc85b6-5d26n 1/1 Running 0 3h4m loki-read-6cf6bc7654-df82j 1/1 Running 0 57s loki-write-0 0/1 Running 0 52s
[/simterm]
Додаємо Grafana Data Source через additionalDataSources (див. Provision the data source):
...
grafana:
enabled: true
...
additionalDataSources:
- name: Loki
type: loki
access: proxy
url: http://loki-gateway:80
jsonData:
maxLines: 1000
...
Деплоїмо, перевіряємо датасорси:
Та логи:
Тепер давайте глянемо, як там з алертами.
Налаштування алертів з VMAlert
Сам VMAlert && Alertmanager вже маємо з чарту, див. values – vmalert та alertmanager:
[simterm]
$ kk -n dev-monitoring-ns get pod | grep alert vmalert-vm-k8s-stack-dff5bf755-57rxd 2/2 Running 0 6d19h vmalertmanager-vm-k8s-stack-0 2/2 Running 0 6d19h
[/simterm]
Спочатку глянемо як конфігуриться Alertmanager, бо алерти будуть відправлятись через нього.
Конфігурація Alertmanager
Документація – VMAlertmanagerSpec.
Глянемо, де його конфіг:
[simterm]
$ kk -n dev-monitoring-ns describe pod vmalertmanager-vm-k8s-stack-0
...
Args:
....
--config.file=/etc/alertmanager/config/alertmanager.yaml
...
Mounts:
...
/etc/alertmanager/config from config-volume (rw)
...
Volumes:
config-volume:
Type: Secret (a volume populated by a Secret)
SecretName: vmalertmanager-vm-k8s-stack-config
...
[/simterm]
Тобто файл /etc/alertmanager/config/alertmanager.yaml береться з Kubernetes Secret vmalertmanager-vm-k8s-stack-config:
[simterm]
$ kk -n dev-monitoring-ns get secret vmalertmanager-vm-k8s-stack-config -o yaml | yq '.data'
{
"alertmanager.yaml": "Z2x***GwK"
}
[/simterm]
Перевіряємо зміст з base64 -d або на сайті www.base64decode.org.
Тепер давайте додамо власний конфіг.
Тут знову ж таки треба буде подумати про секрет, бо в slack_api_url маємо токен. Мабуть, зробимо як з Sentry-токеном – просто будемо передавати через --set.
Оновлюємо values/dev/atlas-monitoring-dev-values.yaml:
...
alertmanager:
enabled: true
config:
global:
resolve_timeout: 5m
slack_api_url: ""
route:
repeat_interval: 12h
group_by: ["alertname"]
receiver: 'slack-default'
routes: []
receivers:
- name: "slack-default"
slack_configs:
- channel: "#alerts-devops"
send_resolved: true
title: '{{ template "slack.monzo.title" . }}'
icon_emoji: '{{ template "slack.monzo.icon_emoji" . }}'
color: '{{ template "slack.monzo.color" . }}'
text: '{{ template "slack.monzo.text" . }}'
actions:
# self
- type: button
text: ':grafana: overview'
url: '{{ (index .Alerts 0).Annotations.grafana_url }}'
- type: button
text: ':grafana: Loki Logs'
url: '{{ (index .Alerts 0).Annotations.logs_url }}'
- type: button
text: ':mag: Alert query'
url: '{{ (index .Alerts 0).GeneratorURL }}'
- type: button
text: ':aws: AWS dashboard'
url: '{{ (index .Alerts 0).Annotations.aws_dashboard_url }}'
- type: button
text: ':aws-cloudwatch: AWS CloudWatch Metrics'
url: '{{ (index .Alerts 0).Annotations.aws_cloudwatch_url }}'
- type: button
text: ':aws-cloudwatch: AWS CloudWatch Logs'
url: '{{ (index .Alerts 0).Annotations.aws_logs_url }}'
...
Хоча взагалі ми маємо власний непоганий темплейт для Slack, але поки глянемо, як виглядаю цей monzo.
Деплоїмо з --set victoria-metrics-k8s-stack.alertmanager.config.global.slack_api_url=$slack_url:
[simterm]
$ slack_url="https://hooks.slack.com/services/T02***37X" $ helm -n dev-monitoring-ns upgrade --install atlas-victoriametrics . -f values/dev/atlas-monitoring-dev-values.yaml --set grafana.sentry_token=$sentry_token --set victoria-metrics-k8s-stack.alertmanager.config.global.slack_api_url=$slack_url --debug
[/simterm]
Та перевіримо.
Знаходимо Alertmanager Service:
[simterm]
$ kk -n dev-monitoring-ns get svc | grep alert vmalert-vm-k8s-stack ClusterIP 172.20.251.179 <none> 8080/TCP 6d20h vmalertmanager-vm-k8s-stack ClusterIP None <none> 9093/TCP,9094/TCP,9094/UDP 6d20h
[/simterm]
Робимо port-forward:
[simterm]
$ kk -n dev-monitoring-ns port-forward svc/vmalertmanager-vm-k8s-stack 9093
[/simterm]
І з cRUL відправляємо алерт:
[simterm]
$ curl -H 'Content-Type: application/json' -d '[{"labels":{"alertname":"testalert"}}]' http://127.0.0.1:9093/api/v1/alerts
{"status":"success"}
[/simterm]
Дивимось в Слаку:
Wait, what?)))
Окей. Воно працює, але ці темплейти меседжів в Слак мені не подобаються, краще взяти ті, що в мене вже є на старому моніторингу.
Custom Slack messages template
Зараз кастомні темплейти підключені через ConfigMap vmalertmanager-vm-k8s-stack-0:
[simterm]
...
Volumes:
...
templates-vm-k8s-stack-alertmanager-monzo-tpl:
Type: ConfigMap (a volume populated by a ConfigMap)
Name: vm-k8s-stack-alertmanager-monzo-tpl
Optional: false
...
[/simterm]
А включаються параметром monzoTemplate.enabled=true.
Також там же маємо templateFiles, де можемо описати власні шаблони:
...
alertmanager:
enabled: true
monzoTemplate:
enabled: false
templateFiles:
slack.tmpl: |-
{{/* Title of the Slack alert */}}
{{ define "slack.title" -}}
{{ if eq .Status "firing" }} :scream: {{- else -}} :relaxed: {{- end -}}
[{{ .Status | toUpper -}} {{- if eq .Status "firing" -}}:{{ .Alerts.Firing | len }} {{- end }}] {{ (index .Alerts 0).Annotations.summary }}
{{ end }}
{{ define "slack.text" -}}
{{ range .Alerts }}
{{- if .Annotations.description -}}
{{- "\n\n" -}}
*Description*: {{ .Annotations.description }}
{{- end }}
{{- end }}
{{- end }}
...
Деплоїмо і перевіряємо ConfigMap, який описано у custom-templates.yaml:
[simterm]
$ kk -n dev-monitoring-ns get cm | grep extra vm-k8s-stack-alertmanager-extra-tpl 1 2m4s
[/simterm]
Перевіряємо волюми в поді:
[simterm]
$ kk -n dev-monitoring-ns exec -ti vmalertmanager-vm-k8s-stack-0 -- ls -l /etc/vm/templates/ Defaulted container "alertmanager" out of: alertmanager, config-reloader total 0 drwxrwxrwx 3 root root 78 Jul 20 10:06 vm-k8s-stack-alertmanager-extra-tpl
[/simterm]
І чекаємо на якийсь алерт:
Тепер все красиво. Поїхали до створення власних алертів.
Алерти для VMAlert з VMRules
Документація – VMAlert.
Отже – як до VMAlert додати наші алерти?
VMAlert використовуює VMRules, які вибирає за ruleSelector:
[simterm]
$ kk -n dev-monitoring-ns get vmrule NAME AGE vm-k8s-stack-alertmanager.rules 6d19h vm-k8s-stack-etcd 6d19h vm-k8s-stack-general.rules 6d19h vm-k8s-stack-k8s.rules 6d19h ...
[/simterm]
Тобто – можемо описати в маніфестах потрібні рули, задеплоїти – і VMAlert їх підхопить.
Глянемо сам VMAlert – він у нас зараз один, і в принципі нам цього поки вистачить:
[simterm]
$ kk -n dev-monitoring-ns get vmalert vm-k8s-stack -o yaml
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMAlert
...
spec:
datasource:
url: http://vmsingle-vm-k8s-stack.dev-monitoring-ns.svc:8429/
evaluationInterval: 15s
extraArgs:
remoteWrite.disablePathAppend: "true"
image:
tag: v1.91.3
notifiers:
- url: http://vmalertmanager-vm-k8s-stack.dev-monitoring-ns.svc:9093
remoteRead:
url: http://vmsingle-vm-k8s-stack.dev-monitoring-ns.svc:8429/
remoteWrite:
url: http://vmsingle-vm-k8s-stack.dev-monitoring-ns.svc:8429/api/v1/write
resources: {}
selectAllByDefault: true
[/simterm]
Спробуємо додати тестовий алерт – створюємо файл victoriametrics/templates/vmalert-vmrules-test.yaml з kind: VMRule:
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMRule
metadata:
name: vmrule-test
# no need now, as we have one VMAlert with selectAllByDefault
#labels:
# project: devops
spec:
groups:
- name: testing-rule
rules:
- alert: TestAlert
expr: up == 1
for: 1s
labels:
severity: test
job: '{{ "{{" }} $labels.job }}'
summary: Testing VMRule
annotations:
value: 'Value: {{ "{{" }} $value }}'
description: 'Monitoring job {{ "{{" }} $labels.job }} failed'
Тут додаємо костиль у вигляді "{{" }}, бо {{ }} використовується і самим Helm, і алертами.
Деплоїмо, перевіряємо VMRule vmrule-test:
[simterm]
$ kk -n dev-monitoring-ns get vmrule vmrule-test -o yaml
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMRule
...
spec:
groups:
- name: testing-rule
rules:
- alert: TestAlert
annotations:
description: Monitoring job {{ $labels.job }} failed
value: 'Value: {{ $value }}'
summary: Testing VMRule
expr: up == 1
for: 1s
labels:
job: '{{ $labels.job }}'
severity: test
[/simterm]
Чекаємо на алерт у Слаку:
Все є.
В принципі, на цьому все – основні моменти наче описав.
Потім ще глянемо як там зі storage і бекапами.























