Prometheus監控實踐:Kubernetes集羣監控

本文將總結一下我們目前使用Prometheus對Kubernetes集羣監控的實踐。 我們選擇Prometheus作爲監控系統主要在以下各層面實現監控:

  • 基礎設施層:監控各個主機服務器資源(包括Kubernetes的Node和非Kubernetes的Node),如CPU,內存,網絡吞吐和帶寬佔用,磁盤I/O和磁盤使用等指標。
  • 中間件層:監控獨立部署於Kubernetes集羣之外的中間件,例如:MySQL、Redis、RabbitMQ、ElasticSearch、Nginx等。
  • Kubernetes集羣:監控Kubernetes集羣本身的關鍵指標
  • Kubernetes集羣上部署的應用:監控部署在Kubernetes集羣上的應用

1.基礎設施層和中間件層的監控

其中基礎設施層監控指標的拉取肯定是來在Prometheus的node_exporter,因爲我們要監控的服務器節點既包含Kubernetes節點又包含其他部署獨立中間件的節點, 所以我們並沒有將node_exporter以daemonset的形式部署到k8s上,而是使用ansible將node_exporter以二進制的形式部署到所有要監控的服務器上。 而負責從node_exporter拉取指標的Prometheus也是用ansible獨立部署在Kubernetes集羣外部的。Prometheus的配置文件prometheus.yml使用ansible的j2模板生成。

中間層的監控和基礎設施層監控類似,使用ansible在各個中間件所在的主機上部署各個中間件的exporter,仍然使用上面在Kubernetes集羣外部的這個Prometheus從這些exporter拉取指標,Prometheus的配置文件prometheus.yml使用ansible的j2模板生成。

2.Kubernetes集羣的監控

要實現對Kubernetes集羣的監控,因爲Kubernetes的rbac機制以及證書認證,當然是把Prometheus部署在Kubernetes集羣上最方便。可是我們目前的監控系統是以k8s集羣外部的Prometheus爲主的,grafana和告警都是使用這個外部的Prometheus,如果還需要在Kubernetes集羣內部部署一個Prometheus的話一定要把它桶外部的Prometheus聯合起來,好在Prometheus支持Federation。

2.1 Prometheus的Federation簡介

Federation允許一個Prometheus從另一個Prometheus中拉取某些指定的時序數據。Federation是Prometheus提供的擴展機制,允許Prometheus從一個節點擴展到多個節點,實際使用中一般會擴展成樹狀的層級結構。下面是Prometheus官方文檔中對federation的配置示例:

- job_name: 'federate'
 scrape_interval: 15s

 honor_labels: true
 metrics_path: '/federate' params: 'match[]': - '{job="prometheus"}' - '{__name__=~"job:.*"}'

 static_configs: - targets: - 'source-prometheus-1:9090' - 'source-prometheus-2:9090' - 'source-prometheus-3:9090'

這段配置所屬的Prometheus將從source-prometheus-1 ~ 3這3個Prometheus的/federate端點拉取監控數據。 match[]參數指定了只拉取帶有job=”prometheus標籤的指標,或者名稱以job開頭的指標。

2.2 在Kubernetes上部署Prometheus

前面已經介紹了將使用Prometheus federation的形式,k8s集羣外部的Prometheus從k8s集羣中Prometheus拉取監控數據,外部的Prometheus纔是監控數據的存儲。 k8s集羣中部署Prometheus的數據存儲層可以簡單的使用emptyDir,數據只保留24小時(或更短時間)即可,部署在k8s集羣上的這個Prometheus實例即使發生故障也可以放心的讓它在集羣節點中漂移。

在k8s上部署Prometheus十分簡單,只需要下面4個文件:prometheus.rbac.yml, prometheus.config.yml, prometheus.deploy.yml, prometheus.svc.yml。 下面給的例子中將Prometheus部署到kube-system命名空間。

prometheus.rbac.yml定義了Prometheus容器訪問k8s apiserver所需的ServiceAccount和ClusterRole及ClusterRoleBinding,參考Prometheus源碼中庫中的例子:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
 name: prometheus
rules: - apiGroups: [""]
 resources: - nodes
 - nodes/proxy
 - services
 - endpoints
 - pods
 verbs: ["get", "list", "watch"] - apiGroups: - extensions
 resources: - ingresses
 verbs: ["get", "list", "watch"] - nonResourceURLs: ["/metrics"]
 verbs: ["get"] ---
apiVersion: v1
kind: ServiceAccount
metadata:
 name: prometheus
 namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
 name: prometheus
roleRef:
 apiGroup: rbac.authorization.k8s.io
 kind: ClusterRole
 name: prometheus
subjects: - kind: ServiceAccount
 name: prometheus
 namespace: kube-system

prometheus.config.yml configmap中的prometheus的配置文件,參考Prometheus源碼中庫中的例子:

apiVersion: v1
kind: ConfigMap
metadata:
 name: prometheus-config
 namespace: kube-system
