查看原文
其他

SpringBoot Admin 2.0 详解

macrozheng 2020-09-13

The following article is from 程序员果果 Author 程序员果果


一、什么是Spring Boot Admin ?

Spring Boot Admin是一个开源社区项目,用于管理和监控SpringBoot应用程序。应用程序作为Spring Boot Admin Client向为Spring Boot Admin Server注册(通过HTTP)或使用SpringCloud注册中心(例如Eureka,Consul)发现。UI是的Vue.js应用程序,展示Spring Boot Admin Client的Actuator端点上的一些监控。服务端采用Spring WebFlux + Netty的方式。Spring Boot Admin为注册的应用程序提供以下功能:

  • 显示健康状况

  • 显示详细信息,例如

    • JVM和内存指标

    • micrometer.io指标

    • 数据源指标

    • 缓存指标

  • 显示构建信息编号

  • 关注并下载日志文件

  • 查看jvm system-和environment-properties

  • 查看Spring Boot配置属性

  • 支持Spring Cloud的postable / env-和/ refresh-endpoint

  • 轻松的日志级管理

  • 与JMX-beans交互

  • 查看线程转储

  • 查看http-traces

  • 查看auditevents

  • 查看http-endpoints

  • 查看计划任务

  • 查看和删除活动会话(使用spring-session)

  • 查看Flyway / Liquibase数据库迁移

  • 下载heapdump

  • 状态变更通知(通过电子邮件,Slack,Hipchat,......)

  • 状态更改的事件日志(非持久性)


二、入门

1. 创建 Spring Boot Admin Server

pom.xml

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

   <modelVersion>4.0.0</modelVersion>
   <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>2.1.0.RELEASE</version>
       <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.gf</groupId>
   <artifactId>admin-server</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>admin-server</name>
   <description>Demo project for Spring Boot</description>

   <properties>
       <java.version>1.8</java.version>
       <spring-boot-admin.version>2.1.0</spring-boot-admin.version>    </properties>

   <dependencies>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
       <dependency>
           <groupId>de.codecentric</groupId>
           <artifactId>spring-boot-admin-starter-server</artifactId>
       </dependency>

       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-test</artifactId>
           <scope>test</scope>
       </dependency>
   </dependencies>

   <dependencyManagement>
       <dependencies>
           <dependency>
               <groupId>de.codecentric</groupId>
               <artifactId>spring-boot-admin-dependencies</artifactId>
               <version>${spring-boot-admin.version}</version>
               <type>pom</type>
               <scope>import</scope>
           </dependency>
       </dependencies>
   </dependencyManagement>

   <build>
       <plugins>
           <plugin>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-maven-plugin</artifactId>
           </plugin>
       </plugins>
   </build>

</project>

application.yml

spring:
 application:
   name: admin-server
server:
 port: 8769

启动类 AdminServerApplication

启动类加上@EnableAdminServer注解,开启AdminServer的功能:

@SpringBootApplication
@EnableAdminServer
public class AdminServerApplication {

   public static void main(String[] args) {
       SpringApplication.run( AdminServerApplication.class, args );
   }

}

2. 创建 Spring Boot Admin Client

pom.xml

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

   <modelVersion>4.0.0</modelVersion>
   <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>2.1.0.RELEASE</version>
       <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.gf</groupId>
   <artifactId>admin-client</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>admin-client</name>
   <description>Demo project for Spring Boot</description>

   <properties>
       <java.version>1.8</java.version>
       <spring-boot-admin.version>2.1.0</spring-boot-admin.version>    </properties>

   <dependencies>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
       <dependency>
           <groupId>de.codecentric</groupId>
           <artifactId>spring-boot-admin-starter-client</artifactId>
       </dependency>

       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-test</artifactId>
           <scope>test</scope>
       </dependency>
   </dependencies>

   <dependencyManagement>
       <dependencies>
           <dependency>
               <groupId>de.codecentric</groupId>
               <artifactId>spring-boot-admin-dependencies</artifactId>
               <version>${spring-boot-admin.version}</version>
               <type>pom</type>
               <scope>import</scope>
           </dependency>
       </dependencies>
   </dependencyManagement>

   <build>
       <plugins>
           <plugin>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-maven-plugin</artifactId>
           </plugin>
       </plugins>
   </build>

</project>

