Prometheus Operator 教程:根據服務維度對 Prometheus 分片


原文鏈接:https://fuckcloudnative.io/posts/aggregate-metrics-user-prometheus-operator/

Promtheus 本身只支持單機部署,沒有自帶支持集群部署,也不支持高可用以及水平擴容,它的存儲空間受限於本地磁盤的容量。同時隨着數據采集量的增加,單台 Prometheus 實例能夠處理的時間序列數會達到瓶頸,這時 CPU 和內存都會升高,一般內存先達到瓶頸,主要原因有:

  • Prometheus 的內存消耗主要是因為每隔 2 小時做一個 Block 數據落盤,落盤之前所有數據都在內存里面,因此和采集量有關。
  • 加載歷史數據時,是從磁盤到內存的,查詢范圍越大,內存越大。這里面有一定的優化空間。
  • 一些不合理的查詢條件也會加大內存,如 Group 或大范圍 Rate

這個時候要么加內存,要么通過集群分片來減少每個實例需要采集的指標。本文就來討論通過 Prometheus Operator 部署的 Prometheus 如何根據服務維度來拆分實例。

1. 根據服務維度拆分 Prometheus

Prometheus 主張根據功能或服務維度進行拆分,即如果要采集的服務比較多,一個 Prometheus 實例就配置成僅采集和存儲某一個或某一部分服務的指標,這樣根據要采集的服務將 Prometheus 拆分成多個實例分別去采集,也能一定程度上達到水平擴容的目的。

在 Kubernetes 集群中,我們可以根據 namespace 來拆分 Prometheus 實例,例如將所有 Kubernetes 集群組件相關的監控發送到一個 Prometheus 實例,將其他所有監控發送到另一個 Prometheus 實例。

Prometheus Operator 通過 CRD 資源名 Prometheus 來控制 Prometheus 實例的部署,其中可以通過在配置項 serviceMonitorNamespaceSelectorpodMonitorNamespaceSelector 中指定標簽來限定抓取 target 的 namespace。例如,將 namespace kube-system 打上標簽 monitoring-role=system,將其他的 namespace 打上標簽 monitoring-role=others

2. 告警規則拆分

將 Prometheus 拆分成多個實例之后,就不能再使用默認的告警規則了,因為默認的告警規則是針對所有 target 的監控指標的,每一個 Prometheus 實例都無法獲取所有 target 的監控指標,勢必會一直報警。為了解決這個問題,需要對告警規則進行拆分,使其與每個 Prometheus 實例的服務維度一一對應,按照上文的拆分邏輯,這里只需要拆分成兩個告警規則,打上不同的標簽,然后在 CRD 資源 Prometheus 中通過配置項 ruleSelector 指定規則標簽來選擇相應的告警規則。

3. 集中數據存儲

解決了告警問題之后,還有一個問題,現在監控數據比較分散,使用 Grafana 查詢監控數據時我們也需要添加許多數據源,而且不同數據源之間的數據還不能聚合查詢,監控頁面也看不到全局的視圖,造成查詢混亂的局面。

為了解決這個問題,我們可以讓 Prometheus 不負責存儲數據,只將采集到的樣本數據通過 Remote Write 的方式寫入遠程存儲的 Adapter,然后將 Grafana 的數據源設為遠程存儲的地址,就可以在 Grafana 中查看全局視圖了。這里選擇 VictoriaMetrics 來作為遠程存儲。VictoriaMetrics 是一個高性能,低成本,可擴展的時序數據庫,可以用來做 Prometheus 的長期存儲,分為單機版本和集群版本,均已開源。如果數據寫入速率低於每秒一百萬個數據點,官方建議使用單節點版本而不是集群版本。本文作為演示,僅使用單機版本,架構如圖:

4. 實踐

確定好了方案之后,下面來進行動手實踐。

部署 VictoriaMetrics

首先部署一個單實例的 VictoriaMetrics,完整的 yaml 如下:

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: victoriametrics
  namespace: kube-system
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 100Gi
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    app: victoriametrics
  name: victoriametrics
  namespace: kube-system
