Prometheus Monitoring

不同時期的工作也經歷了不一樣的 Prometheus 安裝和配置, 大致上分成三個

  1. Docker 版本
  2. K8S Deploymemt 版本
  3. K8S Operator

其中一份工作需要把 Docker 版本的 Monitoring 轉到 K8S 上, 原因主要有兩個

  • 希望可以減少需要管理的 EC2
  • EC2 沒辦法直接辨識 K8S 的 Service Name & FQDN

這讓 K8S 服務發現 (Service Discovery) 的實作相對困難, 因為大部分的需要監控的 K8S 服務還得額外透過 Interal Loadbalancer 接出來才能讓 Prometheus 存取

Prometheus in deployment

第一個版本是 Deployment 版本的 Prometheus, 用的是 Artifacthub 的官方 Helm Chart
另外 Chart 裡面也包含了相關的 Sub-Chart, 例如 AlertManager, Kube-State-Metrics, Node-Exporter

這種部署方式相對直覺, 他和傳統 EC2 版本的 Prometheus 的配置維護邏輯很接近, 缺點就是 Prometheus Config 配置之後還得手動 Reload 或是傳送 SIGHUP 讓配置生效, 這點稍微有點麻煩

範例:

# in container prometheus-server
kill -SIGHUP 1

# from debug container
curl -I -X POST http://prometheus-server.monitoring.svc.cluster.local/-/reload/

Helm Chart 執行腳本參考

RELEASE_NAME=prometheus
RELEASE_NAMESPACE=monitoring
#CHART_VERSION=25.25.0
CHART_VERSION=27.11.0

#helm template $RELEASE_NAME prometheus-community/prometheus \
#helm install $RELEASE_NAME prometheus-community/prometheus \
helm upgrade $RELEASE_NAME prometheus-community/prometheus \
--version $CHART_VERSION \
--debug \
--create-namespace \
--namespace $RELEASE_NAMESPACE \
\
--set prometheus-pushgateway.enabled="false" \
--set alertmanager.enabled="true" \
--set kube-state-metrics.enabled="true" \
--set prometheus-node-exporter.enabled="true" \
--set server.ingress.enabled="false" \
\
--set server.persistentVolume.enable="true" \
--set server.persistentVolume.size="1024Gi" \
--set server.nodeSelector.nodegroup="prometheus" \
--set server.retention="180d" \
\
--set server.resources.requests.cpu="500m" \
--set server.resources.requests.memory="500M" \
--set server.resources.limits.cpu="2" \
--set server.resources.limits.memory="4Gi" \
\
--set server.global.scrape_interval="5s" \
--set server.global.scrape_timeout="5s" \
--set server.global.evaluation_interval="5s" \
\
-f ./prometheus/values.yaml \
\
-f ./custom/alerting_rules.yml \
-f ./custom/extraScrapeConfigs.yml \
-f ./custom/alertmanager.yml

原生 Prometheus Config 參數

這裡列舉一些 Prometheus config 內的配置參數:

  • scrape_interval
    • 多久抓一次 metrics 來累積
  • scrape_timeout
    • 每次取得 metrics 需要在幾秒內完成, 否則視為失敗 (先不考慮 exporter 自己壞掉的狀況)
  • evaluation interval
    • 多久做一次告警 (rule) 條件的檢查, 例如 expr: cpu > 80

簡單的邏輯是 Prometheus 會和一個 Time Series Database 時間序列資料庫協作 (預設是 Prometheus TSDB), scrape_configs 裡面的 job 定義了外部的 metrics 資料來源, 這個資料的抓取和評估透過上面提到的三個參數來定義

例如 scrape_interval: 30 代表每 30 秒 scrape_configs 裡面的 job 就會抓一次外部 metrics, 並把結果寫在 TSDB 裡面, 這些資料提供給 rule 使用, 例如 cpu = 70 這樣的資訊

其中 evaluation_interval: 30 定義了 rule 多久從 TSDB 裡面抓一次 scrape 寫入的歷史資料, 每 30 秒抓一次 TSDB 資料套用於 rule 內的規則並產生結果, 像是 cpu > 80 這樣的結果, 這個結果會存在記憶體裡面而非 TSDB 中, 因此重啟 prometheus 會重新累積, 像是 for: 5m 就會從記憶體內查歷史資料來得到告警是否成立這個結果

Evaluate 結果會讓 rule 有以下幾個狀態:

  • inactive
    • evaluate 的結果是 false 狀態就會變成這個
  • pending
    • 在 for 的時間內如果有一次 evalutate 結果成立就會變成 pending, 下次如果不成立就會變成 inactive, for 這個參數就是為了避免短期抖動造成疲勞告警
  • firing
    • 當 for 的時間內如果持續的都成立, 就會變成 firing, 一旦接下來某次 evaluate 結果不成立, 狀態就變回 inactive

