Kubernetes: мониторинг кластера с Prometheus Operator

Thank you for reading this post, don't forget to subscribe!

зада­ча – под­нять Prometheus и все необ­хо­ди­мые екс­пор­тё­ры в AWS Elastic Kubernetes Cluster, и с него через /federation пере­да­вать мет­ри­ки на наш “цен­тро­вой” Prometheus, где уже есть Alertmanager и Grafana.

Сму­тил целый набор чар­тов – есть про­сто Prometheus, есть kube-prometheus, есть prometheus-operator, при­чём от раз­ных разработчиков:

Хотя в репо­зи­то­рии нахо­дит­ся толь­ко один prometheus-operator:

Раз­ни­ца меж­ду stable/prometheus и stable/prometheus-operator в том, что в Operator вклю­че­на Grafana с набо­ром гото­вых даш­борд и набор ServiceMonitors для сбо­ра мет­рик с сер­ви­сов кла­сте­ра, таких как CoreDNS, API Server, Scheduler, etc.

Соб­ствен­но – исполь­зу­ем stable/prometheus-operator.

Prometheus Operator deployment

Деп­ло­им:

Про­ве­ря­ем поды:

Note: alias kk="kubectl" >> ~/.bashrc

Итак, Prometheus Operator деп­ло­ит нам целый набор сер­ви­сов – и сам Prometheus, и Alertmanager, и Grafana, плюс набор ServiceMonitors:

Роль ServiceMonitors рас­смот­рим ниже, когда будем добав­лять свой ServiceMonitor в Добав­ле­ние сер­ви­са в мониторинг.

Grafana access

Пока всё это тести­ру­ем – про­бро­сим порт на Grafana, что бы посмот­реть какие даш­бор­ды там есть.

Нахо­дим под с Grafana:

И вызы­ва­ем port-forward:

Откры­ва­ем в бра­у­зе­ре localhost:3000, логи­ним­ся с admin и паро­лем prom-operator, и полу­ча­ем целый набор гото­вых гра­фи­ков, например:

На момент напи­са­ния – Prometheus Operator запус­кал Grafana 7.0.3 (на нашем “цен­тро­вом” сер­ве­ре мони­то­рин­га всё ещё 6.5).

Соб­ствен­но, из все­го это­го в буду­щем про­сто мож­но будет надёр­гать при­ме­ров вся­ких запросов.

На сей­час нам тут не нуж­ны ни сама Grafana, ни Alertmanager, так что попоз­же мы их выпилим.

Prometheus Operator configuration

Prometheus Operator исполь­зу­ет Custom Resource Definitions, кото­рые опи­сы­ва­ют ресурсы:

Напри­мер, в prometheuses.monitoring.coreos.com опи­сы­ва­ет­ся Custom Resource с име­нем Prometheus:

И далее к нему мож­но обра­щать­ся, как к обыч­но­му ресур­су Kubernetes, исполь­зуя имя из names:

 

Нам тут инте­рес­но зна­че­ние serviceMonitorSelector:

Кото­рое опре­де­ля­ет какие ServiceMonitors будут вклю­че­ны под “наблю­де­ние” Prometheus.

Добавление сервиса в мониторинг

Теперь попро­бу­ем доба­вить новый сер­вис в наш мониторинг:

  1. запу­стим Redis server
  2. запу­стип redis_exporter
  3. доба­вим ServiceMonitor
  4. настро­им Prometheus Operator исполь­зо­ва­ние это­го ServiceMonitor для сбо­ра мет­рик с експортёра

Запуск Redis server

Созда­ём нейм­с­пейс, что бы мак­си­маль­но при­бли­зить усло­вия к “бое­вым”, когда мони­то­ринг и при­ло­же­ния рабо­та­ют не в одном default namespace, а в разных:

Запус­ка­ем Redis:

Созда­ём для него сервис:

Про­ве­ря­ем:

Окей – сам Redis рабо­та­ет, добав­ля­ем его експортер.

Запуск redis_exporter

Запус­ка­ем из Helm:

helm install -n monitoring redis-exporter --set "redisAddress=redis://redis-svc.redis-test.svc.cluster.local:6379" stable/prometheus-redis-exporter

Про­ве­ря­ем его сервис:

Его енд­по­инт:

