简介
Spring Boot Admin是一个开源社区项目,用于管理和监控SpringBoot应用程序。 应用程序作为Spring Boot Admin Client向为Spring Boot Admin Server注册(通过HTTP)或使用SpringCloud注册中心(例如Eureka,Consul)发现。 UI是的AngularJs应用程序,展示Spring Boot Admin Client的Actuator端点上的一些监控。常见的功能或者监控如下:
- 显示健康状况
- 显示详细信息,例如
- JVM和内存指标
- micrometer.io指标
- 数据源指标
- 缓存指标
- 显示构建信息编号
- 关注并下载日志文件
- 查看jvm系统和环境属性
- 查看Spring Boot配置属性
- 支持Spring Cloud的postable / env-和/ refresh-endpoint
- 轻松的日志级管理
- 与JMX-beans交互
- 查看线程转储
- 查看http跟踪
- 查看auditevents
- 查看http-endpoints
- 查看计划任务
- 查看和删除活动会话(使用spring-session)
- 查看Flyway / Liquibase数据库迁移
- 下载heapdump
- 状态变更通知(通过电子邮件,Slack,Hipchat,......)
- 状态更改的事件日志(非持久性)
快速开始
1.创建Spring Boot Admin Server
Maven的pom文件引入以下的依赖,注意SpringBoot的版本号与SpringBootAdmin的大版本号要对应,例如本文的SpringBoot为2.1.9.RELEASE,SpringBootAdmin为2.1.5
<!-- SpringCloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- SpringBoot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.9.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Spring Boot Admin -->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>2.1.5</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>2.1.5</version>
</dependency>
在服务端工程monitor-admin引入以下依赖:
<!-- SpringBoot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- SpringBootAdmin -->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server-ui</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
<!-- SpringCloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!-- Jetty -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
starter-web中需要排除掉tomcat,改为引用jetty,否则会引发错误,或者tomcat降级
2020-05-09 09:02:57.348 ERROR 10432 --- [io-10210-exec-6] o.a.catalina.connector.CoyoteAdapter : Exception while processing an asynchronous request
java.lang.IllegalStateException: Calling [asyncError()] is not valid for a request with Async state [MUST_DISPATCH]
at org.apache.coyote.AsyncStateMachine.asyncError(AsyncStateMachine.java:440) ~[tomcat-embed-core-9.0.26.jar:9.0.26]
at org.apache.coyote.AbstractProcessor.action(AbstractProcessor.java:513) [tomcat-embed-core-9.0.26.jar:9.0.26]
at org.apache.coyote.Request.action(Request.java:430) ~[tomcat-embed-core-9.0.26.jar:9.0.26]
at org.apache.catalina.core.AsyncContextImpl.setErrorState(AsyncContextImpl.java:401) ~[tomcat-embed-core-9.0.26.jar:9.0.26]
at org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:239) ~[tomcat-embed-core-9.0.26.jar:9.0.26]
at org.apache.coyote.AbstractProcessor.dispatch(AbstractProcessor.java:242) [tomcat-embed-core-9.0.26.jar:9.0.26]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:53) [tomcat-embed-core-9.0.26.jar:9.0.26]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860) [tomcat-embed-core-9.0.26.jar:9.0.26]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1589) [tomcat-embed-core-9.0.26.jar:9.0.26]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.26.jar:9.0.26]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_162]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_162]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.26.jar:9.0.26]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_162]
然后在工程的启动类AdminServerApplication加上@EnableAdminServer注解,开启AdminServer的功能,代码如下:
import de.codecentric.boot.admin.server.config.EnableAdminServer;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
// 等同于@SpringBootApplication + @EnableDiscoveryClient + @EnableCircuitBreaker
@SpringCloudApplication
@EnableAdminServer
public class MonitorAdmin {
public static void main(String[] args) {
SpringApplication.run(MonitorAdmin.class, args);
}
//加入如下配置
@Bean({"threadPoolTaskExecutor", "webMvcAsyncTaskExecutor"})
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
return new ThreadPoolTaskExecutor();
}
}
在工程的配置文件bootstrap.yml中的配置:
# 项目设置
spring:
profiles:
active: local # 默认激活文件
application:
name: monitor-admin
boot:
admin:
client:
url: http://localhost:8769
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: ALWAYS
bootstrap-local.yml配置:
# 设置服务
server:
port: 10210
# 项目设置
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
sentinel:
transport:
dashboard: localhost:8080
# 使用默认日志slf4
logging:
level:
com.sunber: DEBUG # 可以按包显示不同的级别
file: F://###LOGS/Sunber/Monitor/Admin/out.log # 不指定目录则输出到当前项目下
2.创建Spring Boot Admin Client
在admin-client工程的pom文件引入admin-client的起步依赖和web的起步依赖,代码如下:
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
在工程的配置文件application.yml中配置应用名和端口信息,以及向admin-server注册的地址为http://localhost:8769,最后暴露自己的actuator的所有端口信息,具体配置如下:
# 项目设置
spring:
profiles:
active: local # 默认激活文件
application:
name: api-user
boot:
admin:
client:
url: http://127.0.0.1:8769
# 设置服务
server:
port: 10310
# 暴露自己的actuator的所有端口信息
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: ALWAYS
在工程的启动文件如下:
@SpringBootApplication
public class AdminClientApplication {
public static void main(String[] args) {
SpringApplication.run( AdminClientApplication.class, args );
}
}
3.启动
一次启动两个工程,在浏览器上输入localhost:8769 ,浏览器显示的界面如下:
查看wallboard:
点击wallboard,可以查看api-user具体的信息,比如内存状态信息:
也可以查看spring bean的情况:
4.集成spring security
在2.1.0版本中去掉了hystrix dashboard,登录界面默认集成到了spring security模块,只要加上spring security就集成了登录模块。
只需要改变下monitor-admin工程的pom文件引入以下的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
在monitor-admin工程的配置文件中配置spring security的用户名和密码,这时需要在服务注册时带上metadata的信息
Eureka:
spring:
security:
user:
name: "admin"
password: "admin"
eureka:
instance:
metadata-map:
user.name: "admin"
user.password: "admin"
Nacos:
spring:
security:
user:
name: "admin"
password: "admin"
cloud:
nacos:
discovery:
metadata:
user.name: "admin"
user.password: "admin"
写一个配置类SecuritySecureConfig继承WebSecurityConfigurerAdapter,配置如下:
@Configuration
public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {
private final String adminContextPath;
public SecuritySecureConfig(AdminServerProperties adminServerProperties) {
this.adminContextPath = adminServerProperties.getContextPath();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter( "redirectTo" );
http.authorizeRequests()
.antMatchers( adminContextPath + "/assets/**" ).permitAll()
.antMatchers( adminContextPath + "/login" ).permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage( adminContextPath + "/login" ).successHandler( successHandler ).and()
.logout().logoutUrl( adminContextPath + "/logout" ).and()
.httpBasic().and()
.csrf().disable();
// @formatter:on
}
}
重启工程后页面如下
5.集成邮箱报警功能
比如服务不健康了、下线了,都可以给指定邮箱发送邮件。集成非常简单,只需要改造下monitor-admin即可:
在monitor-admin工程Pom文件,加上mail的起步依赖,代码如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
在配置文件application.yml文件中,需要配置邮件相关的配置,需要注意的是发邮件的邮箱和收件邮箱需要是同一类型的邮箱,否则会报权限错误
spring:
# 警告邮箱设置
mail:
host: smtp.qq.com
username: mailA.qq.com
password: 授权码
properties:
mail.debug: true
mail.smtp.auth: true
mail.smtp.ssl.enable: true
boot:
admin:
notify:
mail:
to: mailB@qq.com
from: mailA@qq.com
做完以上配置后,当我们已注册的客户端的状态从 UP 变为 OFFLINE 或其他状态,服务端就会自动将电子邮件发送到上面配置的地址。
6.Spring Boot Admin Server配置属性
属性 | 描述 | 默认值 |
---|---|---|
spring.boot.admin.context-path | 上下文路径在应为Admin Server的静态资产和API提供服务的路径的前面加上前缀。相对于Dispatcher-Servlet | / |
spring.boot.admin.monitor.status-interval | 更新client端状态的时间间隔,单位是毫秒 | 10000 |
spring.boot.admin.monitor.status-lifetime | client端状态的生命周期,该生命周期内不会更新client状态,单位是毫秒 | 10000 |
spring.boot.admin.monitor.connect-timeout | 查询client端状态信息时的连接超时,单位是毫秒 | 2000 |
spring.boot.admin.monitor.read-timeout | 查询client端状态信息时的读取超时时间,单位是毫秒 | 10000 |
spring.boot.admin.monitor.default-retries | 失败请求的默认重试次数。Modyfing请求(PUT,POST,PATCH,DELETE)将永远不会重试 | 0 |
spring.boot.admin.monitor.retries.* | 键值对,具有每个endpointId的重试次数。默认为默认重试。Modyfing请求(PUT,POST,PATCH,DELETE)将永远不会重试 | |
spring.boot.admin.metadata-keys-to-sanitize | 要被过滤掉的元数据(当与正则表达式相匹配时,这些数据会在输出的json数据中过滤掉) | ".password$", ".secret$", ".key$", ".$token$", ".credentials.", ".*vcap_services$" |
spring.boot.admin.probed-endpoints | 要获取的client的端点信息 | "health", "env", "metrics", "httptrace:trace", "threaddump:dump", "jolokia", "info", "logfile", "refresh", "flyway", "liquibase", "heapdump", "loggers", "auditevents" |
spring.boot.admin.instance-proxy.ignored-headers | 向client发起请求时不会被转发的headers信息 | "Cookie", "Set-Cookie", "Authorization" |
spring.boot.admin.ui.public-url | 用于在ui中构建基本href的基本URL | 如果在反向代理后面运行(使用路径重写),则可用于进行正确的自我引用。如果省略了主机/端口,将从请求中推断出来 |
spring.boot.admin.ui.brand | 导航栏中显示的品牌 | <img src="assets/img/icon-spring-boot-admin.svg"><span>Spring Boot Admin</span> |
spring.boot.admin.ui.title | 页面标题 | "Spring Boot Admin" |
spring.boot.admin.ui.favicon | 用作默认图标的图标,用于桌面通知的图标 | "assets/img/favicon.png" |
spring.boot.admin.ui.favicon-danger | 当一项或多项服务关闭并用于桌面通知时,用作网站图标 | "assets/img/favicon-danger.png" |
7.Spring Boot Admin Client 配置属性
属性 | 描述 | 默认值 |
---|---|---|
spring.boot.admin.client.enabled | 启用Spring Boot Admin Client | true |
spring.boot.admin.client.url | 要注册的server端的url地址。如果要同时在多个server端口注册,则用逗号分隔各个server端的url地址 | |
spring.boot.admin.client.api-path | 管理服务器上注册端点的Http路径 | "instances" |
spring.boot.admin.client.username | 如果server端需要进行认证时,该属性用于配置用户名 | |
spring.boot.admin.client.password | 如果server端需要进行认证时,该属性用于配置密码 | |
spring.boot.admin.client.period | 重复注册的时间间隔(以毫秒为单位) | 10000 |
spring.boot.admin.client.connect-timeout | 连接注册的超时时间(以毫秒为单位) | 5000 |
spring.boot.admin.client.read-timeout | 读取注册超时(以毫秒为单位) | 5000 |
spring.boot.admin.client.auto-registration | 如果设置为true,则在应用程序准备就绪后会自动安排注册应用程序的定期任务 | true |
spring.boot.admin.client.auto-deregistration | 当上下文关闭时,切换为在Spring Boot Admin服务器上启用自动解密。如果未设置该值,并且在检测到正在运行的CloudPlatform时,该功能处于活动状态 | null |
spring.boot.admin.client.register-once | 如果设置为true,则客户端将仅向一台管理服务器注册(由定义spring.boot.admin.instance.url);如果该管理服务器出现故障,将自动向下一个管理服务器注册。如果为false,则会向所有管理服务器注册 | true |
spring.boot.admin.client.instance.health-url | 要注册的health-url地址。如果可访问URL不同(例如Docker),则可以覆盖。在注册表中必须唯一 | 默认该属性值与management-url 以及endpoints.health.id有关。比如工程中该值为:healthUrl=http://127.0.0.1:8080/actuator/health,其中http://127.0.0.1:8080/actuator是management-url,health是endpoints.health.id |
spring.boot.admin.client.instance.management-base-url | 用于计算要注册的管理URL的基本URL。该路径是在运行时推断的,并附加到基本URL | 默认该属性值与management.port, service-url 以及server.servlet-path有关,如工程中该值为http://127.0.0.1:8080,其中8080端口是配置的获取actuator信息的端口。127.0.0.1是设置的service-url值,如果没有设置service-url的话,则为配置的server.servlet-path值(项目的启动路径) |
spring.boot.admin.client.instance.management-url | 要注册的management-url。如果可访问的URL不同(例如Docker),则可以覆盖 | 默认该属性值与management-base-url 和 management.context-path两个属性值有关,如 managementUrl=http://127.0.0.1:8080/actuator,其中http://127.0.0.1:8080为management-base-url,/actuator是management.context-path |
spring.boot.admin.client.instance.service-base-url | 用于计算要注册的服务URL的基本URL。该路径是在运行时推断的,并附加到基本URL | 默认该属性值与hostname, server.port有关,如http://127.0.0.1:8080,其中8080端口是配置的server.port。127.0.0.1是client所在服务器的hostname |
spring.boot.admin.client.instance.service-url | 要注册的服务网址。如果可访问的URL不同(例如Docker),则可以覆盖 | 默认值是基于service-base-url 和 server.context-path进行赋值 |
spring.boot.admin.client.instance.name | 要注册的名称 | 默认值是配置的spring.application.name的值,如果没有配置该属性的话,默认值是spring-boot-application |
spring.boot.admin.client.instance.prefer-ip | 在猜测的网址中使用ip地址而不是主机名。如果设置了server.address/ management.address,它将被使用。否则,InetAddress.getLocalHost()将使用从返回的IP地址 | false |
spring.boot.admin.client.instance.metadata.* | 要与此实例相关联的元数据键值对 | |
spring.boot.admin.client.instance.metadata.tags.* | 标记作为要与此实例相关联的键值对 |