範例:

global:
  scrape_interval: 30s # 每個 job 30s 抓一次 metrics
  scrape_timeout: 10s # 每次 job 抓取需要再 10s 內結束, 否則視為失敗
  evaluation_interval: 30s # 每 30 秒評估一次 job 的結果, 也就是 rules 裡面定義的內容

scrape_configs:
  - job_name: 'api-server'
    scrape_interval: 15s        # 複寫 global
    scrape_timeout: 5s          # 複寫 global
    static_configs:
      - targets: ['localhost:8080']
  
  - job_name: 'database'
    static_configs:
      - targets: ['localhost:9090']
    # 使用 global 的 30s

# 也可以 inline 寫 rules, 但是分開比較好管理
rule_files:
  - 'rules.yml'

# 介接的 alertmanager 位置  
alerting:
  alertmanagers:
    - static_configs:
        - targets: ['alertmanager:9093']

範例:rules.yml

groups:
  - name: alerts
    rules:
      - alert: HighCPU
        expr: cpu > 80
        for: 5m
        # 檢查所有 job 的 cpu (不同來源的 exporter 可能會有相同的 metrics)
        # 5m 內累積的所有 scrape 結果都是 Fail 則成立
        
      - alert: APICPUHigh
        expr: cpu{job="api-server"} > 80
        for: 1m
        # 只檢查 api-server 這個 job 定義的 exporter 來源的 cpu metrics

Prometheus with operator

第二個版本是 Operator 版本的 Prometheus, 他也可以透過 Helm 安裝
不同的是官方提供的是另一個 Chart (kube-prometheus-stack), Chart 裡面包含的 Sub-Chart 略有不同, 例如另外還提供了 Grafana, Windows-Export 等額外 Monitoring 相關服務

這個版本的 Prometheus 把許多元件或配置改透過 CRD 的方式實踐
例如 Service Monitor 就類似 Scraping + Service Discovery + Relabel 的綜合體

CRDs

比較常被使用的 Prometheus CRD 大概有以下這幾個:

  • serviceMonitor
    • 對應原生的 scrape_config
  • prometheusRule
    • 對應原生的 rules
  • alertmanagerConfig
    • 對應原生的 alertmanager config
  • scrapeconfigs
    • 若想寫原生的 scrape_config 的話用他

其他有些沒提到的例如 prometheus gloabl or alerting 的配置會在 Prometheus CRD 裡面, 同理 AlertManager CRD 裡面也會有 global 配置

設計上每個 CRD 都是獨立運行的個體, 實際運行在叢集裡的 Prometheus 也不一定只有一個, 因此上述幾個配置也需要透過各種 Selector 來和 Prometheus 配對才會成立, 在 Prometheus CRD 上有這兩種選擇器:

以 ServiceMonitor 為例, Prometheus CRD 裡面會有以下配置:

  # 透過 metadata 裡的 label 來配對
  serviceMonitorSelector:
    matchLabels:
      team: backend
  
  # 透過 namespace 來配對
  serviceMonitorNamespaceSelector:
    matchLabels:
      monitoring: enabled
      
  # 如果希望不要有該條件
  serviceMonitorNamespaceSelector: {}    # 任何 namespace 都可以

同一個 serviceMonitor 是可以因為選擇器配對到兩個不同的 Prometheus 的, 他們之間並不是一對一的關係

ServiceMonitor

顧名思義就是用來自動監控 K8S Service 的工具, 透過 Label Selector 指定對應的 Service 自動加入監控行列, 不用額外針對 Prometheus 做額外配置

範例:
定義一個 serviceMonitor 依據 service label 自動抓取 mariadb service

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: mariadb
  namespace: monitoring
  labels:
    release: kps
    # 這邊要指定 kube-prometheus-stack 的 helm release name
    # 一個叢集不見得只有一組 kube-prometheus-stack
spec:
  endpoints:
    - interval: 15s
      path: /metrics
      port: metrics    #注意:這裡 port 配置的是連接埠名,並非連接埠號碼。
  namespaceSelector:
    matchNames:
    - default
  selector:
    matchLabels:
      app.kubernetes.io/name: mariadb

PrometheusRule

定義告警的規則 (alerting rule), 例如當 CPU 達到 80% 並持續 5 分鐘後告警

