【前置文章】
- 【Monitoring】Prometheus工作原理以及Prometheus架构介绍
- 【Monitoring】使用Helm和Prometheus Operator在Kubernetes中安装Prometheus
【参考】
- 文章:Monitoring Made Simple: Empowering Spring Boot Applications with Prometheus and Grafana -->
这篇使用的是Docker安装Prometheus
- 视频:Prometheus Monitoring - Steps to monitor third-party apps using Prometheus Exporter | Part 2 -->
这篇介绍了MongoDB在Prometheus中的集成,也有讲到一些原理
- 视频:Monitoring Kubernetes and Spring Boot service using Prometheus and Grafana - Part 2 -->
这篇是Spring Boot在Prometheus中的集成
使用Grafana来查看Spring Boot项目的Metrics,主要流程:
- Spring Boot集成
spring-boot-starter-actuator
模块和micrometer-registry-prometheus
模块暴露/actuator/prometheus
端点 - Prometheus每隔一定时间通过
/actuator/prometheus
端点抓取数据,存入时间序列数据库。 - 访问Grafana Dashboard:http:localhost:3000,其背后是Grafana通过PromQL查询Prometheus时间序列数据库。
本文主要集中在如何Spring Boot如何暴露/actuator/prometheus
端点,以及在Prometheus中设置Target(通过创建ServiceMonitor)。至于Prometheus和Grafana在Kubernetes中的安装,请查看前置文章。本篇基于Spring Boot 2.7.0。
1. Spring Boot暴露/actuator/prometheus
端点
1.1 集成Spring Actuator模块
Spring Boot官网,关于Actuator,参考:docs.spring.io/spring-boot...
Spring Actuator模块提供了Spring Boot的生产就绪功能(Production-ready Features)。
加入依赖
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
端口号
如果没有额外声明,和项目用同一个端口号。也可以额外定义management.server.port=5050
启动Spring Boot项目后,访问:http://localhost:5050/actuator
endpoints
Spring Actuator提供了很多endpoints供查询各种信息。endpoints种类比较多,具体参考:docs.spring.io/spring-boot...
默认情况下开放的endpoints比较少,如访问以下两个端点会报404错误:
默认情况下,只提供了health相关的查询:
可以通过配置上述property进行添加,也可以用通配 *
表示开放所有endpoints。
2. 与Prometheus结合
为什么需要引入Prometheus相关的依赖?虽然Spring Boot的actuator提供了一些监控数据,但如果想要在Prometheus UI上显示或是使用Grafana图形化显示,就需要特定的格式,而项目micrometer-registry-prometheus
正是帮我们做了这件事。
首先引入依赖:
xml
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
看Spring Boot Actuator官网,支持endpoints=prometheus:
第#1.1章说了默认情况下只开放了health endponts,所以需要主动加上prometheus
:
ini
management.endpoints.web.exposure.include=health,prometheus
测试项目没有配management.server.port
,所以这里端口号还是8080。
访问:http://localhost:8080/actuator/prometheus,可以看到很多运行相关的信息,以下截图是jvm相关的,因为信息很多,所以一般需要通过UI进行展示:
2. 编写Dockerfile文件
这块可以参考我之前的文章:# 【k8s学习】布署Spring Boot项目到minikube上,写的很详细。
sql
FROM openjdk:17-alpine
COPY target/spring-acturator-test.jar spring-acturator-test.jar
expose 8080
ENTRYPOINT ["java","-jar","spring-acturator-test.jar"]
3. Prometheus怎么发现新的Target?
本文假设Prometheus和Grafana已经在Kubernetes中安装好了,如没有安装,请参考文章开头的前置文章。
访问Prometheus Dashboard:http://localhost:9090
Prometheus默认集成了一些Targets,如:
通地命令查看servicemonitor
,是Kubernetes定制的Kubernetes component,正是以下这些servicemonitor产生了上述Prometheus的Targets:
$ kubectl get servicemonitor -n monitoring
NAME AGE
prometheus-grafana 66m
prometheus-kube-prometheus-alertmanager 66m
prometheus-kube-prometheus-apiserver 66m
prometheus-kube-prometheus-coredns 66m
prometheus-kube-prometheus-kube-controller-manager 66m
prometheus-kube-prometheus-kube-etcd 66m
prometheus-kube-prometheus-kube-proxy 66m
prometheus-kube-prometheus-kube-scheduler 66m
prometheus-kube-prometheus-kubelet 66m
prometheus-kube-prometheus-operator 66m
prometheus-kube-prometheus-prometheus 66m
prometheus-kube-state-metrics 66m
prometheus-prometheus-node-exporter 66m
我们查看其中一个servicemonitor,以yaml形式展示:
$ kubectl get servicemonitor prometheus-grafana -n monitoring -o yaml
可以看到资源类型是ServiceMonitor
,endpoints的端点是metrics
,其中一个label是app.kubernetes.io/instance: prometheus
,这里的label为什么是prometheus呢?其实是我们chart的name,我们在install prometheus的时候用的命令是helm install prometheus prometheus-community/kube-prometheus-stack -n monitoring
,那么这里的release-name
就是prometheus,如果我们换成abc,这里的release-name也会是abc,只要和CRD中的matchLabels对应起来就可以了(下文有介绍CRD):
yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
annotations:
meta.helm.sh/release-name: prometheus
meta.helm.sh/release-namespace: monitoring
creationTimestamp: "2024-04-14T06:06:21Z"
generation: 1
labels:
app.kubernetes.io/instance: prometheus
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: grafana
app.kubernetes.io/version: 10.4.0
helm.sh/chart: grafana-7.3.7
name: prometheus-grafana
namespace: monitoring
resourceVersion: "5103"
uid: 1f009abd-37ac-4ebe-ad7b-a582b419c5ba
spec:
endpoints:
- honorLabels: true
path: /metrics
port: http-web
scheme: http
scrapeTimeout: 30s
jobLabel: prometheus
namespaceSelector:
matchNames:
- monitoring
selector:
matchLabels:
app.kubernetes.io/instance: prometheus
app.kubernetes.io/name: grafana
要想看具体内部是怎么关联的,我们需要再查看CRD。上述ServiceMonitor
的apiVersion为:apiVersion: monitoring.coreos.com/v1
,我们查看下CRD,首先列出所有CRDs:
$ kubectl get crd -n monitoring
NAME CREATED AT
prometheuses.monitoring.coreos.com 2024-04-14T05:32:50Z <其它略>
具体查看CRD=prometheuses.monitoring.coreos.com,以yaml格式展示:
$ kubectl get prometheuses.monitoring.coreos.com -n monitoring -o yaml
资源定义很长,其中一段定义,所以我们创建的ServiceMonitor
,需要加上这个Label,否则就不会被关联上并发现,如果我们chart name为其它名字,如abc,那么在安装生成CRD的时候这里的release就会是abc,而不是prometheus:
yaml
serviceMonitorSelector:
matchLabels:
release: prometheus
4. 编写Spring Boot的ServiceMonitor
本文参考的是上述视频2中的Git Sample: github.com/kodedge-swa...
进入Spring Boot项目目录,创建helm chart:
$ helm create ytchart
Creating ytchart
这样helm chart就创建好了,我们只需要修改其中的几个配置即可:
a. 首先要修改的是value.yaml
中的image:
yaml
image:
repository: spring-monitoring-kube
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: "latest"
还需要修改value.yaml
的service定义:
yaml
service:
type: NodePort
port: 8080
serviceLabel: spring-svc
jobName: spring-microservice-job
b. 其次修改service.yaml
:
yaml
apiVersion: v1
kind: Service
metadata:
name: {{ include "ytchart.fullname" . }}
labels:
app: {{ .Values.service.serviceLabel }}
job: {{ .Values.service.jobName }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "ytchart.selectorLabels" . | nindent 4 }}
c. 新建service-monitor.yaml
,这边的selector.matchLabels需要和service中的labels对应起来,而这里的labels需要和CRD中的matchLabels对应起来(上一章节有介绍过)。
interval=5s表示每隔5秒来抓取一次数据。
yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: spring-boot-microservice-monitor
labels:
release: prometheus
spec:
jobLabel: job
endpoints:
- interval: 5s
path: /actuator/prometheus
port: http
namespaceSelector:
any: true
selector:
matchLabels:
app: {{ .Values.service.serviceLabel }}
job: {{ .Values.service.jobName }}
d. 还需要把deployment.yaml
中的livenessProbe
和readinessProbe
先注释掉。
5. 开始布署
build docker image:
docker build -t spring-acturator-test .
以下这个命令是可以使minikube读取本地的docker images,这样就可以不需要让我们的docker image进行push到远程的操作了:
eval $(minikube docker-env)
安装chart:
helm install mychart ytchart
查看安装结果:
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
pod/mychart-ytchart-5c686c8db8-xzm9p 1/1 Running 0 15s
查看service:
kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 443/TCP 3h42m
mychart-ytchart NodePort 10.110.23.68 8080:32634/TCP 96m
对service进行转发以便本地可以访问:
kubectl port-forward service/mychart-ytchart 8080:8080
访问:http://localhost:8080/actuator/prometheus,返回metrics数据。
此时访问Prometheus Dashboard的Service Discovery
:http://localhost:9090/service-discovery,可以看到Spring Boot的Metrics了:
总结起来就是service-monitor.yaml起作用了。
6. 在Grafana中增加Spring Boot Dashboard
Prometheus并不是必须依赖Grafana,至第5章,Prometheus已经可以定期抓取运行在Kubernetes中的Spring Boot项目的Metrics了,我们可以通过Prometheus的Dashboard进行PromQL查询(如下图:在1中输入PromQL,点击2运行,3是运行结果):
但Grafana的展示更为强大。访问grafana.com/grafana/das...,查询我们想要的Grafana dashboard,输入Spring Boot查询,添加第2个结果:
点击进去,复制Dashboard ID:
回到Grafana Dashboard页面,右侧New
--> Import
:
输入上述复制的Dashboard ID,点击Load:
Prometheus下拉框选择Prometheus,点击Import:
这样就可以展示我们Spring Boot项目Metrics了:
7. 验证抓取间隔
我们上面service-monitor.yaml
配置的internal=5s,可以验证下。
在Spring Boot项目application.properties
中打开DispatcherServlet类的DEBUG:
ini
logging.level.org.springframework.web.servlet.DispatcherServlet=DEBUG
重新docker build。
helm也需要先uninstall,再install:
helm uninstall mychart
helm install mychart ytchart
查看pod日志:
kubectl logs -f mychart-ytchart-5c686c8db8-x68sv
日志结果,可以看出每隔5秒/actuator/prometheus
被调用了一次:
2024-04-14 13:02:21.204 DEBUG 1 --- [io-8080-exec-10] o.s.web.servlet.DispatcherServlet : GET "/actuator/prometheus", parameters={}
2024-04-14 13:02:21.211 DEBUG 1 --- [io-8080-exec-10] o.s.web.servlet.DispatcherServlet : Completed 200 OK
2024-04-14 13:02:26.204 DEBUG 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : GET "/actuator/prometheus", parameters={}
2024-04-14 13:02:26.213 DEBUG 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed 200 OK
2024-04-14 13:02:31.203 DEBUG 1 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : GET "/actuator/prometheus", parameters={}
2024-04-14 13:02:31.211 DEBUG 1 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Completed 200 OK