天天看點

使用 Prometheus + Grafana 監控 k8s 上的 Spring Boot 應用

背景

本文主要介紹如何使用 Prometheus 和 Grafana 可視化監控運作在 k8s 上的 Spring Boot 應用,監控名額包括 CPU、記憶體、線程資訊、日志資訊、HTTP 請求、JVM 等。

技術方案

技術方案如下圖所示:

使用 Prometheus + Grafana 監控 k8s 上的 Spring Boot 應用

首先我們需要在 Spring Boot 應用中使用 

Spring Boot Actuator

監控應用、暴露名額,并使用

Micrometer Prometheus

将 Actuator 監控名額轉換為 Prometheus 格式。

Micrometer

為 Java 平台上的性能資料收集提供了一個通用的 API,類似于 SLF4J ,隻不過它關注的不是Logging(日志),而是application metrics(應用名額)。 簡而言之,它就是應用監控界的SLF4J。

然後在 k8s 叢集中,我們需要通過 Service 對外提供 Spring Boot 應用的名額接口。

Prometheus

是一個開源系統監控和警報工具包,可以采集監控名額,并存儲為時間序列資料,Prometheus 還提供了靈活的查詢語言 PromQL 來查詢資料。Prometheus 通過拉模型采集名額,是以我們需要在 Prometheus 叢集中配置服務發現(ServiceMonitor)來定期從應用中抓取名額。

Grafana 是一個開源的可視化分析平台,可以用它建立監控儀表盤、配置告警等。

整體個配置流程如下:

使用 Prometheus + Grafana 監控 k8s 上的 Spring Boot 應用

部署應用

應用配置

在 

pom.xml

中添加如下配置:

<!-- 開啟 Spring Boot Actuator -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 将 Actuator 名額轉換為 Prometheus 格式 -->
<dependency>
  <groupId>io.micrometer</groupId>
  <artifactId>micrometer-registry-prometheus</artifactId>
  <version>${micrometer.version}</version>
</dependency>      

然後修改 

application.yaml

中添加 Spring Boot Actuator 相關配置:

spring:
  application:
    name: spring-boot-demo
management:
  endpoints:
    web:
      exposure:
        include: "*"
    health:
      show-details: always
  metrics:
    export:
      prometheus:
        enable: true
    tags:
      application: spring-boot-demo      

至此,應用配置就完成了,可以通過 

/actuator/prometheus

接口檢視配置是否正确:

$ curl 'http://localhost:8080/actuator/prometheus' -i -X GET      

傳回結果如下所示:

HTTP/1.1 200 OK
Content-Type: text/plain;version=0.0.4;charset=utf-8
Content-Length: 2375
# HELP jvm_buffer_memory_used_bytes An estimate of the memory that the Java virtual machine is using for this buffer pool
# TYPE jvm_buffer_memory_used_bytes gauge
jvm_buffer_memory_used_bytes{id="direct",} 489719.0
jvm_buffer_memory_used_bytes{id="mapped",} 0.0
# HELP jvm_memory_committed_bytes The amount of memory in bytes that is committed for the Java virtual machine to use
# TYPE jvm_memory_committed_bytes gauge
jvm_memory_committed_bytes{area="heap",id="PS Survivor Space",} 5.1380224E7
jvm_memory_committed_bytes{area="heap",id="PS Old Gen",} 4.86539264E8
jvm_memory_committed_bytes{area="heap",id="PS Eden Space",} 2.11812352E8
jvm_memory_committed_bytes{area="nonheap",id="Metaspace",} 1.62439168E8
jvm_memory_committed_bytes{area="nonheap",id="Code Cache",} 5.4329344E7
jvm_memory_committed_bytes{area="nonheap",id="Compressed Class Space",} 2.4551424E7
# HELP jvm_buffer_total_capacity_bytes An estimate of the total capacity of the buffers in this pool
# TYPE jvm_buffer_total_capacity_bytes gauge
jvm_buffer_total_capacity_bytes{id="direct",} 489718.0
jvm_buffer_total_capacity_bytes{id="mapped",} 0.0
# HELP jvm_memory_max_bytes The maximum amount of memory in bytes that can be used for memory management
# TYPE jvm_memory_max_bytes gauge
jvm_memory_max_bytes{area="heap",id="PS Survivor Space",} 5.1380224E7
jvm_memory_max_bytes{area="heap",id="PS Old Gen",} 7.16177408E8
jvm_memory_max_bytes{area="heap",id="PS Eden Space",} 2.31735296E8
jvm_memory_max_bytes{area="nonheap",id="Metaspace",} -1.0
jvm_memory_max_bytes{area="nonheap",id="Code Cache",} 2.5165824E8
jvm_memory_max_bytes{area="nonheap",id="Compressed Class Space",} 1.073741824E9
# HELP jvm_buffer_count_buffers An estimate of the number of buffers in the pool
# TYPE jvm_buffer_count_buffers gauge
jvm_buffer_count_buffers{id="direct",} 17.0
jvm_buffer_count_buffers{id="mapped",} 0.0
# HELP jvm_memory_used_bytes The amount of used memory
# TYPE jvm_memory_used_bytes gauge
jvm_memory_used_bytes{area="heap",id="PS Survivor Space",} 5.1139432E7
jvm_memory_used_bytes{area="heap",id="PS Old Gen",} 9.7572216E7
jvm_memory_used_bytes{area="heap",id="PS Eden Space",} 1.47234248E8
jvm_memory_used_bytes{area="nonheap",id="Metaspace",} 1.46403048E8
jvm_memory_used_bytes{area="nonheap",id="Code Cache",} 5.3970112E7
jvm_memory_used_bytes{area="nonheap",id="Compressed Class Space",} 2.1374208E7      

