Prometheus: запуск Pushgateway у Kubernetes з Helm та Terraform

Автор |  28/04/2023
 

Маємо на проекті багато AWS Lambda функцій, з яких девелопери хочуть мати можливість відправляти метрики до нашого Prometheus, щоб додати власних алертів та графіків у Grafana.

Для цього у функціях використовується бібліотека Prometheus, яка дозволяє ці метрики створювати (див. Prometheus: створення Custom Prometheus Exporter на Python), але ж ми не маємо змоги нормально отримати ці дані з Prometheus, бо функції можуть жити декілька секунд, а Prometheus використовує PULL-модель, тобто він сам ходить до експортерів, та витягує звідти дані.

Що можемо зробити у випадку AWS Lambda – це додати Prometheus Pushgateway, який буде мати зовнішній ендпоінт, на який функції будуть слати свої метрики, а Prometheus буде забирати ці дані з Pushgateway, який виконує таку собі “проксі роль”.

Загальна схема роботи Prometheus та роль Pushgateway добре відображена на цій схемі:

Тож сьогодні запустимо Prometheus Pushgateway у Kubernetes використовуючи Helm-чарт, а чарт будемо встановлювати за допомогою Terraform.

Pushgateway Helm chart

Спочатку, давайте подивимося, що у нас є у values чарту Pushgateway.

По факту, наразі нам тут можуть бути цікавими тільки два параметри – це Ingress та ServiceMonitor.

Напишемо свій values, для тесту задеплоїмо на Dev оточення, а потім додамо до Terraform, через який Pushgateway вже буде деплоїтися по всіх наших моніторинг-оточеннях:

ingress:
  enabled: true
  className: alb
  path: /
  pathType: Prefix
  annotations:
    alb.ingress.kubernetes.io/scheme: internal
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-west-2:638***021:certificate/e97f17e9-33f9-46e7-9b2b-d50de8a72219
    alb.ingress.kubernetes.io/target-type: ip
  hosts:
    - test-pushgateway.monitoring.dev.example.com

serviceMonitor:
  enabled: true
  namespace: monitoring
  additionalLabels:
    release: prometheus

Тут описуємо створення Kubernetes Ingress, якому на порт 443 відповідного AWS Application Load Balancer підключимо SSL сертифікат з Amazon Certificate Manager. В hosts задаємо ім’я хоста, яке за допомогою ExternalDNS буде створено в AWS Route53.

І додаємо ServiceMonitor з лейблою release: prometheus, щоб Prometheus із Kube Prometheus Stack його побачив.

Додаємо репозиторій Prometheus:

[simterm]

$ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
$ helm repo update

[/simterm]

І встановлюємо Pushgateway до неймспейсу monitoring:

[simterm]

$ helm -n monitoring upgrade --install prometheus-pushgateway-test prometheus-community/prometheus-pushgateway -f pushgateway-values-dev.yaml 
...
NOTES:
1. Get the application URL by running these commands:
  http://test-pushgateway.monitoring.example.com/

[/simterm]

Перевіряємо Pod та Ingress:

[simterm]

$ kubectl get pod,ingress --namespace monitoring -l app.kubernetes.io/instance=prometheus-pushgateway-test
NAME                                               READY   STATUS    RESTARTS   AGE
pod/prometheus-pushgateway-test-6b5dfbdd7f-chzkf   1/1     Running   0          53s

NAME                                                    CLASS   HOSTS                                         ADDRESS                                                              PORTS   AGE
ingress.networking.k8s.io/prometheus-pushgateway-test   alb     test-pushgateway.monitoring.dev.example.com   internal-k8s-monitori-promethe-***-***.us-west-2.elb.amazonaws.com   80      54s

[/simterm]

Pushgateway має власний веб-інтерфейс – відкриваємо доступ до його поду на порт 9091:

[simterm]

$ kubectl -n monitoring port-forward pod/prometheus-pushgateway-test-6b5dfbdd7f-chzkf 9091
Forwarding from 127.0.0.1:9091 -> 9091
Forwarding from [::1]:9091 -> 9091

[/simterm]

Та в браузері переходимо на http://localhost:9091:

Далі, перевіримо чи бачить сам Prometheus цей Pushgateway – відкриваємо порт 9090 до Prometheus Pod:

[simterm]

$ kk -n monitoring port-forward prometheus-prometheus-kube-prometheus-prometheus-0 9090
Forwarding from 127.0.0.1:9090 -> 9090
Forwarding from [::1]:9090 -> 9090

[/simterm]

Та переходимо до Status > Targets, і шукаємо Pushgateway target:

