Цього разу я не буду починати статтю із історії появи та особливості Prometheus, адже раніше вже опублікував подібну. У ній ми також зупинились на складових частинах моніторингової системи та її конфігурації для звичайних вузлів. Цього разу поговоримо про місце, яке займає Prometheus в моніторингу Kubernetes, його додатків та підсистем.
WHAT IS PROMETHEUS OPERATOR
Prometheus реалізований як оператор Kubernetes. Цю концепцію вперше запропонувала компанія CoreOS, яка була поглинута RedHat-ом. Оператор - це додаткова абстракція, що допомагає менеджити сервіси, які можуть бути дещо "нерідними" для Kubernetes і надає додатковий рівень автоматизації такому програмному продукту. Оператор вводить додаткові типи об'єктів, котрі включають в себе об'єкти більш низького рівня (native resources). Скажімо використавши "kind: Prometeus", оператор (додатковий постійний сервіс) автоматично створить та налаштує StatefulSet, а в його поди буде змонтовано необхідний Secret, що містить конфігураційний файл для старту Прометеуса. Цей контролер також буде слідкувати за подальшою ситуацією щодо ресурсів, створених ним же, і буде їх змінювати за необхідності: скейлити, даунскейлити, видаляти і т.п.
Такі типи об'єктів реалізовуються за допомогою CRD (custom resource definition), що є розширенням до Kubernetes API. Існує велика множина операторів, для деяких продуктів - це офіційний спосіб їх установки і менеджменту, для інших - опціональний чи навіть неофіційний. Ніщо не заважає запакувати оператор в Helm-чарт чи просто виливати його як набір yaml-файлів.
Є декілька варіантів установки Prometheus оператора, і це варто усвідомлювати перед вибором способу інсталяції:
- prometheus-operator. Основний та офіційний репозиторій, де відбувається розробка. Після його установки всі ресурси (Prometheus, Alertmanager та ін.) необхідно буде створити власноруч, він описує лише створення оператору та CRDs, якими і маніпулює. Prometheus Operator не тягне за собою купи дашбордів для графани чи щось подібне, як наступний проект в списку.
- kube-prometheus. Також офіційний спосіб інсталяції, який вже включає приклад конфігурації для повного моніторингу Kubernetes кластеру, створює Prometheus та Alertmanager в HA режимі і навіть активізує нотифікації у разі критичних проблем. Так би мовити мінімальний набір Kubernetes-користувача.
- kube-prometheus-stack helm chart надає схожі з kube-prometheus можливості, проте не є офіційним рішенням від проекту.
Із питаннями по першим двом можна звертатись в офіційний Kubernetes slack-канал. Community helm чарт може мати інакшу конфігугацію, інші Grafana-дашборди та навіть інші лейбли для додавання сервісів до моніторингу. Однак всередині все ті ж CRDs та оператор.
У статті буде розглянуто лише два перші способи установки. Основна ціль статті - показати як працювати із примітивами оператора, а не просто встановити Prometheus.
MINIKUBE AND EXPERIMENTAL APP SETUP
У якості дистрибутива Kubernetes оберемо звичайний minikube, але згодиться навіть те, що є під рукою. Ініціюємо його так, як рекомендує сам проєкт:
$ curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
$ sudo install minikube-linux-amd64 /usr/local/bin/minikube
$ minikube delete && minikube start --kubernetes-version=v1.23.0 --memory=6g --bootstrapper=kubeadm --extra-config=kubelet.authentication-token-webhook=true --extra-config=kubelet.authorization-mode=Webhook --extra-config=scheduler.bind-address=0.0.0.0 --extra-config=controller-manager.bind-address=0.0.0.0
Також у разі minikube рекомендується вимкнути metrics-server аддон:
$ minikube addons disable metrics-server
Перевіримо статус роботи K8s:
$ minikube status
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
Чудово! Тепер задеплоїмо тестовий додаток example-app, для подальшої демонстрації роботи Prometheus:
$ kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: example-app
spec:
replicas: 3
selector:
matchLabels:
app: example-app
template:
metadata:
labels:
app: example-app
spec:
containers:
- name: example-app
image: fabxc/instrumented_app
ports:
- name: web
containerPort: 8080
---
kind: Service
apiVersion: v1
metadata:
name: example-app
labels:
app: example-app
spec:
# type: NodePort
selector:
app: example-app
ports:
- name: web
port: 8080
EOF
Перевіримо чи сервіс справді створився:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
example-app-56cc7f77dd-56zvm 1/1 Running 0 42s
example-app-56cc7f77dd-bmplr 1/1 Running 0 42s
example-app-56cc7f77dd-l45z7 1/1 Running 0 42s
...
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
example-app ClusterIP 10.100.52.216 <none> 8080/TCP 44s
...
На :8080/metrics сервіс має відповідати Prometheus-форматом метрик зі статистикою своєї роботи.
PROMETHEUS-OPERATOR SETUP
Тепер встановимо Prometheus Operator, використавши останній зі стабільних тегів:
$ git clone git@github.com:prometheus-operator/prometheus-operator.git
$ cd prometheus-operator
$ git checkout tags/v0.57.0
$ kubectl create -f bundle.yaml
$ kubectl get crds
NAME CREATED AT
alertmanagerconfigs.monitoring.coreos.com 2022-06-18T11:02:18Z
alertmanagers.monitoring.coreos.com 2022-06-18T11:02:18Z
podmonitors.monitoring.coreos.com 2022-06-18T11:02:18Z
probes.monitoring.coreos.com 2022-06-18T11:02:18Z
prometheuses.monitoring.coreos.com 2022-06-18T11:02:18Z
prometheusrules.monitoring.coreos.com 2022-06-18T11:02:18Z
servicemonitors.monitoring.coreos.com 2022-06-18T11:02:18Z
thanosrulers.monitoring.coreos.com 2022-06-18T11:02:18Z
Із виводу видно які саме CRD буде створено. Оператор створився в default неймспейсі, звісно це не годиться для prod-середовища, але зараз йде мова не про це:
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/prometheus-operator-567cd8b6f6-xxvjp 1/1 Running 0 3m31s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 16m
service/prometheus-operator ClusterIP None <none> 8080/TCP 3m31s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/prometheus-operator 1/1 1 1 3m31s
NAME DESIRED CURRENT READY AGE
replicaset.apps/prometheus-operator-567cd8b6f6 1 1 1 3m31s
Це все, абсолютний мінімум. Ніяких web-панелей поки немає, їх ще необхідно буде описати.
RBAC PERMISSIONS
Почнемо із RBAC правил, адже Prometheus потребує доступу до Kubernetes API для опитувань ресурсів (targets) та доступу до майбутнього Alertmanager:
$ kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: prometheus
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: prometheus
rules:
- apiGroups: [""]
resources:
- nodes
- nodes/metrics
- services
- endpoints
- pods
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources:
- configmaps
verbs: ["get"]
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs: ["get", "list", "watch"]
- nonResourceURLs: ["/metrics"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: prometheus
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: prometheus
subjects:
- kind: ServiceAccount
name: prometheus
namespace: default
EOF
DEPLOY AND CONFIGURE PROMETHEUS
Маючи працюючий оператор та необхідний ServiceAccount, можемо перейти до установки Prometheus:
$ kubectl apply -f - <<EOF
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
name: prometheus
spec:
serviceAccountName: prometheus
serviceMonitorNamespaceSelector: {}
serviceMonitorSelector: {}
podMonitorSelector: {}
resources:
requests:
memory: 400Mi
EOF
serviceAccountName вказує який саме ServiceAccount використовувати, serviceMonitorNamespaceSelector описує в які неймспейси дивитись для додавання нових target-ів для моніторингу, serviceMonitorSelector та podMonitorSelector описують по яким лейблам (їх регулярним виразам) додавати serviceMonitor-и та podMonitor-и (CRDs, про котрі поговоримо далі). Цього разу ми не будемо обмежуватись в неймінгу, на що вказує значення {}. Проте щоб обмежити моніторинг лише одним неймспейсом - можна вказати наступне:
...
serviceMonitorNamespaceSelector:
matchLabels:
name: some-namespace
...
Перевіримо чи Прометеус працює:
$ kubectl get prometheus
NAME VERSION REPLICAS AGE
prometheus 64s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
...
prometheus-prometheus-0 2/2 Running 0 68s
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
prometheus-operated ClusterIP None <none> 9090/TCP 2m49s
...
Відкриємо панель Prometheus, щоб пересвідчитись що він працює та справді поки нічого не моніторить:
$ kubectl port-forward svc/prometheus-operated 9090:9090
DEPLOY AND CONFIGURE SERVICEMONITOR
Оператор використовує ServiceMonitor об'єкти для того, щоб описати цілі (target-и) моніторингу. Він використовує лейбли/селектори для того, щоб описати які K8s сервіси, в яких саме неймспейсах та із якими портами мають бути додані.
Ця блок-схема гарно демонструє логіку роботи ServiceMonitor та і оператора в цілому:
Створимо ServiceMonitor для моніторингу самого Прометеусу:
$ kubectl apply -f - <<EOF
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: prometheus
labels:
name: prometheus
spec:
selector:
matchLabels:
operated-prometheus: "true"
namespaceSelector:
any: true
endpoints:
- port: web
EOF
Цей ServiceMonitor буде слідкувати за сервісами із селектором operated-prometheus: "true", що знаходяться в будь-якому нейсмейсі (any: true) та web-портом. operated-prometheus: "true" лейбл додається автоматично до всіх інстансів Prometheus:
$ kubectl get svc prometheus-operated -o yaml
apiVersion: v1
kind: Service
metadata:
creationTimestamp: "2022-05-18T11:48:51Z"
labels:
operated-prometheus: "true"
name: prometheus-operated
namespace: default
ownerReferences:
- apiVersion: monitoring.coreos.com/v1
kind: Prometheus
name: prometheus
uid: d7412620-855a-489a-9de2-322b0c57e79f
resourceVersion: "2834"
uid: 80f66293-0552-41e5-81a2-ce5d2720e722
spec:
clusterIP: None
clusterIPs:
- None
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: web
port: 9090
protocol: TCP
targetPort: web
selector:
app.kubernetes.io/name: prometheus
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
Також додамо до моніторингу тестовий сервіс example-app, котрий ми створили для демонстративних цілей:
$ kubectl apply -f - <<EOF
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: example-app
labels:
name: example-app
spec:
selector:
matchLabels:
app: example-app
namespaceSelector:
any: true
endpoints:
- port: web
EOF
Процес появи ендпоїнтів в веб-панелі Prometheus не миттєвий, зазвичай треба зачекати декілька хвилин:
DEPLOY AND CONFIGURE PODMONITOR
Часом необхідно моніторити поди, котрі не мають відповідного сервісу. Це може бути, скажімо, моніторинг через sidecar-контейнер із окремим портом чи просто додатку не потрібен K8s-сервіс взагалі. У такому разі можливості обирати поди за лейблом сервісу немає і у нагоді стає PodMonitor. Опишемо PodMonitor, котрий буде слідкувати за портом 8080 кожного поду із example-app деплойменту:
$ kubectl apply -f - <<EOF
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: example-app
labels:
name: example-app
spec:
namespaceSelector:
matchNames:
- default
selector:
matchLabels:
app: example-app
podMetricsEndpoints:
- targetPort: 8080
EOF
selector обере лише поди із лейблом app: example-app в default неймспейсі. Звісно можна також використовувати вибірку по всіх неймспейсах, котру ми використовували раніше.
ADDITIONAL SCRAPE CONFIGURATION
Хоч це і не найліпший варіант по багатьом причинам, але є можливість додавати конфігурацію Prometheus через Secret файли. Вони зобов'язані мати коректний синтаксис і лише користувач відповідальний за їхню правильність. Інакше вони не будуть включені в загальну конфігурацію.
Створимо таку додаткову конфігурацію:
$ vim prometheus-additional-job.yaml
- job_name: "example-app"
static_configs:
- targets: ["example-app.default:8080"]
Вона описує додатковий target, але у звичному для Prometheus форматі. example-app.default - внутрішнє доменне ім'я нашого демонстраційного сервісу, що лежить в неймспейсі default. Тепер створимо секрет із prometheus-additional-job.yaml та застосуємо його:
$ kubectl create secret generic additional-scrape-configs --from-file=prometheus-additional-job.yaml --dry-run=client -oyaml > additional-scrape-configs.yaml
$ cat additional-scrape-configs.yaml
apiVersion: v1
data:
prometheus-additional-job.yaml: LSBqb2JfbmFtZTogImV4YW1wbGUtYXBwIiAgIAogIHN0YXRpY19jb25maWdzOiAgICAgCiAgICAtIHRhcmdldHM6IFsiZXhhbXBsZS1hcHAuZGVmYXVsdCJdCg==
kind: Secret
metadata:
creationTimestamp: null
name: additional-scrape-configs
$ kubectl apply -f additional-scrape-configs.yaml
Але це ще не все. Потрібно також описати цей секрет в самому Прометеусі:
$ kubectl apply -f - <<EOF
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
name: prometheus
spec:
serviceAccountName: prometheus
serviceMonitorNamespaceSelector: {}
serviceMonitorSelector: {}
podMonitorSelector: {}
additionalScrapeConfigs:
name: additional-scrape-configs
key: prometheus-additional-job.yaml
resources:
requests:
memory: 400Mi
enableAdminAPI: false
EOF
Додалась секція additionalScrapeConfigs, все інше залишилось таким, як і було раніше.
Такий конфіг варто використовувати лише якщо ресурси для моніторингу не можна описати попередніми способами, наприклад у разі, якщо вони не лежать у межах одного K8s кластера.
DEPLOY AND CONFIGURE ALERTMANAGER
Прометеус оператор також відповідальний за створення Alertmanager ресурсів, що дозволяють декларативно описати Alertmanager кластер. Як і раніше, все це завдяки кастомним ресурсам, що привнесли CRDs.
Створимо конфігураційний файл Alertmanager. Цього разу опишемо ресурс із відправкою повідомлень у вигаданий Wechat чат:
$ kubectl apply -f - <<EOF
apiVersion: monitoring.coreos.com/v1alpha1
kind: AlertmanagerConfig
metadata:
name: config-alertmanager
labels:
alertmanagerConfig: example-app
spec:
route:
groupBy: ['job']
groupWait: 30s
groupInterval: 5m
repeatInterval: 12h
receiver: 'wechat-example-app'
receivers:
- name: 'wechat-example-app'
wechatConfigs:
- apiURL: 'http://wechatserver:8080/'
corpID: 'wechat-corpid'
apiSecret:
name: 'wechat-config'
key: 'apiSecret'
---
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: wechat-config
data:
apiSecret: cGFzc3dvcmQK
EOF
Після цього опишемо сам Alertmanager, що використовуватиме цей конфігураційний файл:
$ kubectl apply -f - <<EOF
apiVersion: monitoring.coreos.com/v1
kind: Alertmanager
metadata:
name: example-app
spec:
replicas: 1
alertmanagerConfigSelector:
matchLabels:
alertmanagerConfig: example-app
EOF
Це все. Як і раніше, для того, щоб побачити веб-панель, її необхідно прокинути, використовуючи port-forward:
$ kubectl port-forward svc/alertmanager-operated 9093:9093
Після чого за адресою http://localhost:9093/#/status можна побачити новий конфіг.
Окрім всього цього, Alertmanager також має бути прив'язаний до Prometheus, котрий ми створили раніше. Для цього необхідно лиш дещо поправити ресурс останнього:
$ kubectl apply -f - <<EOF
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
name: prometheus
spec:
serviceAccountName: prometheus
serviceMonitorNamespaceSelector: {}
serviceMonitorSelector: {}
podMonitorSelector: {}
additionalScrapeConfigs:
name: additional-scrape-configs
key: prometheus-additional-job.yaml
resources:
requests:
memory: 400Mi
enableAdminAPI: false
alerting:
alertmanagers:
- namespace: default
name: alertmanager-operated
port: web
ruleSelector:
matchLabels:
role: alert-rules
prometheus: example-app
EOF
CONFIGURING PROMETHEUS RULES
Ресурс PrometheusRule підтримує опис однієї чи більше RuleGroups. RuleGroups - це множина правил, котрі представляють 2 типи правил: запису чи оповіщення.
Виключно задля демонстрації опишемо наступний PrometheusRule, котрий буде постійно викликати оповіщення:
$ kubectl apply -f - <<EOF
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
creationTimestamp: null
labels:
prometheus: example-app
role: alert-rules
name: prometheus-example-rules
spec:
groups:
- name: example
rules:
- alert: SmallHttpResponseSizeBytes
expr: http_response_size_bytes{job="default/example-app", quantile="0.99"} > 30
for: 10m
labels:
severity: page
annotations:
summary: We need more bytes in response!
EOF
ruleSelector.matchLabels в Prometheus описі має збігатись із labels в PrometheusRule. Інакше Prometheus-оператор їх буде ігнорувати.
Тепер можна відкрити http://localhost:9090/alerts та http://localhost:9093/#/alerts і пересвідчитись в тому, що нотифікації справді існують і складові система працюють разом.
FEW WORDS REGARDING KUBE-PROMETHEUS
Як я вже говорив, Kube-prometheus розвивається в межах основного проекту. Він надає готові конфігурації для менеджменту всіх найважливіших системних ресурсів Kubernetes на кшалт вузлів кластеру, системних сервісів і т.п. В тому числі цей репозиторій включає установку Графани та дашбордів до неї.
Установка його така ж проста як і основного оператора. Для початку перестворимо minikube, що використовували раніше:
$ minikube delete && minikube start --kubernetes-version=v1.23.0 --memory=6g --bootstrapper=kubeadm --extra-config=kubelet.authentication-token-webhook=true --extra-config=kubelet.authorization-mode=Webhook --extra-config=scheduler.bind-address=0.0.0.0 --extra-config=controller-manager.bind-address=0.0.0.0
Та застосуємо код в репозиторію:
$ git clone git@github.com:prometheus-operator/kube-prometheus.git
$ cd kube-prometheus
$ kubectl apply --server-side -f manifests/setup
$ kubectl apply -f manifests/
Цього разу функціонал metrics-server вже покривається окремим адаптером тому його потрібно заборонити:
$ minikube addons disable metrics-server
Цього разу ввесь стек буде проінтсальовано в monitoring неймспейс:
$ kubectl get deploy -n monitoring
NAME READY UP-TO-DATE AVAILABLE AGE
blackbox-exporter 1/1 1 1 11m
grafana 1/1 1 1 11m
kube-state-metrics 1/1 1 1 11m
prometheus-adapter 2/2 2 2 11m
prometheus-operator 1/1 1 1 11m
Додавання своїх сервісів для моніторингу відбувається аналогічним чином, проте попередньо потрібно заглянути в конфіг Прометеуса, щоб побачити які налаштування лейблів він приймає:
$ kubectl get prometheus -n monitoring
NAME VERSION REPLICAS AGE
k8s 2.36.1 2 19m
$ kubectl -n monitoring get prometheus k8s -o yaml
kind: Prometheus
metadata:
annotations:
...
spec:
alerting:
alertmanagers:
- apiVersion: v2
name: alertmanager-main
namespace: monitoring
port: web
...
podMonitorNamespaceSelector: {}
podMonitorSelector: {}
probeNamespaceSelector: {}
probeSelector: {}
replicas: 2
resources:
requests:
memory: 400Mi
ruleNamespaceSelector: {}
ruleSelector: {}
scrapeInterval: 30s
securityContext:
fsGroup: 2000
runAsNonRoot: true
runAsUser: 1000
serviceAccountName: prometheus-k8s
serviceMonitorNamespaceSelector: {}
serviceMonitorSelector: {}
version: 2.36.1
status:
availableReplicas: 2
conditions:
...
unavailableReplicas: 0
updatedReplicas: 2
Тут, як і в prometheus-operator, немає обмежень на лейбли podMonitor та ServiceMonitor. Але в операторі, що виливається ком'юніті helm-чартом kube-prometheus-stack такі є:
$ kubectl get prometheus kube-prometheus-stack-prometheus -o yaml
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
...
podMonitorNamespaceSelector: {}
podMonitorSelector:
matchLabels:
release: kube-prometheus-stack
portName: http-web
probeNamespaceSelector: {}
probeSelector:
matchLabels:
release: kube-prometheus-stack
replicas: 1
retention: 10d
routePrefix: /
ruleNamespaceSelector: {}
ruleSelector:
matchLabels:
release: kube-prometheus-stack
scrapeInterval: 30s
securityContext:
fsGroup: 2000
runAsGroup: 2000
runAsNonRoot: true
runAsUser: 1000
serviceAccountName: kube-prometheus-stack-prometheus
serviceMonitorNamespaceSelector: {}
serviceMonitorSelector:
matchLabels:
release: kube-prometheus-stack
...
Toбто podMonitor/ServiceMonitor мають бути із додатковим лейблом 'release: kube-prometheus-stack' (в залежності яка була обрана вами назва Helm реліза) щоб їх помітив оператор Prometheus.
Посилання:
https://blog.container-solutions.com/prometheus-operator-beginners-guide
https://github.com/prometheus-operator/prometheus-operator
https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/getting-started.md
https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/alerting.md
https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/design.md
Немає коментарів:
Дописати коментар