教你如何進行Prometheus 分片自動縮放

华为云开发者联盟發表於2024-04-23

本文分享自華為雲社群《使用 Prometheus-Operator 進行 Prometheus + Keda 分片自動縮放》,作者: Kubeservice@董江。

垂直縮放與水平縮放

Prometheus已經成為雲原生時代事實上的監控工具。從監控小型花園的例項到企業中大規模的監控,Prometheus 都可以處理工作負載!但並非沒有挑戰…

在擁有數百個團隊的大型組織中,每秒獲取數百萬個指標是很常見的。人們可以維護一個 Prometheus 例項,並透過投入資金來解決擴充套件問題:只需獲得一個更大的節點即可。好吧,如果你願意付錢,那就去吧!但是節點價格的增長速度通常高於其大小,並且管理大型和小型 Prometheus 例項之間還有另一個很大的區別:WAL 重播!

Prometheus 保留一個包含最新抓取資料的記憶體資料庫。為了避免在可能的重新啟動期間丟失資料,Prometheus 在磁碟上保留了預寫日誌 (WAL)。當 Prometheus 重啟時,它會將 WAL 重新載入到記憶體中,這樣最新抓取的資料就又可用了,這個操作就是我們所說的 WAL Replay。

在 WAL 重放期間,Prometheus 完全無法進行查詢,也無法抓取任何目標,因此我們希望儘快完成此操作!這就是巨大的 Prometheus 例項成為問題的時候。當將數百 GiB 的資料重放到記憶體中時,此操作很容易需要 20 到 30 分鐘,在更極端的情況下甚至需要幾個小時。如果您決定保留單個 Prometheus 例項,WAL Replay 操作可能會導致監控系統出現長時間停機。

避免大型 Prometheus 例項的一種常見策略是在多個 Prometheus 之間分片抓取目標。由於每個 Prometheus 都會抓取較少量的指標,因此它們會小得多,並且 WAL Replay 不會像以前那樣成為問題。為了仍然能夠擁有集中式查詢體驗,可以將指標轉發到另一個工具,例如 Thanos、Cortex 或雲提供商,這些工具也能夠擴充套件 Prometheus 查詢功能。

整個時間內負載不均勻

我們已經透過使用分片而不是垂直擴充套件 Prometheus 取得了一些重大進展,但是當暴露的指標數量全天增加和減少時會發生什麼?對於每天從數百個節點擴充套件到數千個節點(反之亦然)的 Kubernetes 叢集來說,這是一種非常常見的情況。在決定普羅米修斯碎片的數量時,我們如何找到成本/效益比的最佳點?

您可以每天手動微調叢集中的分片數量,但有更智慧的方法來完成此任務。在這篇博文中,我將重點介紹 Horizo​​ntal Pod Autoscaler 策略,該策略是最近透過 Prometheus-Operator v0.71.0 版本實現的。

使用 Keda 自動縮放 Prometheus 碎片

設定

使用 Kubernetes Scale API 的任何型別的 Horizo​​ntal Pod Autoscaler,但出於演示目的,將使用Keda,它支援多種擴充套件策略。

讓我們從建立一個小型叢集開始,我建議使用KinD或Minikube:

$ kind create cluster
Creating cluster "kind" ...
 ✓ Ensuring node image (kindest/node:v1.27.1) 🖼 
 ✓ Preparing nodes 📦  
 ✓ Writing configuration 📜 
 ✓ Starting control-plane 🕹️ 
 ✓ Installing CNI 🔌 
 ✓ Installing StorageClass 💾 
Set kubectl context to "kind-kind"
You can now use your cluster with:

kubectl cluster-info --context kind-kind

Have a nice day! 👋

現在讓我們安裝 Keda:

$ helm repo add kedacore https://kedacore.github.io/charts
$ helm repo update
$ helm install keda kedacore/keda --namespace keda --create-namespace
$ watch kubectl get pods -n keda

一旦所有 Pod 都達到該Running狀態,我們就可以繼續!下一步是安裝 Prometheus Operator:

$ git clone https://github.com/prometheus-operator/prometheus-operator
$ cd prometheus-operator
$ kubectl apply --server-side -f bundle.yaml

部署 Prometheus 和示例應用程式

好了,初始設定完成了。讓我們部署一些公開一些指標的應用程式!為了演示目的,讓我們部署一個 Alertmanager:

---
apiVersion: monitoring.coreos.com/v1
kind: Alertmanager
metadata:
  name: main
  namespace: monitoring
spec:
  image: quay.io/prometheus/alertmanager:v0.26.0
  podMetadata:
    labels:
      app.kubernetes.io/instance: main
      app.kubernetes.io/name: alertmanager
  replicas: 1
  serviceAccountName: alertmanager-main
---
apiVersion: v1
kind: Service
metadata:
  name: alertmanager-main
  namespace: monitoring
  labels:
    app.kubernetes.io/instance: main
    app.kubernetes.io/name: alertmanager
spec:
  ports:
  - name: web
    port: 9093
    targetPort: web
  - name: reloader-web
    port: 8080
    targetPort: reloader-web
  selector:
    app.kubernetes.io/instance: main
    app.kubernetes.io/name: alertmanager