І перевіримо, чи потраплять метрики з Pushgateway до Prometheus.

Оскільки наш Ingress/ALB має тип internal, тобто недоступний ззовні, то запустимо Kubernetes Pod з Ubuntu в Kubernetes-кластері:

[simterm]

$ kubectl run pod --rm -i --tty --image ubuntu -- bash
If you don't see a command prompt, try pressing enter.
root@pod:/# 

[/simterm]

Встановлюємо в ньому curl:

[simterm]

root@pod:/# apt update && apt -y install curl

[/simterm]

Та користуючись документацією відправимо запит, тільки порт не вказуємо, бо у нас він 443, SSL:

[simterm]

root@pod:/# echo "some_metric 3.14" | curl --data-binary @- https://test-pushgateway.monitoring.dev.exmaple.com/metrics/job/some_job

[/simterm]

Перевіряємо в Pushgateway:

Та у Prometheus:

Є, чудово.

Аутентифікація Pushgateway

Оскільки у нас Pushgateway працює на internal-ALB, то я не став поки робити аутентифікацію, бо він це все ще в процесі тестування, і поки невідомо як воно там зайде девелоперам.

Але у values є блок, з прикладом запуску контейнера з openshift/oauth-proxy, а у Using OpenShift OAuth Proxy to secure your Applications on OpenShift наче непогано описано приклад його використання – якось можна буде спробувати.

Terraform та Helm для Pushgateway

Так в проекті повелося” (с), що більша частина ресурсів у Kubernetes деплоїться за допомогою Terraform та його helm_release resource.

У нас багато аккаунтів AWS, і в кожному буде свій ARN сертифікату, тож отримаємо його за допомогою Data Source (або можна створити власний за допомогою aws_acm_certificate):

data "aws_acm_certificate" "wildcard" {
  domain = "*.${var.root_domain}"
}

Змінна root_domain у нас передається з основного модулю, та має вигляд monitoring.dev.example.com.

Для нашого values створюємо темплейт pushgateway-values.tpl.yaml:

ingress:
  enabled: true
  className: alb 
  path: /
  pathType: Prefix 
  annotations:
    alb.ingress.kubernetes.io/scheme: internal
    alb.ingress.kubernetes.io/certificate-arn: ${acmWildcardArn}
    alb.ingress.kubernetes.io/target-type: ip
  hosts: 
    - ${pushgatewayUrl}
  
serviceMonitor:
  enabled: true
  namespace: monitoring
  additionalLabels:
    release: prometheus

І додаємо сам helm_release, в якому у values[] задаємо файл темплейту та пару змінних – ARN сертифікату, який отримали за допомогою data.aws_acm_certificate, та домен для Ingress hosts:

resource "helm_release" "pushgateway" {
  name = "prometheus-pushgateway"

  namespace = kubernetes_namespace.monitoring.id

  repository  = "https://prometheus-community.github.io/helm-charts"
  chart       = "prometheus-pushgateway"
  version     = "2.1.3"
  max_history = 10

  values = [
    templatefile("${path.module}/configs/prometheus/pushgateway-values.tpl.yaml", {
      acmWildcardArn : data.aws_acm_certificate.wildcard.arn,
      pushgatewayUrl : "pushgateway.${var.root_domain}"
    })
  ]
}

Деплоїмо:

[simterm]

$ terraform apply
...
module.monitoring.helm_release.pushgateway: Creating...
module.monitoring.helm_release.pushgateway: Still creating... [10s elapsed]
module.monitoring.helm_release.pushgateway: Still creating... [20s elapsed]
module.monitoring.helm_release.pushgateway: Still creating... [30s elapsed]
module.monitoring.helm_release.pushgateway: Creation complete after 32s [id=prometheus-pushgateway]
...
Apply complete! Resources: 1 added, 1 changed, 0 destroyed.

[/simterm]

Перевіряємо Ingress та Pod:

[simterm]

$ kk -n monitoring get ingress,pod -l app.kubernetes.io/instance=prometheus-pushgateway
NAME                                               CLASS   HOSTS                                    ADDRESS                                                              PORTS   AGE
ingress.networking.k8s.io/prometheus-pushgateway   alb     pushgateway.monitoring.dev.example.com   internal-k8s-monitori-promethe-***-***.us-west-2.elb.amazonaws.com   80      10m

NAME                                          READY   STATUS    RESTARTS   AGE
pod/prometheus-pushgateway-55b9f5ffd6-sm9ck   1/1     Running   0          10m

[/simterm]

Все є.

Готово.