配置 Service

因為應用是部署在 k8s 上的,由多個 Pod 組成,是以還需要為 Pod 添加 Service,對外提供 HTTP 服務,這樣 Prometheus 才可以抓取監控名額。

在 k8s 中添加類似下面的 Service:

apiVersion: v1
kind: Service
metadata:
  labels:
    app: spring-boot-demo-exporter
  name: spring-boot-demo-exporter
  namespace: default
spec:
  ports:
    - name: spring-boot-demo-exporter
      port: 8080
      protocol: TCP
      targetPort: 8080
  selector:
    app: spring-boot-demo
  type: NodePort      

需要注意 

spec.selector

需要與 Pod 的标簽對應。例如使用 Deployment 部署應用,則需要與 Deployment 的

spec.template.metadata.labels

對應,這樣 Service 才能知道對應的 Pod。

配置服務發現

如果使用的是自己部署的 Prometheus 服務,則可以在 

prometheus.yml

中添加上 Service 對應的任務,例如:

scrape_configs:
  # ...
  -  job_name: 'spring-boot-demo' # Prometheus 任務名稱,自定義
     metrics_path: '/actuator/prometheus' # 名額擷取路徑
     scrape_interval: 5s # 抓取名額的間隔時間
     static_configs:
       - targets: ['spring-boot-demo-exporter:8080'] # 名額通路入口,即 k8s 叢集的 Service      

如果使用的是雲廠商提供的 Prometheus 服務,則需要安裝雲廠商的規則添加服務發現。如 

阿裡雲 Prometheus 監控

的 ServiceMonitor 配置如下:

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: spring-boot-exporter
  namespace: default
spec:
  endpoints:
  - interval: 30s
    # Prometheus Exporter 對應的 Path 的值
    path: /actuator/prometheus
    # service.yaml 中 Prometheus Exporter 對應的 Port 的 Name 字段的值
    port: spring-boot-exporter
  namespaceSelector:
    any: true
  selector:
    matchLabels:
      # service.yaml 的 Label 字段的值以定位目标 service.yaml
      app: spring-boot-demo-exporter      

配置大盤

Grafana

提供了豐富的大盤模闆,可以在其官網搜尋合适的大盤導入到自己的 Grafana 監控中。

使用 Prometheus + Grafana 監控 k8s 上的 Spring Boot 應用

我使用的是這兩個大盤:

最終效果預覽如下:

使用 Prometheus + Grafana 監控 k8s 上的 Spring Boot 應用

Spring Boot 監控

使用 Prometheus + Grafana 監控 k8s 上的 Spring Boot 應用

JVM 監控

總結

至此,基于 Prometheus + Grafana 的 Spring Boot 應用監控系統就建立完成了。接下來還可以使用 Grafana 實作告警,這類就不贅述了。