说明

  • Spring Boot Actuator 提供了对单个 Spring Boot 应用的监控,信息包含应用状态、内存、线程、堆栈等,比较全面的监控了 Spring Boot 应用的整个生命周期。
  • 但是这样监控也有一些问题:
    • 第一,所有的监控都需要调用固定的接口来查看,如果全面查看应用状态需要调用很多接口,并且接口返回的 JSON 信息不方便运营人员理解;
    • 第二,如果 Spring Boot 应用集群非常大,每个应用都需要调用不同的接口来查看监控信息,操作非常繁琐低效。在这样的背景下,就诞生了另外一个开源软件:Spring Boot Admin

Spring Boot Admin

  • Spring Boot Admin 是一个管理和监控 Spring Boot 应用程序的开源软件,每个应用都认为是一个客户端,通过 HTTP 或者使用 Eureka 注册到 admin server 中进行展示,Spring Boot Admin UI 部分使用 Vue.js 将数据展示在前端。

  • Spring Boot Admin 是一个针对 Spring Boot 的 Actuator 接口进行 UI 美化封装的监控工具,它可以在列表中浏览所有被监控 spring-boot 项目的基本信息、详细的 Health 信息、内存信息、JVM 信息、垃圾回收信息、各种配置信息(比如数据源、缓存列表和命中率)等,还可以直接修改 logger 的 level。

  • 值得注意的是 Spring Boot Admin 并不是 Spring Boot 官方出品的开源软件,而是开源社区孵化的项目, 其软件质量和使用广泛度都非常的高,并且 Spring Boot Admin 会及时随着 Spring Boot 的更新而更新,当 Spring Boot 推出 2.X 版本时 Spring Boot Admin 也及时进行了更新。

  • Spring Boot Admin 2.x 不仅是跟着支持了 Spring Boot 2.x,还在 1.x 的基础上进行了大量的更新和优化:

    • 重新规划了项目依赖包,让项目中更方便的集成 Spring Boot Admin
    • 1.x 前端使用了 Angular.js,2.x 使用 Vue 对界面进行了重写,界面美观度提升幅度非常高
    • 提供了支持 Spring Cloud 的组件
    • 其他更新,具体参考:Changes with 2.x
  • Spring Boot Admin 分为服务端和客户端,

    • 服务端其实就是一个监控后台用来汇总展示所有的监控信息,
    • 客户端就是我们的应用,
  • 使用时需要先启动服务端,在启动客户端的时候打开 Actuator 的接口,并指向服务端的地址,这样服务端会定时读取相关信息以达到监控的目的。

  • 官网参考链接:https://github.com/codecentric/spring-boot-admin/

监控单体应用

用 Spring Boot Admin 监控单个 Spring Boot 应用。

服务端的搭建

添加依赖

  • pom.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- 2.x 下只需要添加此一个包即可,其他组件会自动依赖添加。-->
    <dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-server</artifactId>
    <version>2.3.1</version>
    </dependency>
    </dependencies>
  • application.yml 中配置端口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 指定端口
    server:
    port: 6145
    spring:
    application:
    name: spring-boot-admin
    # 登录账号和密码
    security:
    user:
    name: fulsun
    password: 123456

启动类

  • 创建一个启动类,具体代码如下所示。

    1
    2
    3
    4
    5
    6
    7
    @EnableAdminServer // 开启 springboot admin 服务端
    @SpringBootApplication
    public class App {
    public static void main(String[] args) {
    SpringApplication.run(App.class, args);
    }
    }

效果

  • 浏览器访问 http://localhost: 6145/ 出现以下页面说明 SpringBoot Admin 服务端搭建成功