spec:
  serviceName: pvictoriametrics
  selector:
    matchLabels:
      app: victoriametrics
  replicas: 1
  template:
    metadata:
      labels:
        app: victoriametrics
    spec:
      nodeSelector:
        blog: "true"
      containers:    
      - args:
        - --storageDataPath=/storage
        - --httpListenAddr=:8428
        - --retentionPeriod=1
        image: victoriametrics/victoria-metrics
        imagePullPolicy: IfNotPresent
        name: victoriametrics
        ports:
        - containerPort: 8428
          protocol: TCP
        readinessProbe:
          httpGet:
            path: /health
            port: 8428
          initialDelaySeconds: 30
          timeoutSeconds: 30
        livenessProbe:
          httpGet:
            path: /health
            port: 8428
          initialDelaySeconds: 120
          timeoutSeconds: 30
        resources:
          limits:
            cpu: 2000m
            memory: 2000Mi
          requests:
            cpu: 2000m
            memory: 2000Mi
        volumeMounts:
        - mountPath: /storage
          name: storage-volume
      restartPolicy: Always
      priorityClassName: system-cluster-critical
      volumes:
      - name: storage-volume
        persistentVolumeClaim:
          claimName: victoriametrics
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: victoriametrics
  name: victoriametrics
  namespace: kube-system
spec:
  ports:
  - name: http
    port: 8428
    protocol: TCP
    targetPort: 8428
  selector:
    app: victoriametrics
  type: ClusterIP

有幾個啟動參數需要注意:

  • storageDataPath : 數據目錄的路徑。 VictoriaMetrics 將所有數據存儲在此目錄中。
  • retentionPeriod : 數據的保留期限(以月為單位)。舊數據將自動刪除。默認期限為1個月。
  • httpListenAddr : 用於監聽 HTTP 請求的 TCP 地址。默認情況下,它在所有網絡接口上監聽端口 8428

給 namespace 打標簽

為了限定抓取 target 的 namespace,我們需要給 namespace 打上標簽,使每個 Prometheus 實例只抓取特定 namespace 的指標。根據上文的方案,需要給 kube-system 打上標簽 monitoring-role=system

$ kubectl label ns kube-system monitoring-role=system

給其他的 namespace 打上標簽 monitoring-role=others。例如:

$ kubectl label ns monitoring monitoring-role=others
$ kubectl label ns default monitoring-role=others

拆分 PrometheusRule

告警規則需要根據監控目標拆分成兩個 PrometheusRule。具體做法是將 kube-system namespace 相關的規則整合到一個 PrometheusRule 中,並修改名稱和標簽:

# prometheus-rules-system.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  labels:
    prometheus: system
    role: alert-rules
  name: prometheus-system-rules
  namespace: monitoring
spec:
  groups:
...
...

剩下的放到另外一個 PrometheusRule 中,並修改名稱和標簽:

# prometheus-rules-others.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  labels:
    prometheus: others
    role: alert-rules
  name: prometheus-others-rules
  namespace: monitoring
spec:
  groups:
...
...

然后刪除默認的 PrometheusRule:

$ kubectl -n monitoring delete prometheusrule prometheus-k8s-rules

新增兩個 PrometheusRule:

$ kubectl apply -f prometheus-rules-system.yaml
$ kubectl apply -f prometheus-rules-others.yaml

如果你實在不知道如何拆分規則,或者不想拆分,想做一個伸手黨,可以看這里:

拆分 Prometheus

下一步是拆分 Prometheus 實例,根據上面的方案需要拆分成兩個實例,一個用來監控 kube-system namespace,另一個用來監控其他 namespace:

# prometheus-prometheus-system.yaml
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
  labels:
    prometheus: system 
  name: system
  namespace: monitoring
spec:
  remoteWrite:
    - url: http://victoriametrics.kube-system.svc.cluster.local:8428/api/v1/write
      queueConfig:
        maxSamplesPerSend: 10000
  retention: 2h 
  alerting:
    alertmanagers:
    - name: alertmanager-main
      namespace: monitoring
      port: web
  image: quay.io/prometheus/prometheus:v2.17.2
  nodeSelector:
    beta.kubernetes.io/os: linux
  podMonitorNamespaceSelector:
    matchLabels:
      monitoring-role: system 
  podMonitorSelector: {}
  replicas: 1 
  resources:
    requests:
      memory: 400Mi
    limits:
      memory: 2Gi
  ruleSelector:
    matchLabels:
      prometheus: system 
      role: alert-rules
  securityContext:
    fsGroup: 2000
    runAsNonRoot: true
    runAsUser: 1000
  serviceAccountName: prometheus-k8s
  serviceMonitorNamespaceSelector: 
    matchLabels:
      monitoring-role: system 
  serviceMonitorSelector: {}
  version: v2.17.2
---
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
  labels:
    prometheus: others
  name: others
  namespace: monitoring