application.yml

  • spring.boot.admin.client.url:要注册的Spring Boot Admin Server的URL。

  • management.endpoints.web.exposure.include:与Spring Boot 2一样,默认情况下,大多数actuator的端口都不会通过http公开,* 代表公开所有这些端点。对于生产环境,应该仔细选择要公开的端点。

spring:
 application:
   name: admin-client
 boot:
   admin:
     client:
       url: http://localhost:8769
server:
 port: 8768

management:
 endpoints:
   web:
     exposure:
       include: '*'
 endpoint:
   health:
     show-details: ALWAYS

启动类 AdminClientApplication

@SpringBootApplication
public class AdminClientApplication {

   public static void main(String[] args) {
       SpringApplication.run( AdminClientApplication.class, args );
   }

}

启动两个工程,在浏览器上输入localhost:8769 ,浏览器显示的界面如下:


查看wallboard:


点击wallboard,可以查看admin-client具体的信息,比如内存状态信息:


查看spring bean的情况:


查看应用程序运行状况,信息和详细:


还有很多监控信息,多点一点就知道。


三、集成 Eureka

1. 创建 sc-eureka-server

这是一个 eureka-server 注册中心。

pom.xml

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

   <modelVersion>4.0.0</modelVersion>
   <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>2.1.0.RELEASE</version>
       <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.gf</groupId>
   <artifactId>sc-admin-server</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>sc-admin-server</name>
   <description>Demo project for Spring Boot</description>

   <properties>
       <java.version>1.8</java.version>
       <spring-boot-admin.version>2.1.0</spring-boot-admin.version>
       <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>    </properties>

   <dependencies>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
       <dependency>
           <groupId>de.codecentric</groupId>
           <artifactId>spring-boot-admin-starter-server</artifactId>
           <version>2.1.0</version>
       </dependency>
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
       </dependency>

       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-test</artifactId>
           <scope>test</scope>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-security</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-mail</artifactId>
       </dependency>
       <dependency>
           <groupId>org.jolokia</groupId>
           <artifactId>jolokia-core</artifactId>
       </dependency>
   </dependencies>

   <dependencyManagement>
       <dependencies>
           <dependency>
               <groupId>org.springframework.cloud</groupId>
               <artifactId>spring-cloud-dependencies</artifactId>
               <version>${spring-cloud.version}</version>
               <type>pom</type>
               <scope>import</scope>
           </dependency>
           <dependency>
               <groupId>de.codecentric</groupId>
               <artifactId>spring-boot-admin-dependencies</artifactId>
               <version>${spring-boot-admin.version}</version>
               <type>pom</type>
               <scope>import</scope>
           </dependency>
       </dependencies>
   </dependencyManagement>

   <build>
       <plugins>
           <plugin>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-maven-plugin</artifactId>
           </plugin>
       </plugins>
   </build>

</project>

application.yml

spring:
 application:
   name: sc-eureka-server
server:
 port: 8761
eureka:
 client:
   service-url:
     defaultZone: http://localhost:8761/eureka
   register-with-eureka: false
   fetch-registry: false
management:
 endpoints:
   web:
     exposure:
       include: "*"
 endpoint:
   health:
     show-details: ALWAYS

启动类 ScEurekaServerApplication

@SpringBootApplication
@EnableEurekaServer
public class ScEurekaServerApplication {

   public static void main(String[] args) {
       SpringApplication.run( ScEurekaServerApplication.class, args );
   }

}

2. 创建 sc-admin-server

这是一个 Spring Boot Admin Server端。

pom.xml

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

   <modelVersion>4.0.0</modelVersion>
   <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>2.1.0.RELEASE</version>
       <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.gf</groupId>
   <artifactId>sc-admin-server</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>sc-admin-server</name>
   <description>Demo project for Spring Boot</description>

   <properties>
       <java.version>1.8</java.version>
       <spring-boot-admin.version>2.1.0</spring-boot-admin.version>
       <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>    </properties>

   <dependencies>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
       <dependency>
           <groupId>de.codecentric</groupId>
           <artifactId>spring-boot-admin-starter-server</artifactId>
           <version>2.1.0</version>
       </dependency>
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
       </dependency>

       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-test</artifactId>
           <scope>test</scope>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-security</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-mail</artifactId>
       </dependency>
       <dependency>
           <groupId>org.jolokia</groupId>
           <artifactId>jolokia-core</artifactId>
       </dependency>
   </dependencies>

   <dependencyManagement>
       <dependencies>
           <dependency>
               <groupId>org.springframework.cloud</groupId>
               <artifactId>spring-cloud-dependencies</artifactId>
               <version>${spring-cloud.version}</version>
               <type>pom</type>
               <scope>import</scope>
           </dependency>
           <dependency>
               <groupId>de.codecentric</groupId>
               <artifactId>spring-boot-admin-dependencies</artifactId>
               <version>${spring-boot-admin.version}</version>
               <type>pom</type>
               <scope>import</scope>
           </dependency>
       </dependencies>
   </dependencyManagement>

   <build>
       <plugins>
           <plugin>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-maven-plugin</artifactId>
           </plugin>
       </plugins>
   </build>

