Prometheus Operator 安裝配置|最新版


介紹

Prometheus Operator 為 Kubernetes 提供了對 Prometheus 機器相關監控組件的本地部署和管理方案,該項目的目的是為了簡化和自動化基於 Prometheus 的監控棧配置,主要包括以下幾個功能:

  • Kubernetes 自定義資源:使用 Kubernetes CRD 來部署和管理 Prometheus、Alertmanager 和相關組件。
  • 簡化的部署配置:直接通過 Kubernetes 資源清單配置 Prometheus,比如版本、持久化、副本、保留策略等等配置。
  • Prometheus 監控目標配置:基於熟知的 Kubernetes 標簽查詢自動生成監控目標配置,無需學習 Prometheus 特地的配置。

首先我們先來了解下 Prometheus Operator 的架構圖:

 

上圖是 Prometheus-Operator 官方提供的架構圖,各組件以不同的方式運行在 Kubernetes 集群中,其中 Operator 是最核心的部分,作為一個控制器,他會去創建 Prometheus、ServiceMonitor、AlertManager 以及 PrometheusRule 等 CRD 資源對象,然后會一直 Watch 並維持這些資源對象的狀態。

在最新版本的 Operator 中提供了以下幾個 CRD 資源對象:

  • Prometheus
  • Alertmanager
  • ServiceMonitor
  • PodMonitor
  • Probe
  • ThanosRuler
  • PrometheusRule
  • AlertmanagerConfig

Prometheus

該 CRD 聲明定義了 Prometheus 期望在 Kubernetes 集群中運行的配置,提供了配置選項來配置副本、持久化、報警實例等。

對於每個 Prometheus CRD 資源,Operator 都會以 StatefulSet 形式在相同的命名空間下部署對應配置的資源,Prometheus Pod 的配置是通過一個包含 Prometheus 配置的名為 <prometheus-name>  的 Secret 對象聲明掛載的。

該 CRD 根據標簽選擇來指定部署的 Prometheus 實例應該覆蓋哪些 ServiceMonitors,然后 Operator 會根據包含的 ServiceMonitors 生成配置,並在包含配置的 Secret 中進行更新。

如果未提供對 ServiceMonitor 的選擇,則 Operator 會將 Secret 的管理留給用戶,這樣就可以提供自定義配置,同時還能享受 Operator 管理 Operator 的設置能力。

Alertmanager

該 CRD 定義了在 Kubernetes 集群中運行的 Alertmanager 的配置,同樣提供了多種配置,包括持久化存儲。

對於每個 Alertmanager 資源,Operator 都會在相同的命名空間中部署一個對應配置的 StatefulSet,Alertmanager Pods 被配置為包含一個名為 <alertmanager-name> 的 Secret,該 Secret 以 alertmanager.yaml 為 key 的方式保存使用的配置文件。

當有兩個或更多配置的副本時,Operator 會在高可用模式下運行 Alertmanager 實例。

ThanosRuler

該 CRD 定義了一個 Thanos Ruler 組件的配置,以方便在 Kubernetes 集群中運行。通過 Thanos Ruler,可以跨多個Prometheus 實例處理記錄和警報規則。

一個 ThanosRuler 實例至少需要一個 queryEndpoint,它指向 Thanos Queriers 或 Prometheus 實例的位置。queryEndpoints 用於配置 Thanos 運行時的 --query 參數,更多信息也可以在 Thanos 文檔中找到。

ServiceMonitor

該 CRD 定義了如何監控一組動態的服務,使用標簽選擇來定義哪些 Service 被選擇進行監控。這可以讓團隊制定一個如何暴露監控指標的規范,然后按照這些規范自動發現新的服務,而無需重新配置。

為了讓 Prometheus 監控 Kubernetes 內的任何應用,需要存在一個 Endpoints 對象,Endpoints 對象本質上是IP地址的列表,通常 Endpoints 對象是由 Service 對象來自動填充的,Service 對象通過標簽選擇器匹配 Pod,並將其添加到Endpoints 對象中。一個 Service 可以暴露一個或多個端口,這些端口由多個 Endpoints 列表支持,這些端點一般情況下都是指向一個 Pod。

