Prometheus監控實踐:Kubernetes叢集監控_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
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的告警的。