data:
 prometheus.yml: | global:
 scrape_interval: 15s
 evaluation_interval: 15s
 scrape_configs: - job_name: 'kubernetes-apiservers'
 kubernetes_sd_configs: - role: endpoints
 scheme: https
 tls_config:
 ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
 bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
 relabel_configs: - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
 action: keep
 regex: default;kubernetes;https
 
 - job_name: 'kubernetes-nodes'
 kubernetes_sd_configs: - role: node
 scheme: https
 tls_config:
 ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
 bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
 relabel_configs: - action: labelmap
 regex: __meta_kubernetes_node_label_(.+) - target_label: __address__
 replacement: kubernetes.default.svc:443 - source_labels: [__meta_kubernetes_node_name]
 regex: (.+)
 target_label: __metrics_path__
 replacement: /api/v1/nodes/${1}/proxy/metrics

 - job_name: 'kubernetes-cadvisor'
 kubernetes_sd_configs: - role: node
 scheme: https
 tls_config:
 ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
 bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
 relabel_configs: - action: labelmap
 regex: __meta_kubernetes_node_label_(.+) - target_label: __address__
 replacement: kubernetes.default.svc:443 - source_labels: [__meta_kubernetes_node_name]
 regex: (.+)
 target_label: __metrics_path__
 replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor

 - job_name: 'kubernetes-service-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

 - job_name: 'kubernetes-services'
 kubernetes_sd_configs: - role: service
 metrics_path: /probe
 params:
 module: [http_2xx]
 relabel_configs:
 - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_probe]
 action: keep
 regex: true
 - source_labels: [__address__]
 target_label: __param_target
 - target_label: __address__
 replacement: blackbox-exporter.example.com:9115
 - source_labels: [__param_target]
 target_label: instance
 - action: labelmap
 regex: __meta_kubernetes_service_label_(.+)
 - source_labels: [__meta_kubernetes_namespace]
 target_label: kubernetes_namespace
 - source_labels: [__meta_kubernetes_service_name]
 target_label: kubernetes_name

 - job_name: 'kubernetes-ingresses'
 kubernetes_sd_configs:
 - role: ingress
 relabel_configs:
 - source_labels: [__meta_kubernetes_ingress_annotation_prometheus_io_probe]
 action: keep
 regex: true
 - source_labels: [__meta_kubernetes_ingress_scheme,__address__,__meta_kubernetes_ingress_path]
 regex: (.+);(.+);(.+)
 replacement: ${1}://${2}${3}
 target_label: __param_target
 - target_label: __address__
 replacement: blackbox-exporter.example.com:9115 - source_labels: [__param_target]
 target_label: instance
 - action: labelmap
 regex: __meta_kubernetes_ingress_label_(.+) - source_labels: [__meta_kubernetes_namespace]
 target_label: kubernetes_namespace
 - source_labels: [__meta_kubernetes_ingress_name]
 target_label: kubernetes_name

 - job_name: 'kubernetes-pods'
 kubernetes_sd_configs: - role: pod
 relabel_configs: - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
 action: keep
 regex: true - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
 action: replace
 target_label: __metrics_path__
 regex: (.+) - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
 action: replace
 regex: ([^:]+)(?::\d+)?;(\d+)
 replacement: $1:$2
 target_label: __address__
 - action: labelmap
 regex: __meta_kubernetes_pod_label_(.+) - source_labels: [__meta_kubernetes_namespace]
 action: replace
 target_label: kubernetes_namespace
 - source_labels: [__meta_kubernetes_pod_name]
 action: replace
 target_label: kubernetes_pod_name

prometheus.deploy.yml定義Prometheus的部署:

---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
 labels:
 name: prometheus-deployment
 name: prometheus
 namespace: kube-system
spec:
 replicas: 1
 selector:
 matchLabels:
 app: prometheus
 template:
 metadata:
 labels:
 app: prometheus
 spec:
 containers: - image: harbor.frognew.com/prom/prometheus:2.0.0
 name: prometheus
 command: - "/bin/prometheus"
 args: - "--config.file=/etc/prometheus/prometheus.yml" - "--storage.tsdb.path=/prometheus" - "--storage.tsdb.retention=24h"
 ports: - containerPort: 9090
 protocol: TCP
 volumeMounts: - mountPath: "/prometheus"
 name: data
 - mountPath: "/etc/prometheus"
 name: config-volume
 resources:
 requests:
 cpu: 100m
 memory: 100Mi
 limits:
 cpu: 500m
 memory: 2500Mi
 serviceAccountName: prometheus
 imagePullSecrets: - name: regsecret
 volumes: - name: data
 emptyDir: {} - name: config-volume
 configMap:
 name: prometheus-config 

prometheus.svc.yml定義Prometheus的Servic,需要將Prometheus以NodePort, LoadBalancer或使用Ingress暴露到集羣外部,這樣外部的Prometheus才能訪問它:

---
kind: Service
apiVersion: v1
metadata:
 labels:
 app: prometheus
 name: prometheus
 namespace: kube-system