Prometheus Operator 引入的這個 ServiceMonitor 對象就會發現這些 Endpoints 對象,並配置 Prometheus 監控這些 Pod。ServiceMonitorSpec 的 endpoints 部分就是用於配置這些 Endpoints 的哪些端口將被 scrape 指標的。

注意:endpoints(小寫)是 ServiceMonitor CRD 中的字段,而 Endpoints(大寫)是 Kubernetes 的一種對象。

ServiceMonitors 以及被發現的目標都可以來自任何命名空間,這對於允許跨命名空間監控的場景非常重要。使用 PrometheusSpec 的 ServiceMonitorNamespaceSelector,可以限制各自的 Prometheus 服務器選擇的 ServiceMonitors 的命名空間。使用 ServiceMonitorSpec 的 namespaceSelector,可以限制 Endpoints 對象被允許從哪些命名空間中發現,要在所有命名空間中發現目標,namespaceSelector 必須為空:

spec:
  namespaceSelector:
    any: true

PodMonitor

該 CRD 用於定義如何監控一組動態 pods,使用標簽選擇來定義哪些 pods 被選擇進行監控。同樣團隊中可以制定一些規范來暴露監控的指標。

Pod 是一個或多個容器的集合,可以在一些端口上暴露 Prometheus 指標。

由 Prometheus Operator 引入的 PodMonitor 對象會發現這些 Pod,並為 Prometheus 服務器生成相關配置,以便監控它們。

PodMonitorSpec 中的 PodMetricsEndpoints 部分,用於配置 Pod 的哪些端口將被 scrape 指標,以及使用哪些參數。

PodMonitors 和發現的目標可以來自任何命名空間,這同樣對於允許跨命名空間的監控用例是很重要的。使用 PodMonitorSpec 的 namespaceSelector,可以限制 Pod 被允許發現的命名空間,要在所有命名空間中發現目標,namespaceSelector 必須為空:

spec:
  namespaceSelector:
    any: true

PodMonitor 和 ServieMonitor 最大的區別就是不需要有對應的 Service。

Probe

該 CRD 用於定義如何監控一組 Ingress 和靜態目標。除了 target 之外,Probe 對象還需要一個 prober,它是監控的目標並為 Prometheus 提供指標的服務。例如可以通過使用 blackbox-exporter 來提供這個服務。

PrometheusRule

用於配置 Prometheus 的 Rule 規則文件,包括 recording rules 和 alerting,可以自動被 Prometheus 加載。

AlertmanagerConfig

在以前的版本中要配置 Alertmanager 都是通過 Configmap 來完成的,在 v0.43 版本后新增該 CRD,可以將 Alertmanager 的配置分割成不同的子對象進行配置,允許將報警路由到自定義 Receiver 上,並配置抑制規則。

AlertmanagerConfig 可以在命名空間級別上定義,為 Alertmanager 提供一個聚合的配置。這里提供了一個如何使用它的例子。不過需要注意這個 CRD 還不穩定。

這樣我們要在集群中監控什么數據,就變成了直接去操作 Kubernetes 集群的資源對象了,是這樣比之前手動的方式就方便很多了。

安裝

為了使用 Prometheus-Operator,這里我們直接使用 kube-prometheus 這個項目來進行安裝,該項目和 Prometheus-Operator 的區別就類似於 Linux 內核和 CentOS/Ubuntu 這些發行版的關系,真正起作用的是 Operator 去實現的,而 kube-prometheus 只是利用 Operator 編寫了一系列常用的監控資源清單。

首先 clone 項目代碼,切換到當前最新的 v0.7.0 版本:

$ git clone https://github.com/prometheus-operator/kube-prometheus.git
$ cd kube-prometheus && git checkout v0.7.0

首先創建需要的命名空間和 CRDs,等待它們可用后再創建其余資源:

$ kubectl apply -f manifests/setup
$ until kubectl get servicemonitors --all-namespaces ; do date; sleep 1; echo ""; done
$ kubectl apply -f manifests/

進入到 manifests 目錄下面,首先我們需要安裝 setup 目錄下面的 CRD 和 Operator 資源對象,等待它們可用后再創建其余資源:

$ kubectl apply -f setup/
$ kubectl get pods -n monitoring
NAME                                   READY   STATUS    RESTARTS   AGE
prometheus-operator-7649c7454f-wqtx7   2/2     Running   0          2m42s

