快速部署Kubernetes監控系統Kube-Prometheus
- 1、什么是Kube-Prometheus(Operator) 框架
- 2、Kube-Prometheus部署
- 2.1、Kube-Prometheus安裝
- 2.2、Kube-Prometheus配置
- 3、自定義 Kube-Prometheus 監控項
- 3.1、獲取ETCD證書
- 3.2、創建ServiceMonitor
- 4、Kube-Prometheus數據持久化
- 5、Kube-Prometheus數據持久時間
- 6、Grafana數據持久化
- 7、Kube-Prometheus服務發現
- 8、Kube-Prometheus釘釘告警
1、什么是Kube-Prometheus(Operator) 框架
Operator是由 CoreOS 公司開發的,用來擴展 Kubernetes API,特定的應用程序控制器。它被用來創建、配置和管理復雜的有狀態應用,如數據庫、緩存和監控系統。Operator 是基於 Kubernetes 的資源和控制器概念之上構建,但同時又包含了應用程序特定的一些專業知識:比如創建一個數據庫的Operator,則必須對創建的數據庫的各種運維方式非常了解,創建Operator的關鍵是CRD(自定義資源)的設計。
注:CRD是對 Kubernetes API 的擴展,Kubernetes 中的每個資源都是一個 API 對象的集合,例如我們在 YAML文件里定義的那些spec都是對 Kubernetes 中的資源對象的定義,所有的自定義資源可以跟 Kubernetes 中內建的資源一樣使用 kubectl 操作。
Operator是將運維人員對軟件操作的知識給代碼化,同時利用 Kubernetes 強大的抽象來管理大規模的軟件應用。目前CoreOS官方提供了幾種Operator的實現,其中就包括我們今天的主角:Prometheus Operator,Operator的核心實現就是基於 Kubernetes 的以下兩個概念:
- 資源:對象的狀態定義;
- 控制器:觀測、分析和行動,以調節資源的分布。
在最新的版本中,Kubernetes的 Prometheus-Operator 部署內容已經從 Prometheus-Operator 的 Github工程中拆分出獨立工程Kube-Prometheus。Kube-Prometheus 即是通過 Operator 方式部署的Kubernetes集群監控,所以我們直接容器化部署 Kube-Prometheus 即可。
Kube-Prometheus項目地址:https://github.com/coreos/kube-prometheus
因為我們前面Kubernetes集群的安裝版本為v1.16.8,為了考慮兼容性、這里我們安裝 Kube-Prometheus-Release-0.4 版本。當然大家也可以去 Kube-Prometheus 的文檔中查看兼容性列表,如下:
2、Kube-Prometheus部署
2.1、Kube-Prometheus安裝
下面我們直接開始部署Kube-Prometheus,我們通過 git clone 命令把項目下載到本地以后,直接進入 Kube-Prometheus 根目錄,根目錄下面的 kustomization.yaml 文件中包含了所有相關的容器化配置文件:
# 這里我們下載0.4版本 git clone https://github.com/coreos/kube-prometheus.git cd kube-prometheus cat kustomization.yaml
這里我們直接依次執行下面的命令即可完成安裝:
kubectl create -f manifests/setup
kubectl create -f manifests
部署完成后,會創建一個名為monitoring的 namespace,所以資源對象對將部署在改命名空間下面,此外 Operator 會自動創建6個 CRD 資源對象:
我們可以在 monitoring 命名空間下面查看所有的 Pod和SVC資源,其中 alertmanager 和 prometheus 是用 StatefulSet 控制器管理的,其中還有一個比較核心的 prometheus-operator 的 Pod,用來控制其他資源對象和監聽對象變化的:
kubectl get pod -n monitoring -o wide kubectl get svc -n monitoring -o wide
2.2、Kube-Prometheus配置
我們可以看到大部分的配置都是正常的,只有兩個沒有管理到對應的監控目標,比如 kube-controller-manager 和 kube-scheduler 這兩個系統組件,這就和 ServiceMonitor 的定義有關系了,我們先來查看下 kube-scheduler 組件對應的 ServiceMonitor 資源的定義(prometheus-serviceMonitorKubeScheduler.yaml):
apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: labels: k8s-app: kube-scheduler name: kube-scheduler namespace: monitoring spec: endpoints: - interval: 30s # 每30s獲取一次信息 port: http-metrics # 對應service的端口名 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,所以我們需要手動創建一個 Service(prometheus-kubeSchedulerService.yaml):
apiVersion: v1 kind: Service metadata: namespace: kube-system name: kube-scheduler labels: k8s-app: kube-scheduler spec: #selector: # component: kube-scheduler ports: - name: http-metrics port: 10251 targetPort: 10251 protocol: TCP
我們采用相同的方法創建Kube-Controller-Manager的Service(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: 10252 targetPort: 10252 protocol: TCP
創建完成之后我們通過 kubectl get svc -n kube-system 命令看到對應SVC資源已經生成了:
kubectl get svc -n kube-system
但是此時Prometheus面板的 targets 還是沒有任何顯示,我們通過 kubectl get ep -n kube-system 命令去查看一下 kube-controller-manager 和 kube-scheduler 的endpoints發現並沒有任何endpoints,這里我們需要手動來添加endpoints。我們定義兩個endpoints資源文件,如下:
prometheus-kubeSchedulerServiceEnpoints.yaml
apiVersion: v1 kind: Endpoints metadata: labels: k8s-app: kube-scheduler name: kube-scheduler namespace: kube-system subsets: - addresses: - ip: 172.16.230.51 - ip: 172.16.230.52 - ip: 172.16.230.53 ports: - name: http-metrics port: 10251 protocol: TCP
prometheus-KubeControllerManagerServiceEnpoints.yaml
apiVersion: v1 kind: Endpoints metadata: labels: k8s-app: kube-controller-manager name: kube-controller-manager namespace: kube-system subsets: - addresses: - ip: 172.16.230.51 - ip: 172.16.230.52 - ip: 172.16.230.53 ports: - name: https-metrics port: 10252 protocol: TCP
定義完成之后我們直接去創建上面的兩個endpoints資源,然后我們繼續查看 kube-controller-manager 和 kube-scheduler 的endpoints資源狀態:
kubectl get ep -n kube-system
我們已經成功為 kube-controller-manager 和 kube-scheduler 這兩個SVC資源添加了 Endpoints 資源。但是此時我們去刷新Prometheus的 target 可以看到 monitoring/kube-scheduler/0 數據正常、但是 monitoring/kube-controller-manager/0 狀態顯示為DOWN。錯誤信息為:Server Returned HTTP Status 400 Bad Request。仔細觀察我們會發現、Endpoints 信息為:http://172.16.200.11:10252/metrics,我們在前面部署 kube-controller-manager 明明用的是HTTPS、但是為什么這里就變成 HTTP 了呢?
我們去查看 prometheus-serviceMonitorKubeControllerManager.yaml 文件發現 kube-controller-manager 的 ServiceMonitor kind 端口寫的是 http-metrics。我們需要把Port修改為https-metrics,並添加token信息,這里我們可以 insecureSkipVerify: true 參數禁止掉證書驗證,詳細信息如下:
[root@master1 files]# cat prometheus-serviceMonitorKubeControllerManager.yaml apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: labels: k8s-app: kube-controller-manager name: kube-controller-manager namespace: monitoring spec: endpoints: - interval: 30s bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token #添加 metricRelabelings: - action: drop regex: kubelet_(pod_worker_latency_microseconds|pod_start_latency_microseconds|cgroup_manager_latency_microseconds|pod_worker_start_latency_microseconds|pleg_relist_latency_microseconds|pleg_relist_interval_microseconds|runtime_operations|runtime_operations_latency_microseconds|runtime_operations_errors|eviction_stats_age_microseconds|device_plugin_registration_count|device_plugin_alloc_latency_microseconds|network_plugin_operations_latency_microseconds) sourceLabels: - __name__ - action: drop regex: scheduler_(e2e_scheduling_latency_microseconds|scheduling_algorithm_predicate_evaluation|scheduling_algorithm_priority_evaluation|scheduling_algorithm_preemption_evaluation|scheduling_algorithm_latency_microseconds|binding_latency_microseconds|scheduling_latency_seconds) sourceLabels: - __name__ - action: drop regex: apiserver_(request_count|request_latencies|request_latencies_summary|dropped_requests|storage_data_key_generation_latencies_microseconds|storage_transformation_failures_total|storage_transformation_latencies_microseconds|proxy_tunnel_sync_latency_secs) sourceLabels: - __name__ - action: drop regex: kubelet_docker_(operations|operations_latency_microseconds|operations_errors|operations_timeout) sourceLabels: - __name__ - action: drop regex: reflector_(items_per_list|items_per_watch|list_duration_seconds|lists_total|short_watches_total|watch_duration_seconds|watches_total) sourceLabels: - __name__ - action: drop regex: etcd_(helper_cache_hit_count|helper_cache_miss_count|helper_cache_entry_count|request_cache_get_latencies_summary|request_cache_add_latencies_summary|request_latencies_summary) sourceLabels: - __name__ - action: drop regex: transformation_(transformation_latencies_microseconds|failures_total) sourceLabels: - __name__ - action: drop regex: (admission_quota_controller_adds|crd_autoregistration_controller_work_duration|APIServiceOpenAPIAggregationControllerQueue1_adds|AvailableConditionController_retries|crd_openapi_controller_unfinished_work_seconds|APIServiceRegistrationController_retries|admission_quota_controller_longest_running_processor_microseconds|crdEstablishing_longest_running_processor_microseconds|crdEstablishing_unfinished_work_seconds|crd_openapi_controller_adds|crd_autoregistration_controller_retries|crd_finalizer_queue_latency|AvailableConditionController_work_duration|non_structural_schema_condition_controller_depth|crd_autoregistration_controller_unfinished_work_seconds|AvailableConditionController_adds|DiscoveryController_longest_running_processor_microseconds|autoregister_queue_latency|crd_autoregistration_controller_adds|non_structural_schema_condition_controller_work_duration|APIServiceRegistrationController_adds|crd_finalizer_work_duration|crd_naming_condition_controller_unfinished_work_seconds|crd_openapi_controller_longest_running_processor_microseconds|DiscoveryController_adds|crd_autoregistration_controller_longest_running_processor_microseconds|autoregister_unfinished_work_seconds|crd_naming_condition_controller_queue_latency|crd_naming_condition_controller_retries|non_structural_schema_condition_controller_queue_latency|crd_naming_condition_controller_depth|AvailableConditionController_longest_running_processor_microseconds|crdEstablishing_depth|crd_finalizer_longest_running_processor_microseconds|crd_naming_condition_controller_adds|APIServiceOpenAPIAggregationControllerQueue1_longest_running_processor_microseconds|DiscoveryController_queue_latency|DiscoveryController_unfinished_work_seconds|crd_openapi_controller_depth|APIServiceOpenAPIAggregationControllerQueue1_queue_latency|APIServiceOpenAPIAggregationControllerQueue1_unfinished_work_seconds|DiscoveryController_work_duration|autoregister_adds|crd_autoregistration_controller_queue_latency|crd_finalizer_retries|AvailableConditionController_unfinished_work_seconds|autoregister_longest_running_processor_microseconds|non_structural_schema_condition_controller_unfinished_work_seconds|APIServiceOpenAPIAggregationControllerQueue1_depth|AvailableConditionController_depth|DiscoveryController_retries|admission_quota_controller_depth|crdEstablishing_adds|APIServiceOpenAPIAggregationControllerQueue1_retries|crdEstablishing_queue_latency|non_structural_schema_condition_controller_longest_running_processor_microseconds|autoregister_work_duration|crd_openapi_controller_retries|APIServiceRegistrationController_work_duration|crdEstablishing_work_duration|crd_finalizer_adds|crd_finalizer_depth|crd_openapi_controller_queue_latency|APIServiceOpenAPIAggregationControllerQueue1_work_duration|APIServiceRegistrationController_queue_latency|crd_autoregistration_controller_depth|AvailableConditionController_queue_latency|admission_quota_controller_queue_latency|crd_naming_condition_controller_work_duration|crd_openapi_controller_work_duration|DiscoveryController_depth|crd_naming_condition_controller_longest_running_processor_microseconds|APIServiceRegistrationController_depth|APIServiceRegistrationController_longest_running_processor_microseconds|crd_finalizer_unfinished_work_seconds|crdEstablishing_retries|admission_quota_controller_unfinished_work_seconds|non_structural_schema_condition_controller_adds|APIServiceRegistrationController_unfinished_work_seconds|admission_quota_controller_work_duration|autoregister_depth|autoregister_retries|kubeproxy_sync_proxy_rules_latency_microseconds|rest_client_request_latency_seconds|non_structural_schema_condition_controller_retries) sourceLabels: - __name__ - action: drop regex: etcd_(debugging|disk|request|server).* sourceLabels: - __name__ port: https-metrics #由http-metrics 變成 https-metrics scheme: https #模式支持https tlsConfig: # tlsconfig配置項 insecureSkipVerify: true #忽略驗證 jobLabel: k8s-app namespaceSelector: matchNames: - kube-system selector: matchLabels: k8s-app: kube-controller-manager
我們直接通過 kubectl apply -f prometheus-serviceMonitorKubeControllerManager.yaml 更新上面的資源文件,然后稍等30秒重新刷新 prometheus 頁面。我們可以看到 monitoring/kube-controller-manager/0 這個 target 狀態已經變成UP了。這時我們去看看 Grafana 里面是否有對應數據,當然你也可以通過 PromSQL 來查詢驗證:
上面的監控數據配置完成后,現在我們可以去查看下 Grafana 下面的 Dashboard,我們使用上面配置的Ingress域名訪問即可,第一次登錄使用 admin:admin 登錄即可,進入首頁后,可以發現已經和我們的 Prometheus 數據源關聯上了,正常來說可以看到一些監控圖表了:
3、自定義 Kube-Prometheus 監控項
前面我們講解了 如何快速部署 Kube-Prometheus 監控系統,下面我們繼續介紹如何在 Kube-Prometheus 中添加一個自定義的監控項。除了 Kubernetes 集群中的一些資源對象、節點以及組件需要監控,有的時候我們可能還需要根據實際的業務需求去添加自定義的監控項,添加一個自定義監控的步驟也是非常簡單的。
- 第一步:建立一個 ServiceMonitor 對象,用於 Prometheus 添加監控項;
- 第二步:為 ServiceMonitor 對象關聯 metrics 數據接口的一個 Service 對象;
- 第三步:確保 Service 對象可以正確獲取到 metrics 數據。
接下來我們就來看看如何添加 Etcd 集群的監控。無論是 Kubernetes 集群外的還是使用 Kubeadm 安裝在集群內部的 Etcd 集群,我們這里都將其視作集群外的獨立集群,因為對於二者的使用方法沒什么特殊之處。
etcdServiceMonitor,
cat prometheus-serviceMonitorEtcd.yaml
apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: etcd-k8s namespace: monitoring labels: k8s-app: etcd-k8s spec: jobLabel: k8s-app endpoints: - port: port interval: 30s scheme: https tlsConfig: caFile: /etc/kubernetes/ssl/ca.pem #證書路徑 (Pod里的路徑) certFile: /etc/kubernetes/ssl/etcd.pem keyFile: /etc/kubernetes/ssl/etcd-key.pem insecureSkipVerify: true selector: matchLabels: k8s-app: etcd namespaceSelector: matchNames: - kube-system
上面這個文件我們匹配 Kube-system 這個命名空間下面具有 k8s-app=etcd 這個label標簽的Service,job label用於檢索job任務名稱的標簽。由於證書 serverName 和 etcd 中簽發的證書可能不匹配,所以添加了 insecureSkipVerify=true 將不再對服務端的證書進行校驗。接下來我們直接創建這個ServiceMonitor:
# 創建資源文件 kubectl apply -f prometheus-serviceMonitorEtcd.yaml # 查看servicemonitors資源 kubectl get servicemonitors -n monitoring |grep etcd
我們需要定義一個 Service 對象和一個 Endpoints,對應資源文件如下。
prometheus-EtcdService.yaml:
apiVersion: v1 kind: Service metadata: name: etcd-k8s namespace: kube-system labels: k8s-app: etcd spec: type: ClusterIP clusterIP: None ports: - name: port port: 2379 protocol: TCP
prometheus-EtcdServiceEnpoints.yaml
apiVersion: v1 kind: Endpoints metadata: name: etcd-k8s namespace: kube-system labels: k8s-app: etcd subsets: - addresses: - ip: 172.16.230.51 #etcd節點名稱 #nodeName: etcd1 #kubelet名稱 (kubectl get node)顯示的名稱 - ip: 172.16.230.52 #nodeName: etcd2 - ip: 172.16.230.53 #nodeName: etcd3 ports: - name: port port: 2379 protocol: TCP
然后我們直接創建上面的 Service 對象和 Endpoints 對象:
kubectl apply -f prometheus-EtcdService.yaml
kubectl apply -f prometheus-EtcdServiceEnpoints.yaml
# 查看ETCD狀態 kubectl describe svc -n kube-system etcd-k8s
創建完成后,稍等一會我們可以去Prometheus 里面查看targets,便會出現etcd監控信息:
如果提示ip:2379 connection refused,首先檢查本地Telnet 是否正常,在檢查etcd配置文件是否是監聽0.0.0.0:2379。
數據采集完成后,接下來可以在grafana中導入dashboard。這里我們可以導入 :https://grafana.com/grafana/dashboards/3070;還可以導入中文版ETCD集群插件:https://grafana.com/grafana/dashboards/9733;導入過程這里就不再詳細描述了、不會的小伙伴請自行百度:
4、Kube-Prometheus數據持久化
前面我們需改完Prometheus的相關配置后,重啟了 Prometheus 的 Pod,如果我們仔細觀察的話會發現我們之前采集的數據已經沒有了,這是因為我們通過 Prometheus 這個 CRD 創建的 Prometheus 並沒有做數據的持久化,我們可以直接查看生成的 Prometheus Pod 的掛載情況就清楚了:
kubectl get pod prometheus-k8s-0 -n monitoring -o yaml
從上圖我們可以看到 Prometheus 的數據目錄 /prometheus 實際上是通過 emptyDir 進行掛載的,我們知道 emptyDir 掛載的數據的生命周期和 Pod 生命周期一致的,所以如果 Pod 掛掉了,數據也就丟失了,這也就是為什么我們重建 Pod 后之前的數據就沒有了的原因,對應線上的監控數據肯定需要做數據的持久化的,同樣的 prometheus 這個 CRD 資源也為我們提供了數據持久化的配置方法,由於我們的 Prometheus 最終是通過 Statefulset 控制器進行部署的,所以我們這里需要通過 storageclass 來做數據持久化,首先創建一個 StorageClass 對象(prometheus-storageclass.yaml):
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: prometheus-data-db provisioner: fuseim.pri/ifs
這里我們聲明一個 StorageClass 對象,其中 provisioner=fuseim.pri/ifs,則是因為我們集群中使用的是 nfs 作為存儲后端,而前面我們創建的 nfs-client-provisioner 中指定的 PROVISIONER_NAME 就為 fuseim.pri/ifs,這個名字不能隨便更改。然后我們直接創建這個資源:
kubectl apply -f prometheus-storageclass.yaml kubectl get storageclass
然后在 prometheus 的 CRD 資源對象中添加如下配置:
storage: volumeClaimTemplate: spec: storageClassName: prometheus-data-db resources: requests: storage: 100Gi
注意這里的 storageClassName 名字為上面我們創建的 StorageClass 對象名稱,然后更新 prometheus 這個 CRD 資源。更新完成后會自動生成兩個 PVC 和 PV 資源對象:
# 更新資源文件 kubectl apply -f prometheus-prometheus.yaml # 查看PVC kubectl get pvc -n monitoring # 查看PV kubectl get pv
5、Kube-Prometheus數據持久時間
前面說了prometheus operator持久化的問題,但是還有一個問題很多人都忽略了,那就是prometheus operator數據保留天數,根據官方文檔的說明,默認prometheus operator數據存儲的時間為1d,這個時候無論你prometheus operator如何進行持久化,都沒有作用,因為數據只保留了1天,那么你是無法看到更多天數的數據。
實際上我們修改 Kube-Prometheus 時間是通過 retention 參數進行修改,上面也提示了在prometheus.spec下填寫。這里我們直接修改 prometheus-prometheus.yaml 文件,並添加下面的參數:
注:如果已經安裝了可以直接修改 prometheus-prometheus.yaml 然后通過kubectl apply -f 刷新即可,修改完成以后記得檢查Pod運行狀態是否正常。
接下來可以訪問grafana或者prometheus ui進行檢查 (我這里修改完畢后等待2天,檢查數據是否正常)。
6、Grafana數據持久化
前面我們介紹了關於prometheus的數據持久化、但是沒有介紹如何針對Grafana做數據持久化;如果Grafana不做數據持久化、那么服務重啟以后,Grafana里面配置的Dashboard、賬號密碼等信息將會丟失;所以Grafana做數據持久化也是很有必要的。
原始的數據是以 emptyDir 形式存放在pod里面,生命周期與pod相同;出現問題時,容器重啟,在Grafana里面設置的數據就全部消失了。
volumeMounts: - mountPath: /var/lib/grafana name: grafana-storage readOnly: false ... volumes: - emptyDir: {} name: grafana-storage
從上圖我們可以看出Grafana將dashboard、插件這些數據保存在/var/lib/grafana這個目錄下面。做持久化的話,就需要對這個目錄進行volume掛載聲明。
我們把emptyDir修改為pvc方式:
volumes: - name: grafana-storage persistentVolumeClaim: claimName: grafana
如果要使用一個 pvc 對象來持久化數據,我們就需要添加一個可用的 pv 供 pvc 綁定使用,grafana-volume.yaml內容如下:
apiVersion: v1 kind: PersistentVolume metadata: name: grafana spec: capacity: storage: 10Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle nfs: server: 172.16.200.10 path: /mnt/lv/k8s --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: grafana namespace: monitoring spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi
然后我們直接創建上面的PV和PVC、更新 grafana-deployment.yaml 文件即可:
# kubectl apply -f grafana-volume.yaml
# kubectl apply -f grafana-deployment.yaml
創建完成以后我們查看Pod狀態,我們發現Pod狀態一直是 CrashLoopBackOff 沒有正常啟動,我們再看一下這個 Pod 的日志,錯誤信息如下:
mkdir: cannot create directory '/var/lib/grafana/plugins': Permission denied
這個錯誤是 Grafana 5.1版本以后才會出現的。錯誤的原因很明顯,就是 /var/lib/grafana 目錄的權限不夠。在 `` 中有這樣一個屬性:
securityContext: runAsNonRoot: true runAsUser: 65534
我們查看一下65534是哪個用戶:
cat /etc/passwd | grep 65534
所以,我們只需要把 /mnt/lv/k8s 目錄的用戶改為 nfsnobody 就可以了。當然把屬性改為 777 也沒問題:
chown nfsnobody /mnt/lv/k8s
把剛才出錯的那個 Pod 刪除,新的 Grafana Pod 就成功啟動了。然后就可以添加 Dashboard 了,現在Pod 重建也不會丟失數據了。
7、Kube-Prometheus服務發現
前面我們在 Kube-Prometheus 下面自定義一個監控項,以及自定義報警規則的使用。那么我們還能夠直接使用前面課程中的自動發現功能嗎?如果在我們的 Kubernetes 集群中有了很多的 Service/Pod,那么我們都需要一個一個的去建立一個對應的 ServiceMonitor 對象來進行監控嗎?這樣豈不是又變得麻煩起來了?
為解決上面的問題,Kube-Prometheus 為我們提供了一個額外的抓取配置的來解決這個問題,我們可以通過添加額外的配置來進行服務發現進行自動監控。和前面自定義的方式一樣,我們可以在 Kube-Prometheus 當中去自動發現並監控具有prometheus.io/scrape=true 這個 annotations 的 Service,之前我們定義的 Prometheus 的配置如下:
- job_name: 'kubernetes-endpoints' kubernetes_sd_configs: - role: endpoints relabel_configs: - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] action: keep regex: true - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] action: replace target_label: __scheme__ regex: (https?) - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] action: replace target_label: __metrics_path__ regex: (.+) - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] action: replace target_label: __address__ regex: ([^:]+)(?::\d+)?;(\d+) replacement: $1:$2 - action: labelmap regex: __meta_kubernetes_service_label_(.+) - source_labels: [__meta_kubernetes_namespace] action: replace target_label: kubernetes_namespace - source_labels: [__meta_kubernetes_service_name] action: replace target_label: kubernetes_name - source_labels: [__meta_kubernetes_pod_name] action: replace target_label: kubernetes_pod_name
要想自動發現集群中的 Service,就需要我們在 Service 的 annotation 區域添加 prometheus.io/scrape=true 的聲明,將上面文件直接保存為 prometheus-additional.yaml,然后通過這個文件創建一個對應的 Secret 對象:
kubectl create secret generic additional-configs --from-file=prometheus-additional.yaml -n monitoring
然后我們需要在聲明 prometheus 的資源對象文件中通過 additionalScrapeConfigs 屬性添加上這個額外的配置:(prometheus-prometheus.yaml)
apiVersion: monitoring.coreos.com/v1 kind: Prometheus metadata: labels: prometheus: k8s name: k8s namespace: monitoring spec: retention: 365d storage: volumeClaimTemplate: spec: storageClassName: prometheus-data-db resources: requests: storage: 100Gi alerting: alertmanagers: - name: alertmanager-main namespace: monitoring port: web baseImage: quay.io/prometheus/prometheus nodeSelector: kubernetes.io/os: linux podMonitorNamespaceSelector: {} podMonitorSelector: {} replicas: 2 secrets: - etcd-ssl resources: requests: memory: 400Mi ruleSelector: matchLabels: prometheus: k8s role: alert-rules securityContext: fsGroup: 2000 runAsNonRoot: true runAsUser: 1000 serviceAccountName: prometheus-k8s serviceMonitorNamespaceSelector: {} serviceMonitorSelector: {} version: v2.11.0 # 添加額外配置內容 additionalScrapeConfigs: name: additional-configs key: prometheus-additional.yam
添加完成后,直接更新 prometheus 這個 CRD 資源對象即可:
kubectl apply -f prometheus-prometheus.yaml
隔一小會兒,可以前往 Prometheus 的 Dashboard 中查看配置已經生效了:
但是我們切換到 targets 頁面下面卻並沒有發現對應的監控任務,查看 Prometheus 的 Pod 日志:
kubectl logs -f prometheus-k8s-0 prometheus -n monitoring | grep cluster
可以看到有很多錯誤日志出現,都是 xxx is forbidden,這說明是 RBAC 權限的問題,通過 prometheus 資源對象的配置可以知道 Prometheus 綁定了一個名為 prometheus-k8s 的 ServiceAccount 對象,而這個對象綁定的是一個名為 prometheus-k8s 的 ClusterRole:(prometheus-clusterRole.yaml)
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: prometheus-k8s rules: - apiGroups: - "" resources: - nodes/metrics verbs: - get - nonResourceURLs: - /metrics verbs: - get
上面的權限規則中我們可以看到明顯沒有對 Service 或者 Pod 的 list 權限,所以報錯了,要解決這個問題,我們只需要添加上需要的權限即可:
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: prometheus-k8s rules: - apiGroups: - "" resources: - nodes - services - endpoints - pods - nodes/proxy verbs: - get - list - watch - apiGroups: - "" resources: - configmaps - nodes/metrics verbs: - get - nonResourceURLs: - /metrics verbs: - get
更新上面的 ClusterRole 這個資源對象,然后重建 Prometheus 的所有 Pod,正常就可以看到 targets 頁面下面有 kubernetes-endpoints 這個監控任務了:
轉載:快速部署Kubernetes監控系統Kube-Prometheus | 鄒坤個人博客