</project>

application.yml

spring:
 application:
   name: admin-server
server:
 port: 8769
eureka:
 client:
   registryFetchIntervalSeconds: 5
   service-url:
     defaultZone: ${EUREKA_SERVICE_URL:http://localhost:8761}/eureka/
 instance:
   leaseRenewalIntervalInSeconds: 10
   health-check-url-path: /actuator/health

management:
 endpoints:
   web:
     exposure:
       include: "*"
 endpoint:
   health:
     show-details: ALWAYS

启动类 ScAdminServerApplication

@SpringBootApplication
@EnableAdminServer
@EnableDiscoveryClient
public class ScAdminServerApplication {

   public static void main(String[] args) {
       SpringApplication.run( ScAdminServerApplication.class, args );
   }

}

3. 创建 sc-admin-client

这是一个 Spring Boot Admin client 端。

pom.xml

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

   <modelVersion>4.0.0</modelVersion>
   <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>2.1.0.RELEASE</version>
       <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.gf</groupId>
   <artifactId>sc-admin-client</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>sc-admin-client</name>
   <description>Demo project for Spring Boot</description>

   <properties>
       <java.version>1.8</java.version>
       <spring-boot-admin.version>2.1.0</spring-boot-admin.version>
       <spring-cloud.version>Finchley.SR2</spring-cloud.version>    </properties>

   <dependencies>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-actuator</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-webflux</artifactId>
       </dependency>
       <dependency>
           <groupId>de.codecentric</groupId>
           <artifactId>spring-boot-admin-starter-client</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
       </dependency>

       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-test</artifactId>
           <scope>test</scope>
       </dependency>
   </dependencies>

   <dependencyManagement>
       <dependencies>
           <dependency>
               <groupId>org.springframework.cloud</groupId>
               <artifactId>spring-cloud-dependencies</artifactId>
               <version>${spring-cloud.version}</version>
               <type>pom</type>
               <scope>import</scope>
           </dependency>
           <dependency>
               <groupId>de.codecentric</groupId>
               <artifactId>spring-boot-admin-dependencies</artifactId>
               <version>${spring-boot-admin.version}</version>
               <type>pom</type>
               <scope>import</scope>
           </dependency>
       </dependencies>
   </dependencyManagement>

   <build>
       <plugins>
           <plugin>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-maven-plugin</artifactId>
           </plugin>
       </plugins>
   </build>

</project>

application.yml

spring:
 application:
   name: sc-admin-client
eureka:
 instance:
   leaseRenewalIntervalInSeconds: 10
   health-check-url-path: /actuator/health

 client:
   registryFetchIntervalSeconds: 5
   service-url:
     defaultZone: ${EUREKA_SERVICE_URL:http://localhost:8761}/eureka/
management:
 endpoints:
   web:
     exposure:
       include: "*"
 endpoint:
   health:
     show-details: ALWAYS
server:
 port: 8762

启动类 ScAdminClientApplication

@SpringBootApplication
@EnableDiscoveryClient
public class ScAdminClientApplication {

   public static void main(String[] args) {
       SpringApplication.run( ScAdminClientApplication.class, args );
   }

}

启动三个工程,访问localhost:8769,出现如下界面:


admin 会自己拉取 Eureka 上注册的 app 信息,主动去注册。这也是唯一区别之前入门中手动注册的地方,就是 client 端不需要 admin-client 的依赖,也不需要配置 admin 地址了,一切全部由 admin-server 自己实现。这样的设计对环境变化很友好,不用改了admin-server后去改所有app 的配置了。


四、集成 Spring Security

Web应用程序中的身份验证和授权有多种方法,因此Spring Boot Admin不提供默认方法。默认情况下,spring-boot-admin-server-ui提供登录页面和注销按钮。我们结合 Spring Security 实现需要用户名和密码登录的安全认证。

sc-admin-server工程的pom文件需要增加以下的依赖:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-security</artifactId>
</dependency>

在 sc-admin-server工的配置文件 application.yml 中配置 spring security 的用户名和密码,这时需要在服务注册时带上 metadata-map 的信息,如下:

spring:
 security:
   user:
     name: "admin"
     password: "admin"
     
eureka:
 instance:
   metadata-map:
     user.name: ${spring.security.user.name}
     user.password: ${spring.security.user.password}

@EnableWebSecurity注解以及WebSecurityConfigurerAdapter一起配合提供基于web的security。继承了WebSecurityConfigurerAdapter之后,再加上几行代码,我们就能实现要求用户在进入应用的任何URL之前都进行验证的功能,写一个配置类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");
       successHandler.setDefaultTargetUrl(adminContextPath + "/");

       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()
               //启用HTTP-Basic支持。这是Spring Boot Admin Client注册所必需的
               .httpBasic().and();
       // @formatter:on
   }

}