搭建 client 端

  1. 进入 demo-actuator,启动客户端程序,注册到服务端

  2. 在需要监测的项目的 pom 加入如下依赖

    • 添加 spring-boot-starter-web 是为了使应用处于启动状态,

    • spring-boot-admin-starter-client 会自动添加 Actuator 相关依赖。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <dependencies>
    <dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-client</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-security</artifactId>
    </dependency>
    </dependencies>
  3. 配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    server:
    port: 8080
    servlet:
    context-path: /demo
    # 若要访问端点信息,需要配置用户名和密码
    spring:
    application:
    # Spring Boot Admin展示的客户端项目名,不设置,会使用自动生成的随机id
    name: demo-actuator
    security:
    user:
    name: fulsun
    password: 123456
    boot:
    admin:
    client:
    #监控服务器的地址
    url: http://localhost:6145
    # username: fulsun
    # password: 123456
    instance:
    # 当前系统首页地址
    service-base-url: http://localhost:8080/
    metadata:
    # 客户端端点信息的安全认证信息
    user.name: ${spring.security.user.name}
    user.password: ${spring.security.user.password}

    management:
    # 端点信息接口使用的端口,为了和主系统接口使用的端口进行分离
    # server:
    # port: 8090
    # servlet:
    # context-path: /sys
    # 端点健康情况,默认值"never",设置为"always"可以显示硬盘使用情况和线程情况
    endpoint:
    health:
    show-details: always
    shutdown:
    # 允许admin工程远程停止本应用
    enabled: true
    endpoints:
    web:
    exposure:
    # 设置端点暴露的哪些内容,默认["health","info"],设置"*"代表暴露所有可访问的端点
    include: '*'

效果

  • 配置完成之后,启动 Client 端,Admin 服务端会自动检查到客户端的变化,并展示其应用:

  • 页面会展示被监控的服务列表,点击项目名称会进入此应用的详细监控信息:

监控微服务

  • 如果我们使用的是单个 Spring Boot 应用,就需要在每一个被监控的应用中配置 Admin Server 的地址信息;

  • 如果应用都注册在 Eureka 中就不需要再对每个应用进行配置,Spring Boot Admin 会自动从注册中心抓取应用的相关信息。

  • 如果使用了 Spring Cloud 的服务发现功能,就不需要再单独添加 Admin Client 客户端,仅仅需要 Spring Boot Server,其他内容会自动进行配置。

演示

  • 接下来以 Eureka 作为服务发现的示例来进行演示,实际上也可以使用 Consul 或者 Zookeeper。

添加依赖

  • 服务端和客户端添加 spring-cloud-starter-eureka 到包依赖中

    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

启动类

  • 启动类添加注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    @Configuration
    @EnableAutoConfiguration
    @EnableDiscoveryClient
    @EnableAdminServer
    public class SpringBootAdminApplication {
    public static void main(String[] args) {
    SpringApplication.run(SpringBootAdminApplication.class, args);
    }

    @Configuration
    public static class SecurityPermitAllConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().anyRequest().permitAll()
    .and().csrf().disable();
    }
    }
    }
  • 使用类 SecurityPermitAllConfig 关闭了安全验证。

配置文件

  • 在客户端中配置服务发现的地址

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    eureka:   
    instance:
    leaseRenewalIntervalInSeconds: 10
    health-check-url-path: /actuator/health
    metadata-map:
    startup: ${random.int} #needed to trigger info and endpoint update after restart
    client:
    registryFetchIntervalSeconds: 5
    serviceUrl:
    defaultZone: ${EUREKA_SERVICE_URL:http://localhost:8761}/eureka/

    management:
    endpoints:
    web:
    exposure:
    include: "*"
    endpoint:
    health:
    show-details: ALWAYS
  • Spring Cloud 提供了示例代码可以参考这里:spring-boot-admin-sample-eureka

  • 重启启动服务端和客户端之后,访问服务端的相关地址就可以看到监控页面了。

安全控制

  • Spring Boot Admin 后台有很多的敏感信息和操作,如果公司不做权限控制可能会影响到公司系统的安全性。
  • Spring Boot Admin 也考虑到了这个因素,可以利用前面的 Spring Security 做安全访问控制,在 spring-boot-admin-server 上进行改造。

改造 server

  • 添加 Spring Boot Security 依赖包

    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
  • 添加安全访问控制

    • 和前面的 Security 配置一样,给项目添加访问控制。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    @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,引导 Spring Boot Admin 客户端注册
    .httpBasic().and()
    .csrf()
    // 打开跨站点请求保护 Cookies
    .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
    .ignoringAntMatchers(
    // 取消跨站点请求保护 "/instances",方便 Admin 客户端注册
    adminContextPath + "/instances",
    // 取消跨站点请求保护 "/actuator/**",可以让 Admin 监控到 Actuator 的相关接口
    adminContextPath + "/actuator/**"
    );
    }
    }
  • 然后可以给 security 设置一个用户名和密码:

    1
    2
    spring.security.user.name=admin
    spring.security.user.password=admin
  • 配置完成之后重启 Admin Server 端,访问网址 http://localhost: 6145 就会发现需要一个登录的用户名和密码了。

  • 使用刚才设置的用户名和密码登录之后,发现注册到 Server 端的服务数成为 0 了,这是 客户端也需要配置服务端的帐户名和密码信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    spring:
    application:
    # Spring Boot Admin展示的客户端项目名,不设置,会使用自动生成的随机id
    name: spring-boot-demo-admin-client
    security:
    user:
    name: admin
    password: admin
    boot:
    admin:
    client:
    instance:
    metadata:
    # 用客户端信息注册:
    user.name: ${spring.security.user.name}
    user.password: ${spring.security.user.password}
    url: "http://localhost:8000"
    username: admin
    password: admin
  • 配置完成之后重新启动,在服务端就又可以查看监控到的应用了。