---
apiVersion: v1
automountServiceAccountToken: false
kind: ServiceAccount
metadata:
  name: alertmanager-main
  namespace: monitoring
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: alertmanager-main
  namespace: monitoring
spec:
  endpoints:
  - interval: 30s
    port: web
  - interval: 30s
    port: reloader-web
  selector:
    matchLabels:
      app.kubernetes.io/instance: main
      app.kubernetes.io/name: alertmanager

還有一個 Prometheus 負責抓取這個 Alertmanager(以及之後部署的更多內容)。我們希望根據每秒抓取的樣本進行擴充套件,因此我們將配置 Prometheus 來抓取自身

apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
  name: k8s
spec:
  image: quay.io/prometheus/prometheus:v2.48.1
  podMetadata:
    labels:
      app.kubernetes.io/instance: k8s
      app.kubernetes.io/name: prometheus
  shards: 1
  serviceAccountName: prometheus-k8s
  serviceMonitorSelector: {}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: prometheus-k8s
rules:
- apiGroups:
  - ""
  resources:
  - configmaps
  verbs:
  - get
- apiGroups:
  - ""
  resources:
  - services
  - endpoints
  - pods
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - extensions
  resources:
  - ingresses
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - networking.k8s.io
  resources:
  - ingresses
  verbs:
  - get
  - list
  - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: prometheus-k8s
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: prometheus-k8s
subjects:
- kind: ServiceAccount
  name: prometheus-k8s
  namespace: default
---
apiVersion: v1
kind: Service
metadata:
  name: prometheus-k8s
  labels:
    app.kubernetes.io/instance: k8s
    app.kubernetes.io/name: prometheus
spec:
  ports:
  - name: web
    port: 9090
    targetPort: web
  - name: reloader-web
    port: 8080
    targetPort: reloader-web
  selector:
    app.kubernetes.io/instance: k8s
    app.kubernetes.io/name: prometheus
---
apiVersion: v1
automountServiceAccountToken: true
kind: ServiceAccount
metadata:
  name: prometheus-k8s
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: prometheus-k8s
spec:
  endpoints:
  - interval: 30s
    port: web
  - interval: 30s
    port: reloader-web
  selector:
    matchLabels:
      app.kubernetes.io/instance: k8s
      app.kubernetes.io/name: prometheus

部署完所有內容後,我們可以透過暴露其 UI 來驗證 Prometheus 的表現:

$ kubectl port-forward prometheus-k8s-0 9090

如果我們查詢指標
sum(rate(prometheus_tsdb_head_samples_appended_total[2m])),
我們會注意到我們穩定在每秒攝取 40~50 個樣本左右。

配置 Keda 來擴充套件/縮小 Prometheus

Keda 的自動縮放物件是透過ScaledObject CRD配置的。 ScaledObjects 有大量不同的縮放器,但在這裡我們將使用Prometheus 縮放器來縮放 Prometheus 本身。

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: prometheus
spec:
  scaleTargetRef:
    apiVersion: monitoring.coreos.com/v1
    kind: Prometheus
    name: k8s
  minReplicaCount:  1
  maxReplicaCount:  100
  fallback:
    failureThreshold: 5
    replicas: 10
  triggers:
  - type: prometheus
    metadata:
      serverAddress: http://prometheus-k8s.svc.default.cluster.local:9090 
      # Ingested samples per second across all shards
      query: sum(rate(prometheus_tsdb_head_samples_appended_total[2m])) 
      # We'll scale up/down on every 200 samples ingested per second
      threshold: '200'

要驗證 ScaledObject 是否按預期工作,請執行:

$ kubectl get scaledobject prometheus

你應該看到這一點STATUS並且ACTIVE兩者都應該是True

觸發擴縮容

現在讓我們開始有趣的部分,首先增加 Alertmanager Pod 的數量:

$ kubectl patch alertmanager main -p '{"spec": {"replicas": 20}}' --type merge

在檢查 Prometheus UI 時,我們會注意到攝取的樣本快速增加:

如果我們檢查 Prometheus Pod 的數量,我們會注意到正在部署新的分片:

$ kubectl get pods -l app.kubernetes.io/name=prometheus
NAME                       READY   STATUS    RESTARTS   AGE
prometheus-k8s-0           2/2     Running   0          21m
prometheus-k8s-shard-1-0   2/2     Running   0          2m54s
prometheus-k8s-shard-2-0   2/2     Running   0          2m24s
prometheus-k8s-shard-3-0   1/2     Running   0          54s

我們還驗證一下,如果負載減少,Prometheus Pod 是否會縮小規模

$ kubectl patch alertmanager main -p '{"spec": {"replicas": 1}}' --type merge

幾分鐘後,分片將返回較少數量的攝取樣本,Keda 應再次調整分片數量:

$ kubectl get pods -l app.kubernetes.io/name=prometheus
NAME               READY   STATUS    RESTARTS   AGE
prometheus-k8s-0   2/2     Running   0          30m

其他

點選關注,第一時間瞭解華為雲新鮮技術~

相關文章