這會創建一個名為 monitoring 的命名空間,以及相關的 CRD 資源對象聲明和 Prometheus Operator 控制器。前面章節中我們講解過 CRD 和 Operator 的使用,當我們聲明完 CRD 過后,就可以來自定義資源清單了,但是要讓我們聲明的自定義資源對象生效就需要安裝對應的 Operator 控制器,這里我們都已經安裝了,所以接下來就可以來用 CRD 創建真正的自定義資源對象了。在 manifests 目錄下面的就是我們要去創建的 Prometheus、Alertmanager 以及各種監控對象的資源清單,直接安裝即可:

$ kubectl apply -f manifests/

這會自動安裝 node-exporter、kube-state-metrics、grafana、prometheus-adapter 以及 prometheus 和 alertmanager 等大量組件,而且 prometheus 和 alertmanager 還是多副本的。

$ kubectl get pods -n monitoring
NAME                                   READY   STATUS    RESTARTS   AGE
alertmanager-main-0                    2/2     Running   0          12m
alertmanager-main-1                    2/2     Running   0          12m
alertmanager-main-2                    2/2     Running   0          12m
grafana-f8cd57fcf-kbnsj                1/1     Running   0          12m
kube-state-metrics-587bfd4f97-pwk5p    3/3     Running   0          12m
node-exporter-djwtz                    2/2     Running   0          12m
node-exporter-k7zl9                    2/2     Running   0          12m
node-exporter-rlnjt                    2/2     Running   0          12m
prometheus-adapter-69b8496df6-vq7bl    1/1     Running   0          12m
prometheus-k8s-0                       2/2     Running   0          12m
prometheus-k8s-1                       1/2     Running   0          12m
prometheus-operator-7649c7454f-wqtx7   2/2     Running   0          16m
$ kubectl get svc -n monitoring                      
NAME                    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
alertmanager-main       ClusterIP   10.104.5.112     <none>        9093/TCP                     4m58s
alertmanager-operated   ClusterIP   None             <none>        9093/TCP,9094/TCP,9094/UDP   4m58s
grafana                 ClusterIP   10.107.173.231   <none>        3000/TCP                     4m52s
kube-state-metrics      ClusterIP   None             <none>        8443/TCP,9443/TCP            4m51s
node-exporter           ClusterIP   None             <none>        9100/TCP                     4m51s
prometheus-adapter      ClusterIP   10.104.205.68    <none>        443/TCP                      4m50s
prometheus-k8s          ClusterIP   10.105.168.183   <none>        9090/TCP                     4m49s
prometheus-operated     ClusterIP   None             <none>        9090/TCP                     4m50s
prometheus-operator     ClusterIP   None             <none>        8443/TCP                     8m54s

可以看到上面針對 grafana、alertmanager 和 prometheus 都創建了一個類型為 ClusterIP 的 Service,當然如果我們想要在外網訪問這兩個服務的話可以通過創建對應的 Ingress 對象或者使用 NodePort 類型的 Service,我們這里為了簡單,直接使用 NodePort 類型的服務即可,編輯 grafanaalertmanager-main 和 prometheus-k8s 這3個 Service,將服務類型更改為 NodePort:

# 將 type: ClusterIP 更改為 type: NodePort
$ kubectl edit svc grafana -n monitoring  
$ kubectl edit svc alertmanager-main -n monitoring
$ kubectl edit svc prometheus-k8s -n monitoring
$ kubectl get svc -n monitoring
NAME                    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
alertmanager-main       NodePort    10.111.28.173    <none>        9093:30733/TCP               18m
grafana                 NodePort    10.99.62.32      <none>        3000:32150/TCP               17m
prometheus-k8s          NodePort    10.111.105.155   <none>        9090:30206/TCP               17m
......

kubectl get svc  grafana -o yaml -n monitoring

apiVersion: v1
kind: Service
metadata:
  labels:
    app: grafana
  name: grafana
  namespace: monitoring
  resourceVersion: "72761933"
spec:
  clusterIP: 10.96.0.139
  externalTrafficPolicy: Cluster
  ports:
  - name: http
    nodePort: 32150
    port: 3000
    protocol: TCP
    targetPort: http
  selector:
    app: grafana
  sessionAffinity: None
  type: NodePort
status:
  loadBalancer: {}

  

kubectl get svc alertmanager-main -o yaml  -n monitoring
apiVersion: v1
kind: Service
metadata:
  labels:
    alertmanager: main
  name: alertmanager-main
  namespace: monitoring
spec:
  clusterIP: 10.96.153.208
  externalTrafficPolicy: Cluster
  ports:
  - name: web
    nodePort: 30733
    port: 9093
    protocol: TCP
    targetPort: web
  selector:
    alertmanager: main
    app: alertmanager
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800
  type: NodePort
status:
  loadBalancer: {}

  

 kubectl get svc prometheus-k8s  -o yaml  -n monitoring
apiVersion: v1
kind: Service
metadata:
  labels:
    prometheus: k8s
  name: prometheus-k8s
  namespace: monitoring
spec:
  clusterIP: 10.96.53.255
  externalTrafficPolicy: Cluster
  ports:
  - name: web
    nodePort: 30206
    port: 9090
    protocol: TCP
    targetPort: web
  selector:
    app: prometheus
    prometheus: k8s
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800
  type: NodePort
status:
  loadBalancer: {}

  

 

更改完成后,我們就可以通過上面的 NodePort 去訪問對應的服務了,比如查看 prometheus 的服務發現頁面:

 

可以看到已經監控上了很多指標數據了,上面我們可以看到 Prometheus 是兩個副本,我們這里通過 Service 去訪問,按正常來說請求是會去輪詢訪問后端的兩個 Prometheus 實例的,但實際上我們這里訪問的時候始終是路由到后端的一個實例上去,因為這里的 Service 在創建的時候添加了 sessionAffinity: ClientIP 這樣的屬性,會根據 ClientIP 來做 session 親和性,所以我們不用擔心請求會到不同的副本上去:

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

為什么會擔心請求會到不同的副本上去呢?正常多副本應該是看成高可用的常用方案,理論上來說不同副本本地的數據是一致的,但是需要注意的是 Prometheus 的主動 Pull 拉取監控指標的方式,由於抓取時間不能完全一致,即使一致也不一定就能保證網絡沒什么問題,所以最終不同副本下存儲的數據很大可能是不一樣的,所以這里我們配置了 session 親和性,可以保證我們在訪問數據的時候始終是一致的。

配置

我們可以看到上面的監控指標大部分的配置都是正常的,只有兩三個沒有管理到對應的監控目標,比如 kube-controller-manager 和 kube-scheduler 這兩個系統組件。

 

這其實就和 ServiceMonitor 的定義有關系了,我們先來查看下 kube-scheduler 組件對應的 ServiceMonitor 資源的定義:

# manifests/prometheus-serviceMonitorKubeScheduler.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  labels:
    k8s-app: kube-scheduler
  name: kube-scheduler
  namespace: monitoring
spec:
  endpoints:
  - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token  # token 文件
    interval: 30s  # 每30s獲取一次信息
    port: https-metrics  # 對應 service 的端口名
    scheme: https  # 注意是使用 https 協議
    tlsConfig:  # 跳過安全校驗
      insecureSkipVerify: true
  jobLabel: k8s-app  # 用於從中檢索任務名稱的標簽
  namespaceSelector:  # 表示去匹配某一命名空間中的 Service,如果想從所有的namespace中匹配用any:true
    matchNames:
    - kube-system
  selector:  # 匹配的 Service 的 labels,如果使用 mathLabels,則下面的所有標簽都匹配時才會匹配該 service,如果使用 matchExpressions,則至少匹配一個標簽的 service 都會被選擇
    matchLabels:
      k8s-app: kube-scheduler

上面是一個典型的 ServiceMonitor 資源對象的聲明方式,上面我們通過 selector.matchLabels 在 kube-system 這個命名空間下面匹配具有 k8s-app=kube-scheduler 這樣的 Service,但是我們系統中根本就沒有對應的 Service:

$ kubectl get svc -n kube-system -l k8s-app=kube-scheduler
No resources found in kube-system namespace.

所以我們需要去創建一個對應的 Service 對象,才能與 ServiceMonitor 進行關聯:

# prometheus-kubeSchedulerService.yaml
apiVersion: v1
kind: Service
metadata:
  namespace: kube-system
  name: kube-scheduler
  labels:  # 必須和上面的 ServiceMonitor 下面的 matchLabels 保持一致
    k8s-app: kube-scheduler
spec:
  selector:
    component: kube-scheduler
  ports:
  - name: https-metrics
    port: 10259  
    targetPort: 10259  # 需要注意現在版本默認的安全端口是10259

其中最重要的是上面 labels 和 selector 部分,labels 區域的配置必須和我們上面的 ServiceMonitor 對象中的 selector 保持一致,selector 下面配置的是 component=kube-scheduler,為什么會是這個 label 標簽呢,我們可以去 describe 下 kube-scheduler 這個 Pod:

$ kubectl describe pod kube-scheduler-master1 -n kube-system
Name:                 kube-scheduler-master1
Namespace:            kube-system
Priority:             2000001000
Priority Class Name:  system-node-critical
Node:                 master1/192.168.31.75
Start Time:           Mon, 29 Mar 2021 18:15:46 +0800
Labels:               component=kube-scheduler
                      tier=control-plane
......

我們可以看到這個 Pod 具有 component=kube-scheduler 和 tier=control-plane 這兩個標簽,而前面這個標簽具有更唯一的特性,所以使用前面這個標簽較好,這樣上面創建的 Service 就可以和我們的 Pod 進行關聯了,直接創建即可:

$ kubectl apply -f prometheus-kubeSchedulerService.yaml
$ kubectl get svc -n kube-system -l k8s-app=kube-scheduler
NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)     AGE
kube-scheduler   ClusterIP   10.100.66.246   <none>        10251/TCP   2m2s

創建完成后,隔一小會兒后去 Prometheus 頁面上查看 targets 下面 kube-scheduler 已經有采集的目標了,但是報了 connect: connection refused 這樣的錯誤:

 

這是因為 kube-scheduler 啟動的時候默認綁定的是 127.0.0.1 地址,所以要通過 IP 地址去訪問就被拒絕了,我們可以查看 master 節點上的靜態 Pod 資源清單來確認這一點:

# /etc/kubernetes/manifests/kube-scheduler.yaml
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    component: kube-scheduler
    tier: control-plane
  name: kube-scheduler
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-scheduler
    - --authentication-kubeconfig=/etc/kubernetes/scheduler.conf
    - --authorization-kubeconfig=/etc/kubernetes/scheduler.conf
    - --bind-address=127.0.0.1  # 綁定了127.0.0.1
    - --kubeconfig=/etc/kubernetes/scheduler.conf
    - --leader-elect=true
    - --port=0  # 如果為0,則不提供 HTTP 服務,--secure-port 默認值:10259,通過身份驗證和授權為 HTTPS 服務的端口,如果為 0,則不提供 HTTPS。
......

我們可以直接將上面的 --bind-address=127.0.0.1 更改為 --bind-address=0.0.0.0 即可,更改后 kube-scheduler 會自動重啟,重啟完成后再去查看 Prometheus 上面的采集目標就正常了。

可以用同樣的方式來修復下 kube-controller-manager 組件的監控,創建一個如下所示的 Service 對象,只是端口改成 10257:

# prometheus-kubeControllerManagerService.yaml
apiVersion: v1
kind: Service
metadata:
  namespace: kube-system
  name: kube-controller-manager
  labels:
    k8s-app: kube-controller-manager
spec:
  selector:
    component: kube-controller-manager
  ports:
  - name: https-metrics
    port: 10257
    targetPort: 10257  # controller-manager 的安全端口為10257

然后將 kube-controller-manager 靜態 Pod 的資源清單文件中的參數 --bind-address=127.0.0.1 更改為 --bind-address=0.0.0.0

 

上面的監控數據配置完成后,我們就可以去查看下 Grafana 下面的監控圖表了,同樣使用上面的 NodePort 訪問即可,第一次登錄使用 admin:admin 登錄即可,進入首頁后,我們可以發現其實 Grafana 已經有很多配置好的監控圖表了。

 

我們可以隨便選擇一個 Dashboard 查看監控圖表信息。

 

接下來我們再來學習如何完全自定義一個 ServiceMonitor 以及其他的相關配置。

如果要清理 Prometheus-Operator,可以直接刪除對應的資源清單即可:

$ kubectl delete -f manifests/ 
$ kubectl delete -f manifests/setup/

 


免責聲明!

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



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