重新访问 http://localhost:8769/ 会出现登录界面,密码是 配置文件中配置好的,账号 admin 密码 admin,界面如下:


五、通知

1. 邮件通知

在 Spring Boot Admin 中 当注册的应用程序状态更改为DOWN、UNKNOWN、OFFLINE 都可以指定触发通知,下面讲解配置邮件通知。

在sc-admin-server工程pom文件,加上mail的依赖,如下:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

在配置文件application.yml文件中,配置收发邮件的配置:

spring:
 mail:
   host: smtp.163.com
   username: xxxx@163.com
   password: xxxx
   properties:
     mail:
       smtp:
         auth: true
         starttls:
           enable: true
           required: true
 boot:
   admin:
     notify:
       mail:
         from: xxxx@163.com
         to: xxxx@qq.com

配置后,重启sc-admin-server工程,之后若出现注册的客户端的状态从 UP 变为 OFFLINE 或其他状态,服务端就会自动将电子邮件发送到上面配置的收件地址。

注意 : 配置了邮件通知后,会出现 反复通知 service offline / up。这个问题的原因在于 查询应用程序的状态和信息超时,下面给出两种解决方案:

#方法一:增加超时时间(单位:ms)

spring.boot.admin.monitor.read-timeout=20000

#方法二:关闭闭未使用或不重要的检查点

management.health.db.enabled=false
management.health.mail.enabled=false
management.health.redis.enabled=false
management.health.mongo.enabled=false

2. 自定义通知

可以通过添加实现Notifier接口的Spring Beans来添加您自己的通知程序,最好通过扩展 AbstractEventNotifier或AbstractStatusChangeNotifier。在sc-admin-server工程中编写一个自定义的通知器:

@Component
public class CustomNotifier  extends AbstractStatusChangeNotifier {
   private static final Logger LOGGER = LoggerFactory.getLogger( LoggingNotifier.class);

   public CustomNotifier(InstanceRepository repository) {
       super(repository);
   }

   @Override
   protected Mono<Void> doNotify(InstanceEvent event, Instance instance) {
       return Mono.fromRunnable(() -> {
           if (event instanceof InstanceStatusChangedEvent) {
               LOGGER.info("Instance {} ({}) is {}", instance.getRegistration().getName(), event.getInstance(),
                       ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus());

               String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus();

               switch (status) {
                   // 健康检查没通过
                   case "DOWN":
                       System.out.println("发送 健康检查没通过 的通知!");
                       break;
                   // 服务离线
                   case "OFFLINE":
                       System.out.println("发送 服务离线 的通知!");
                       break;
                   //服务上线
                   case "UP":
                       System.out.println("发送 服务上线 的通知!");
                       break;
                   // 服务未知异常
                   case "UNKNOWN":
                       System.out.println("发送 服务未知异常 的通知!");
                       break;
                   default:
                       break;
               }

           } else {
               LOGGER.info("Instance {} ({}) {}", instance.getRegistration().getName(), event.getInstance(),
                       event.getType());
           }
       });
   }

}

源码下载:https://github.com/gf-huanchupk/SpringBootLearning/tree/master/springboot-admin

推荐阅读




欢迎关注,点个在看



    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存