Пове­рим доступ к мет­ри­кам – запу­стим дебаг-под с Debian, уста­нав­ли­ва­ем в нём curl:


И обра­ща­ем­ся к енд­по­ин­ту сер­ви­са redis_exporter:

Либо без допол­ни­тель­но­го пода – дела­ем port-forward на redis-svc:

И про­ве­ря­ем с локаль­ной машины:

Хоро­шо – у нас есть при­ло­же­ние – Редис, есть его екс­пор­тёр, кото­рый отда­ёт нам мет­ри­ки на пор­ту 9121 по URI /metrics – теперь надо настро­ить Prometheus Operator на сбор мет­рик с него.

Создание Kubernetes ServiceMonitor

Про­ве­рим лейб­лы наше­го redis_exporter:

И ещё раз гля­нем селек­тор serviceMonitorSelector ресур­са prometheus:

kk -n monitoring get prometheus -o yaml
В кон­це мани­фе­ста находим:

Т.е. Prometheus ищет ServiceMonitor-ы с тегом release, у кото­рых зна­че­ние prometheus.

Далее – созда­ём ServiceMonitor:


В его labels зада­ём release: prometheus, что бы Prometheus его обна­ру­жил, а в selector.matchLabels – ука­зы­ва­ем поиск сер­ви­сов с тегом release: redis-exporter.

При­ме­ня­ем:

kk -n monitoring apply -f redis-service-monitor.yaml
servicemonitor.monitoring.coreos.com/redis-servicemonitor created
И про­ве­ря­ем тар­ге­ты Prometheus: и Мет­ри­ки Редиса:

Что надо дальше?

А даль­ше надо выпи­лить из Operator запуск Alertmanager и Grafana.

Prometheus Operator Helm deployment и конфигурация сервисов

Хотя – а зачем выпи­ли­вать Гра­фа­ну? Там уже есть пач­ка гото­вых даш­борд – пусть остаётся.

Давай­те сде­ла­ем иначе:

  • на каж­дый EKS кла­стер выка­ты­ва­ем Operator с Grafana, но без Alertmanager
  • на локаль­ных кла­сте­ру Prometheus retention period для хра­не­ния мет­рик исполь­зу­ем дефолт­ный – 2 неде­ли, и локаль­ные Grafana будут выво­дить гра­фи­ки за две недели
  • Alertmanager выпи­ли­ва­ем – будем исполь­зо­вать его с цен­траль­но­го сер­ве­ра мони­то­рин­га – там уже настро­е­ны роуты, кана­лы, и про­чее – надо будет толь­ко доба­вить алерты
  • цен­траль­ный сер­вер мони­то­рин­га хра­нит мет­ри­ки год, и там нари­су­ем свою дашборду(ы) Grafana

Зна­чит надо будет создать два LoadBalancer – один с типом internet-facing для Grafana, и один для Prometheus – internal, т.к. к Prometheus в кла­сте­ре будет ходить “цен­траль­ный” Prometheus через AWS VPC Peering, и с /federation заби­рать у него метрики.

И всё это надо заин­те­гри­ро­вать с нашей авто­ма­ти­за­ци­ей – Ansible,

Но сна­ча­ла сде­ла­ем вруч­ную, конечно.

Итак, что нам надо изме­нить в дефолт­ном деп­лое Prometheus Operator?

  • убрать деп­лой Alertmanager
  • доба­вить настрой­ки для: 
    • Prometheus и Grafana – долж­ны деп­ло­ит­ся за LoadBalancer
    • логин-пароль для Grafana

Даль­ше смот­рим доступ­ные пара­мет­ры в доку­мен­та­ции – https://github.com/helm/charts/tree/master/stable/prometheus-operator.

Пока нач­нём с того, что пере­де­п­ло­им стек без Алерт­ме­не­дже­ра, для это­го надо пере­дать alertmanager.enabled.

Про­ве­ря­ем под сейчас:

Реде­п­ло­им, через --set зада­ём alertmanager.enabled=false:

helm upgrade --install --namespace monitoring --create-namespace prometheus stable/prometheus-operator --set "alertmanager.enabled=false"

Про­ве­ря­ем поды ещё раз – Алерт­ме­не­дже­ра нет, отлично.

Настройка LoadBalancer

Итак, мы хотим открыть доступ из мира к Grafana – зна­чит нужен будет ресурс Ingress для неё, и отдель­ный Ingress для Prometheus.