spec:
 type: NodePort
 ports: - port: 9090
 targetPort: 9090
 nodePort: 30003
 selector:
 app: prometheus

2.3 配置Prometheus Federation

完成Kubernetes集羣上的Prometheus的部署之後,下面將配置集羣外部的Prometheus使其從集羣內部的Prometheus拉取數據。 實際上只需以靜態配置的形式添加一個job就可以:

- job_name: 'federate'
 scrape_interval: 15s
 honor_labels: true
 metrics_path: '/federate' params: 'match[]': - '{job=~"kubernetes-.*"}'
 static_configs: - targets: - '<nodeip>:30003'

注意上面的配置是外部Prometheus拉取k8s集羣上面所有名稱以kubernetes-的job的監控數據。

2.4 Kubernetes集羣Grafana Dashboard

監控Dashboard使用Kubernetes cluster monitoring (via Prometheus)這個即可。 另外關於Pod和Deployment還有這兩個Dashboard:Kubernetes Pod MetricsKubernetes Deployment metrics

2.5 Kubernetes集羣告警規則

可以對apiserver和kubelet兩個關鍵組件的存活狀態進行監控,規則如下:

up{job=~"kubernetes-apiservers|kubernetes-nodes|kubernetes-cadvisor"} == 0

更多的告警規則可以通過查看上面2.4中的grafana dashboard中監控的關鍵指標,選擇和合適的指標進行設置,實際上一套好的監控系統的監控指標和告警規則並不是越多越好。

3.Kubernetes集羣上部署應用的監控

Kubernetes集羣上部署應用的監控需要從兩個方面:

  • Kubernetes集羣上Pod, DaemonSet, Deployment, Job, CronJob等各種資源對象的狀態需要監控,這也反映了使用這些資源部署的應用的狀態。但通過查看前面Prometheus從k8s集羣拉取的指標(這些指標主要來自apiserver和kubelet中集成的cAdvisor),並沒有具體的各種資源對象的狀態指標。對於Prometheus來說,當然是需要引入新的exporter來暴露這些指標,Kubernetes提供了一個kube-state-metrics正式我們需要。
  • Kubernetes集羣上應用內部的監控,這個與具體應用的開發語言,開發框架和具體技術緊密相關,比如Java應用的JVM監控,Go應用的GC監控等等,這個需要應用自身作爲Exporter暴露這些指標或在應用的Pod中起一個exporter的sidecar容器。

這裏將主要介紹kube-state-metrics,而對於應用內部的監控實踐後邊有時間再單獨總結。kube-state-metrics使用kubernetes的go語言客戶端client-go可以從Kubernetes集羣中獲取各種資源對象的指標。

3.1 在Kubernetes上部署kube-state-metrics

kube-state-metrics已經給出了在Kubernetes部署的manifest定義文件,具體的文件定義都在這裏

將kube-state-metrics部署到Kubernetes上之後,就會發現Kubernetes集羣中的Prometheus會在kubernetes-service-endpoints這個job下自動服務發現kube-state-metrics,並開始拉取metrics,當然集羣外部的Prometheus也能從集羣中的Prometheus拉取到這些數據了。這是因爲上2.2中prometheus.config.yml中Prometheus的配置文件job kubernetes-service-endpoints的配置。而部署kube-state-metrics的manifest定義文件kube-state-metrics-service.yaml對kube-state-metricsService的定義包含annotation prometheus.io/scrape: ‘true’,因此kube-state-metrics的endpoint可以被Prometheus自動服務發現。

關於kube-state-metrics暴露的所有監控指標可以參考kube-state-metrics的文檔kube-state-metrics Documentation

3.2 告警規則

目前我們根據從kube-state-metrics獲取的監控指標,制定了以下告警規則:

  • 存在執行失敗的Job: kube_job_status_failed{job=”kubernetes-service-endpoints”,k8s_app=”kube-state-metrics”}==1
  • 集羣節點狀態錯誤: kube_node_status_condition{condition=”Ready”,status!=”true”}==1
  • 集羣節點內存或磁盤資源短缺: kube_node_status_condition{condition=~”OutOfDisk|MemoryPressure|DiskPressure”,status!=”false”}==1
  • 集羣中存在失敗的PVC:kube_persistentvolumeclaim_status_phase{phase=”Failed”}==1
  • 集羣中存在啓動失敗的Pod:kube_pod_status_phase{phase=~”Failed|Unknown”}==1
  • 最近30分鐘內有Pod容器重啓: changes(kube_pod_container_status_restarts[30m])>0

其中關於Pod狀態的的告警尤爲重要,可以在Jenkins完成CI/CD自動發佈後,不用守在Kubernetes Dashboard旁邊確認這個Deployment關聯的Pod已經全部啓動,因爲如果出現問題是會收到Prometheus的告警的。

本文轉自kubernetes中文社區-Prometheus監控實踐:Kubernetes集羣監控

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章