客户端安全方式

  • 如果 客户端 Actuator 的端口被使用 HTTP 认证保护,那么 Spring Boot Admin Server 访问的时候需要凭证信息,这时候可以使用 metadata 的方式对账户和密码进行配置。

直接使用客户端注册的方式:

1
2
3
4
5
6
spring.boot.admin.client:
url: http://localhost:8080
instance:
metadata:
user.name: ${spring.security.user.name}
user.password: ${spring.security.user.password}

使用 Eureka 进行注册的方式:

1
2
3
4
5
eureka:
instance:
metadata-map:
user.name: ${spring.security.user.name}
user.password: ${spring.security.user.password}
  • Eureka 中的 metadataMap 是专门用来存放一些自定义的数据,当注册中心或者其他服务需要此服务的某些配置时可以在 metadataMap 里取。
  • 实际上,每个 instance 都有各自的 metadataMap,map 中存放着需要用到的属性。
  • 例如,上面配置中的 eureka.instance.metadata-map.user.name,当这个服务成功注册到 Eureka 上,Spring Boot Admin 就会拿到这个 instance,进而拿到 metadataMap 里的属性,然后放入请求头,向此服务发送请求,访问此服务的 Actuator 开放的端点。

邮件告警

  • Spring Boot Admin 将微服务中所有应用信息在后台进行了展示,非常方便我们对微服务整体的监控和治理。但是我们的运营人员也不可能一天 24 小时盯着监控后台,因此如果服务有异常的时候,有对应的邮件告警就太好了,其实 Spring Boot Admin 也给出了支持。

  • 我们对上面的示例项目 spring-boot-admin-server 进行改造。

添加依赖

增加了邮件发送的 starter 包。

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>

配置文件

  • 在配置文件中添加邮件发送相关信息:邮件的发送者、接受者、协议、移动授权码等

    1
    2
    3
    4
    5
    6
    7
    8
    spring.mail.host=smtp.qq.com
    spring.mail.username=xxx@qq.com
    spring.mail.password=xxx
    spring.mail.properties.mail.smtp.auth=true
    spring.mail.properties.mail.smtp.starttls.enable=true
    spring.mail.properties.mail.smtp.starttls.required=true
    spring.boot.admin.notify.mail.from=yyyy@qq.com
    spring.boot.admin.notify.mail.to=zzz@qq.com
  • 配置完成后,重新启动项目 spring-boot-admin-server,这样 Admin Server 就具备了邮件告警的功能,默认情况下 Admin Server 对 Eureka 中的服务上下线都进行了监控,当服务上下线的时候我们就会收到相应的告警邮件。

  • 当然这只是最基本的邮件监控,在实际的使用过程中,需要根据情况对邮件告警内容进行自定义,比如监控堆内存的使用情况,当到达一定比例的时候进行告警等。

写在后面的话

  • Spring Boot Admin 解决了我们对大规模 Spring Boot 应用监控的需求

  • Spring Boot Admin 充分利用了 Actuator 开放的相关接口,采用优秀的图形界面将这些信息进行了展示,方便我们更加直观的查看集群中应用的状态。

  • Spring Boot Admin 不仅可以监控单个 Spring Boot 应用,也可以结合 Spring Cloud 监控注册到服务中心的所有应用状态,再结合报警系统的使用就可以随时感知到应用的状态变化。

  • 在实际工作中 Spring Boot Admin 是我们在后期运营中频繁用到的一个组件,应该作为重点关注。