本文分享自華為雲社群《使用 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 叢集來說,這是一種非常常見的情況。在決定普羅米修斯碎片的數量時,我們如何找到成本/效益比的最佳點?
您可以每天手動微調叢集中的分片數量,但有更智慧的方法來完成此任務。在這篇博文中,我將重點介紹 Horizontal Pod Autoscaler 策略,該策略是最近透過 Prometheus-Operator v0.71.0 版本實現的。
使用 Keda 自動縮放 Prometheus 碎片
設定
使用 Kubernetes Scale API 的任何型別的 Horizontal 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
其他
- https://www.arthursens.dev/posts/prometheus-shard-autoscaling
- https://keda.sh/docs/2.13/scalers/prometheus/#integrating-cloud-offerings
點選關注,第一時間瞭解華為雲新鮮技術~