Что есть в доке:

grafana.ingress.enabled Enables Ingress for Grafana false
grafana.ingress.hosts Ingress accepted hostnames for Grafana []

Добав­ля­ем Ingress для Графаны:

Какую-то под­сказ­ку уда­лось нагуг­лить тут: https://zero-to-jupyterhub.readthedocs.io/en/latest/administrator/advanced.html#ingress

Про­бу­ем – теперь уже через values.yaml, что бы не горо­дить кучу --set, добав­ля­ем hosts:

Деп­ло­им:

helm upgrade --install --namespace monitoring --create-namespace prometheus stable/prometheus-operator -f oper.yaml

И смот­рим логи ALB Controller:

I0617 11:37:48.272749       1 tags.go:43] monitoring/prometheus-grafana: modifying tags {  ingress.k8s.aws/cluster: “bttrm-eks-dev-0”,  ingress.k8s.aws/stack: “monitoring/prometheus-grafana”,  kubernetes.io/service-name: “prometheus-grafa
na”,  kubernetes.io/service-port: “80”,  ingress.k8s.aws/resource: “monitoring/prometheus-grafana-prometheus-grafana:80”,  kubernetes.io/cluster/bttrm-eks-dev-0: “owned”,  kubernetes.io/namespace: “monitoring”,  kubernetes.io/ingress-name
: “prometheus-grafana”} on arn:aws:elasticloadbalancing:us-east-2:534***385:targetgroup/96759da8-e0b8253ac04c7ceacd7/35de144cca011059
E0617 11:37:48.310083       1 controller.go:217] kubebuilder/controller “msg”=”Reconciler error” “error”=”failed to reconcile targetGroups due to failed to reconcile targetGroup targets due to prometheus-grafana service is not of type NodePort or LoadBalancer and target-type is instance”  “controller”=”alb-ingress-controller” “request”={“Namespace”:”monitoring”,”Name”:”prometheus-grafana”}

Хоро­шо – давай­те доба­вим /target-type: "ip", что бы AWS ALB слал тра­фик пря­мо на под с Grafana, а не на WorkerNodes, заод­но доба­вим валид­ные коды ответов:

Либо, что бы исполь­зо­вать Instance type – мож­но пере­опре­де­лить тип Service для Grafana, и задать его в NodePort:

Пере­де­п­ло­и­ва­ем:

helm upgrade --install --namespace monitoring --create-namespace prometheus stable/prometheus-operator -f oper.yaml
Через мину­ту под­нял­ся ALB:

Но теперь при откры­тии стра­ни­цы dev-0.eks.monitor.example.com – ALB отда­ёт 404:

Что тут происходит?
  1. ALB при­ни­ма­ет запрос к dev-0.eks.monitor.example.com, отправ­ля­ет его на TargetGroup с Grafana
  2. Grafana воз­вра­ща­ет 302 /login
  3. мы воз­вра­ща­ем­ся к ALB, но теперь в URI пере­да­ём /login

Про­ве­ря­ем пра­ви­ла Listener:

Ну, да – а в пра­ви­лах балан­се­ра на все запро­сы кро­ме / мы воз­вра­ща­ем 404. Соот­ветс­вен­но, и на /login тоже воз­вра­ща­ет­ся 404.

Очень хоте­лось бы уви­деть ком­мен­та­рии раз­ра­бот­чи­ка, кото­рый дефолт­ным рулом path задал имен­но такое.

Воз­вра­ща­ем­ся к наше­му values.yaml, добав­ля­ем path рав­ным /*.

А hosts, что бы избе­жать ошиб­ки “Invalid value: []networking.IngressRule(nil): either `backend` or `rules` must be specified” и не при­вя­зы­вать­ся к кон­крет­но­му доме­ну мож­но задать про­сто в виде "":

Реде­п­ло­им, проверяем:

И откры­ва­ем в браузере:

Prometheus и Lens

И даже в Lens появи­лись все гра­фи­ки вме­сто оши­бок “Metrics are not available due to missing or invalid Prometheus configuration” и “Metrics not available at the moment“:

В целом – на этом, думаю, всё основ­ное рассмотрели.

Мож­но при­кру­чи­вать авто­ма­ти­за­цию, и выка­ты­вать в тестирование.