spec:
  remoteWrite:
    - url: http://victoriametrics.kube-system.svc.cluster.local:8428/api/v1/write
      queueConfig:
        maxSamplesPerSend: 10000
  retention: 2h
  alerting:
    alertmanagers:
    - name: alertmanager-main
      namespace: monitoring
      port: web
  image: quay.io/prometheus/prometheus:v2.17.2
  nodeSelector:
    beta.kubernetes.io/os: linux
  podMonitorNamespaceSelector: 
    matchLabels:
      monitoring-role: others 
  podMonitorSelector: {}
  replicas: 1
  resources:
    requests:
      memory: 400Mi
    limits:
      memory: 2Gi
  ruleSelector:
    matchLabels:
      prometheus: others 
      role: alert-rules
  securityContext:
    fsGroup: 2000
    runAsNonRoot: true
    runAsUser: 1000
  serviceAccountName: prometheus-k8s
  serviceMonitorNamespaceSelector:
    matchLabels:
      monitoring-role: others 
  serviceMonitorSelector: {}
  additionalScrapeConfigs:
    name: additional-scrape-configs
    key: prometheus-additional.yaml
  version: v2.17.2

需要注意的配置:

  • 通過 remoteWrite 指定 remote write 寫入的遠程存儲。
  • 通過 ruleSelector 指定 PrometheusRule。
  • 限制內存使用上限為 2Gi,可根據實際情況自行調整。
  • 通過 retention 指定數據在本地磁盤的保存時間為 2 小時。因為指定了遠程存儲,本地不需要保存那么長時間,盡量縮短。
  • Prometheus 的自定義配置可以通過 additionalScrapeConfigs 在 others 實例中指定,當然你也可以繼續拆分,放到其他實例中。

刪除默認的 Prometheus 實例:

$ kubectl -n monitoring delete prometheus k8s

創建新的 Prometheus 實例:

$ kubectl apply -f prometheus-prometheus.yaml

查看運行狀況:

$ kubectl -n monitoring get prometheus
NAME     VERSION   REPLICAS   AGE
system   v2.17.2   1          29h
others   v2.17.2   1          29h

$ kubectl -n monitoring get sts
NAME                READY   AGE
prometheus-system   1/1     29h
prometheus-others   1/1     29h
alertmanager-main   1/1     25d

查看每個 Prometheus 實例的內存占用:

$ kubectl -n monitoring top pod -l app=prometheus
NAME                  CPU(cores)   MEMORY(bytes)
prometheus-others-0   12m          110Mi
prometheus-system-0   121m         1182Mi

最后還要修改 Prometheus 的 Service,yaml 如下:

apiVersion: v1
kind: Service
metadata:
  labels:
    prometheus: system 
  name: prometheus-system
  namespace: monitoring
spec:
  ports:
  - name: web
    port: 9090
    targetPort: web
  selector:
    app: prometheus
    prometheus: system
  sessionAffinity: ClientIP
---
apiVersion: v1
kind: Service
metadata:
  labels:
    prometheus: others
  name: prometheus-others
  namespace: monitoring
spec:
  ports:
  - name: web
    port: 9090
    targetPort: web
  selector:
    app: prometheus
    prometheus: others
  sessionAffinity: ClientIP

刪除默認的 Service:

$ kubectl -n monitoring delete svc prometheus-k8s

創建新的 Service:

$ kubectl apply -f prometheus-service.yaml

修改 Grafana 數據源

Prometheus 拆分成功之后,最后還要修改 Grafana 的數據源為 VictoriaMetrics 的地址,這樣就可以在 Grafana 中查看全局視圖,也能聚合查詢。

打開 Grafana 的設置頁面,將數據源修改為 http://victoriametrics.kube-system.svc.cluster.local:8428

點擊 Explore 菜單:

在查詢框內輸入 up,然后按下 Shift+Enter 鍵查詢:

可以看到查詢結果中包含了所有的 namespace

如果你對我的 Grafana 主題配色很感興趣,可以關注公眾號『雲原生實驗室』,后台回復 grafana 即可獲取秘訣。

寫這篇文章的起因是我的 k3s 集群每台節點的資源很緊張,而且監控的 target 很多,導致 Prometheus 直接把節點的內存資源消耗完了,不停地 OOM。為了充分利用我的雲主機,不得不另謀他路,這才有了這篇文章。


Kubernetes 1.18.2 1.17.5 1.16.9 1.15.12離線安裝包發布地址http://store.lameleg.com ,歡迎體驗。 使用了最新的sealos v3.3.6版本。 作了主機名解析配置優化,lvscare 掛載/lib/module解決開機啟動ipvs加載問題, 修復lvscare社區netlink與3.10內核不兼容問題,sealos生成百年證書等特性。更多特性 https://github.com/fanux/sealos 。歡迎掃描下方的二維碼加入釘釘群 ,釘釘群已經集成sealos的機器人實時可以看到sealos的動態。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM