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 型別的服務即可,編輯 grafana
、alertmanager-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
......
更改完成後,我們就可以通過上面的 NodePort 去訪問對應的服務了,比如檢視 prometheus 的服務發現頁面:
prometheus sd
可以看到已經監控上了很多指標資料了,上面我們可以看到 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/