範例:
當指定 Deployment 的 Pod 數量為 0 並且維持 1 分鐘以上就告警

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: pod-replica-alert
  namespace: monitoring
  labels:
    release: kps
spec:
  groups:
  - name: pod-replica
    rules:
    - alert: PodReplicaZero
      expr: kube_deployment_status_replicas_available{deployment="debug-tools"} == 0
      for: 1m
      labels:
        severity: critical
      annotations:
        summary: "Pod Replica 數量為 0"
        description: "部署 {{ $labels.deployment }} 的可用 Pod 數量為 0"

AlertmanagerConfig

定義告警傳送的目的地, 例如 Slack, Telegram, Email 等
可以將告警分組 (Group) 並針對 Group 做抑制或是暫時靜默等操作 (也可於 AlertManager Web Ui 處理)

範例:
定義當告警符合指定條件時設定 Telegram 為告警發送對象

apiVersion: monitoring.coreos.com/v1alpha1
kind: AlertmanagerConfig
metadata:
  name: simple-telegram
  namespace: monitoring
  labels:
    release: kps
spec:
  route:
    receiver: 'node-alert'
    groupWait: 5s
    repeatInterval: 5m
    routes:
    - matchers:
      - name:   severity
        value:  critical
        matchType: =
      receiver: 'node-alert'

  receivers:
  - name: 'node-alert'
    telegramConfigs:
    - botToken:
        key: bot_token
        name: telegram-bot-secret
      chatID: you_tg_chat_id
      messageThreadID: 5
      message: |
        🚨 告警通知

        {{ range .Alerts }}
        {{ .Annotations.summary }}
        {{ .Annotations.description }}
        {{ end }}
  - name: 'db-alert'
    telegramConfigs:
    - botToken:
        key: bot_token
        name: telegram-bot-secret
      chatID: you_tg_chat_id
      messageThreadID: 2
      message: |
        🚨 告警通知

        {{ range .Alerts }}
        {{ .Annotations.summary }}
        {{ .Annotations.description }}
        {{ end }}

Bot Token 可透過 TG Bot Father 取得, 並定義為 K8S Secret 供 AlertmanagerConfig 使用

apiVersion: v1
kind: Secret
metadata:
  name: telegram-bot-secret
  namespace: monitoring
type: Opaque
stringData:
  bot_token: your_tg_bot_token
scrapeconfigs

很接近原生的 Scrape Rule, 適合用於 K8S 外部服務監控 (無 Service 可抓取)
或是想直接使用原本的 Scrap Rule 也可以採用
例如 kubernetes_sd_config 這種原生的 Service Discovery

原生官方 CLI 工具

可用於檢測 Prometheus & AlertManager 的配置, 驗證, 查詢等功能, 可參考可觀測中文社區的文件
• promtool
• amtool

promtool

範例:
檢查 promehteus.yml 的配置內容是否合規, 合規則顯示 Success
(在使用 Operator 的情況下就不太會使用這個功能了, 因為配置基本上是 CRD 產生)

/etc/prometheus $ promtool check config prometheus.yml

Checking prometheus.yml
 SUCCESS: prometheus.yml is valid prometheus config file syntax

範例:
檢查 rule file 內容是否合規, 若有問題則會顯示 Failed
(在使用 Operator 的情況下就不太會使用這個功能了, 因為配置基本上是 CRD 產生)

promtool check config monitoring-pod-replica-alert-cfdde215-b9
9a-4cff-bd15-3692e7a9624a.yaml

Checking monitoring-pod-replica-alert-cfdde215-b99a-4cff-bd15-3692e7a9624a.yaml
  FAILED: parsing YAML file monitoring-pod-replica-alert-cfdde215-b99a-4cff-bd15-3692e7a9624a.yaml: yaml: unmarshal errors:
  line 1: field groups not found in type config.plain

promtool 除了 Syntax 檢查之外還可以針對告警規則做單元測試, 以及實際發送 PromQL Query

amtool

範例:

檢查 alertmanager.yml 的配置內容是否合規, 合規則顯示 Success
(在使用 Operator 的情況下就不太會使用這個功能了, 因為配置基本上是 CRD 產生)

/etc/alertmanager $ amtool check-config alertmanager.yml 

Checking 'alertmanager.yml'  SUCCESS
Found:
 - global config
 - route
 - 1 inhibit rules
 - 1 receivers
 - 0 templates

amtool 除了做 syntax 檢查之外也可以檢查當前的 alert, silence, 或是新增或刪除 silence, 但是無法增加告警接收者, 例如新增 Slack 作為 Receiver, 這部分需要透過 Alertmanager 配置檔或是 CRD 來操作

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *