1. 什么是 Spring Boot Admin(SBA)?

Spring Boot Admin 是 codecentric 公司开发的一款开源社区项目,目标是让用户更方便的管理以及监控 Spring Boot ® 应用。 应用可以通过我们的Spring Boot Admin客户端(通过HTTP的方式)或者使用Spring Cloud ®(比如Eureka,consul的方式)注册。 而前端UI则是使用Vue.js,基于Spring Boot Actuator默认接口开发的。

针对Python应用可以使用 Pyctuator 来进行支持。

2. 入门

2.1. 配置SBA服务端应用程序

第一步,你需要配置你的服务端程序。 为此,只需要配置一个基础的boot项目(使用 start.spring.io 生成脚手架)。 由于Spring Boot Admin Server同时支持servlet和webflux,所以你需要在其中进行选择,并添加对应的Spring Boot Starter。 在本例中,我们使用servlet作为web starter。

  1. 将Spring Boot Admin Server的starter添加到你的依赖中:

    pom.xml
    <dependency>
        <groupId>de.codecentric</groupId>
        <artifactId>spring-boot-admin-starter-server</artifactId>
        <version>2.6.6</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

如果你使用的是Spring Boot Admin Server的snapshot版本,那么可能还需要添加spring的sonatype snapshot仓库:

pom.xml
<repositories>
    <repository>
        <id>spring-milestone</id>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
        <url>http://repo.spring.io/milestone</url>
    </repository>
    <repository>
        <id>spring-snapshot</id>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
        <url>http://repo.spring.io/snapshot</url>
    </repository>
    <repository>
        <id>sonatype-nexus-snapshots</id>
        <name>Sonatype Nexus Snapshots</name>
        <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
        <releases>
            <enabled>false</enabled>
        </releases>
    </repository>
</repositories>
  1. 在main class上添加`@EnableAdminServer`注解,启用SBA服务器端配置:

    @Configuration
    @EnableAutoConfiguration
    @EnableAdminServer
    public class SpringBootAdminApplication {
        public static void main(String[] args) {
            SpringApplication.run(SpringBootAdminApplication.class, args);
        }
    }
如果你想通过部署war包,以servlet容器的方式来设置SBA,那么请查看 spring-boot-admin-sample-war

同时也看看 spring-boot-admin-sample-servlet, 其中添加了安全保护。

2.2. 注册客户端应用程序

要想在SBA服务端注册你的应用,你需要引入SBA客户端,或者是使用 Spring Cloud服务发现 (例如 Eureka、Consul等等)。 这里有一个 在SBA服务端使用静态配置的简单选项

2.2.1. SBA客户端服务

所有要注册的应用都需要添加Spring Boot Admin客户端依赖。 如果要想对默认接口进行安全保护,还需要添加 spring-boot-starter-security 依赖。

  1. 添加spring-boot-admin-starter-client依赖:

    pom.xml
    <dependency>
        <groupId>de.codecentric</groupId>
        <artifactId>spring-boot-admin-starter-client</artifactId>
        <version>2.6.6</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
  2. 配置Spring Boot Admin服务端的URL来开启SBA客户端:

    application.properties
    spring.boot.admin.client.url=http://localhost:8080  (1)
    management.endpoints.web.exposure.include=*  (2)
    management.info.env.enabled=true (3)
    1 将要注册到的Spring Boot Admin 服务端URL地址。
    2 与Spring Boot 2一样,大部分默认接口都没有通过http暴露出来,这里我们将它们全部暴露。在生产环境,您应该酌情选择您要公开的接口。
    3 在Spring Boot 2.6版本之后,env信息默认是关闭的。所以我们必须启用它们。
  3. 让所有的actuator接口都可以访问:

    @Configuration
    public static class SecurityPermitAllConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests().anyRequest().permitAll()  (1)
                .and().csrf().disable();
        }
    }
    1 为了演示的简单,我们禁用了安全功能。请查看 安全处理章节 来学习如何保护您的接口。

2.2.2. Spring Cloud 服务发现

如果已经在应用中使用了Spring Cloud Discovery,那么就不需要SBA客户端了。 只需要为Spring Boot Admin服务端添加一个DiscoveryClient,其余的工作都会由我们自动配置完成。

下面的步骤中我们使用的是Eureka,但是其它的Spring Cloud Discovery实现也都支持的很好。 这里就有一些使用 ConsulZookeeper 的例子。

另外,也参考一下 Spring Cloud 文档

  1. 在依赖中添加spring-cloud-starter-eureka:

    pom.xml
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
  2. 在配置类中添加 @EnableDiscoveryClient 注解以启用服务发现:

    @Configuration
    @EnableAutoConfiguration
    @EnableDiscoveryClient
    @EnableScheduling
    @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()  (1)
                    .and().csrf().disable();
            }
        }
    }
    1 为了演示的简单,我们禁用了安全功能。请查看 安全处理章节 来学习如何保护您的接口。
  3. 告诉Eureka客户端在哪里查找服务:

    application.yml
    eureka:   (1)
      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: "*"  (2)
      endpoint:
        health:
          show-details: ALWAYS
    1 针对Eureka客户端的配置部分
    2 与Spring Boot 2一样,大部分默认接口都没有通过http暴露出来,这里我们将它们全部暴露。在生产环境,您应该酌情选择您要公开的接口。

另外,也参考一下 spring-boot-admin-sample-eureka

你也可以将Spring Boot Admin服务端安装在Eureka服务端上。首先将前文的安装步骤重复一遍,然后将 spring.boot.admin.context-path 设置为除了 "/" 之外的其它路径,这样Spring Boot Admin服务端的用户交互页面就不会和Eureka的冲突了。

2.2.3. 使用Pyctuator注册Python应用程序

使用 Pyctuator,您可以轻松的将Spring Boot Admin与 Flask 或者是 FastAPI 轻松的集成在一起。

下面的例子使用的是Flask,但是其它web框架也支持的很好。 有关框架的更新列表以及所支持的功能,请查看Pyctuator官方文档。

  1. 安装pyctuator包:

    pip install pyctuator
  2. 将pyctuator指向你的Flask应用,让它知道Spring Boot Admin是在哪里运行的,从而启用pyctuator:

    import os
    from flask import Flask
    from pyctuator.pyctuator import Pyctuator
    
    app_name = "Flask App with Pyctuator"
    app = Flask(app_name)
    
    
    @app.route("/")
    def hello():
        return "Hello World!"
    
    
    Pyctuator(
        app,
        app_name,
        app_url="http://example-app.com",
        pyctuator_endpoint_url="http://example-app.com/pyctuator",
        registration_url=os.getenv("SPRING_BOOT_ADMIN_URL")
    )
    
    app.run()

有关更多的详细信息和示例,请查看Pyctuator的 官方文档 以及 官方示例

3. 客户端应用程序

3.1. 在应用列表中显示版本号

对于 Spring Boot 应用程序,显示版本号最简单的办法,就是使用 spring-boot-maven-plugin maven插件,然后配置 goal build-info,之后该插件就会生成 META-INF/build-info.properties 文件了。更多详情请查看 Spring Boot 参考指南

对于 非Spring Boot 应用的话,可以在注册的时候添加 versionbuild.version 参数,这样在应用列表中就会显示版本号了。

pom.xml
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>build-info</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

要想在gradle项目中生成构建信息的话,请在 build.gradle 文件中添加下面的代码:

build.gradle
springBoot {
  buildInfo()
}

3.2. JMX-Bean的管理

要想在admin页面中与JMX-beans进行交互,必须在应用中引入 Jolokia。 由于Jolokia是基于servlet开发的,所以不支持响应式应用。 如果你使用的是 spring-boot-admin-starter-client 这个依赖,那么它自动会为您引入,如果没有的话,则需要手动的将Jolokia添加到依赖中。 针对Spring Boot 2.2.0版本,如果您想通过JMX暴露Spring bean的话,可能需要设置 spring.jmx.enabled=true

pom.xml
<dependency>
    <groupId>org.jolokia</groupId>
    <artifactId>jolokia-core</artifactId>
</dependency>

3.3. 查看日志文件

默认情况下,无法通过actuator接口访问日志文件,因此默认Spring Boot Admin中是看不到日志文件的。 要想启用actuator的日志文件接口,需要设置 logging.file.pathlogging.file.name 来配置Spring Boot读写日志文件。

Spring Boot Admin会检测所有看起来像URL的东西,并将其呈现为超链接。

ANSI颜色转义语法也是支持的。 你可以自定义一个文件日志的表达式,因为Spring Boot默认情况下是不使用颜色的。

application.properties
logging.file.name=/var/log/sample-boot-application.log (1)
logging.pattern.file=%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID}){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wEx (2)
1 定义日志文件的写入目录。启用日志文件的actuator接口。
2 文件日志使用自定义的ANSI颜色。

3.4. 显示实例的标签

您可以为每个实例添加一个 标签(Tags) 来提高其可读性,它们会显示在应用列表以及实例试图中。 默认情况下实例不会被添加任何标签,它取决与客户端有没有向metadata元数据中添加标签或是向其它info接口中指定标签。

application.properties
#使用metadata元数据
spring.boot.admin.client.instance.metadata.tags.environment=test

#使用info接口
info.tags.environment=test

3.5. SBA客户端

Spring Boot Admin客户端会注册在admin的服务端上。 这是通过定期向SBA服务端发送HTTP post请求来完成的,同时也会向服务端提供应用信息。

有一些可选的属性可以影响SBA客户端的注册方式。如果这些不满足您的需求,你也可以通过提供 ApplicationFactory 实现的方式手动拓展。
表格 1. Spring Boot Admin 客户端配置可选项
属性名 说明 默认值

spring.boot.admin.client.enabled

开启Spring Boot Admin 客户端。

true

spring.boot.admin.client.url

向哪些Spring Boot Admin服务端注册,可以传一个列表,URL中间以逗号分割。这个参数会自动触发。强制性 的。

spring.boot.admin.client.api-path

提供admin服务端的http注册路径。

"instances"

spring.boot.admin.client.username
spring.boot.admin.client.password

如果SBA服务端启用了HTTP Basic认证,则需要提供用户名和密码。

spring.boot.admin.client.period

重复注册的间隔(单位毫秒ms)。

10,000

spring.boot.admin.client.connect-timeout

注册链接的超时时间(单位毫秒ms)。

5,000

spring.boot.admin.client.read-timeout

注册时的读取超时时间(单位毫秒ms)。

5,000

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的话,客户端只会注册到一个admin服务端中(根据 spring.boot.admin.instance.url 中定义的顺序); 如果admin服务端挂掉了的话,则会自动注册到下一个admin服务端。 如果设置为false,那么会注册到所有配置的admin服务端中。

true

spring.boot.admin.client.instance.health-url

注册使用的健康检查url,如果URL不同也可以被覆盖(例如在使用Docker的时候)。在注册时必须时唯一的。

根据 management-url 和 endpoints.health.id 进行拼接。

spring.boot.admin.client.instance.management-base-url

根据 management-url 在注册时进行计算。这个路径在运行期间才会拼接到base url上。

通过 management.port 、 service-url 和 server.servlet-path 计算获得。

spring.boot.admin.client.instance.management-url

要注册的Management-url。如果URL不同也可以被覆盖(例如在使用Docker的时候)。

通过 management-base-url 和 management.context-path 计算获得。

spring.boot.admin.client.instance.service-base-url

Base url用于计算将要注册的service-url。这个路径在运行期间才会计算,并拼接到base url上。 在Cloudfoundry环境下,你可以通过 spring.boot.admin.client.instance.service-base-url=https://${vcap.application.uris[0]} 来进行切换。

通过 hostname 和 server.port 计算获得。

spring.boot.admin.client.instance.service-url

将要注册的 Service-url。如果URL不同也可以被覆盖(例如在使用Docker的时候)。

通过 service-base-url 和 server.context-path 计算获得。

spring.boot.admin.client.instance.service-path

将要注册的 Service-path。如果URL不同也可以被覆盖(例如以代码的方式设置了context-path)。

/

spring.boot.admin.client.instance.name

将要注册的实例名。

如果设置了 ${spring.application.name} 的话就使用这个,否则会使用 "spring-boot-application"

spring.boot.admin.client.instance.service-host-type

选择向服务端发送哪种host信息:
* IP: 使用 InetAddress.getHostAddress() 返回的IP
* HOST_NAME: 使用 InetAddress.getHostName() 返回的单个主机名
* CANONICAL_HOST_NAME: 使用 InetAddress.geCanonicalHostName() 返回的FQDN(Fully Qualified Domain Name:全限定域名:同时带有主机名和域名的名称。例如:主机名是bigserver,域名是mycompany.com,那么FQDN就是bigserver.mycompany.com)
如果在服务中设置了 server.address 或者是 management.address 属性,那么这个值会被覆盖掉。

CANONICAL_HOST_NAME

spring.boot.admin.client.instance.metadata.*

与该实例相关联的元数据键值对。

spring.boot.admin.client.instance.metadata.tags.*

与该实例相关联的标签键值对。

表格 2. 实例元数据可选项
Key Value 默认值

user.name
user.password

用于访问接口的权限凭证。

4. SBA服务端

4.1. 通过代理访问运行的服务端

如果Spring Boot Admin服务端是通过反向代理访问的,那么可能需要通过 (spring.boot.admin.ui.public-url) 配置一个公开的url来访问服务端。 此外,当反向代理阻断了https链接时,可能需要配置 server.forward-headers-strategy=native (同时请参考 Spring Boot 参考指南)。

4.2. 配置项

属性名 说明 默认值

spring.boot.admin.server.enabled

开启Spring Boot Admin 服务端。

true

spring.boot.admin.context-path

访问Admin服务端静态资源以及API的上下文前缀。这是相对于Dispatcher-Servlet来说的。

spring.boot.admin.monitor.status-interval

检查实例状态的时间间隔。

10,000ms

spring.boot.admin.monitor.status-lifetime

状态的生命周期。只要最后一次的状态没有过期就不会更新。

10,000ms

spring.boot.admin.monitor.info-interval

检查实例信息的时间间隔。

1m

spring.boot.admin.monitor.info-lifetime

信息的生命周期。只要最后一次的信息没有过期就不会更新。

1m

spring.boot.admin.monitor.default-timeout

请求默认的超时时间。可以使用 spring.boot.admin.monitor.timeout.* 属性配置某个特定接口的超时时间。

10,000

spring.boot.admin.monitor.timeout.*

针对某个接口id超时时间的键值对配置方式。默认情况下就是 default-timeout。

spring.boot.admin.monitor.default-retries

请求失败的默认重试次数。修改请求 (PUT, POST, PATCH, DELETE) 永远不会重试。 可以使用 spring.boot.admin.monitor.retries.* 属性覆盖某个特定接口的重试次数。

0

spring.boot.admin.monitor.retries.*

针对某个接口id重试次数的键值对配置方式。默认情况下就是 default-retries。修改请求 (PUT, POST, PATCH, DELETE) 永远不会重试。

spring.boot.admin.metadata-keys-to-sanitize

根据正则表达式匹配元数据的key,匹配到的结果在所有的json输出中会被清除。

".password$", ".*secret$", ".*key$", ".*token$", ".*credentials.", ".*vcap_services$"

spring.boot.admin.probed-endpoints

针对Spring Boot 1.x版本的客户端应用,SBA使用该选项来配置特定接口。 如果路径和id不同,可以设置为 id:path(比如 health:ping)..

"health", "env", "metrics", "httptrace:trace", "threaddump:dump", "jolokia", "info", "logfile", "refresh", "flyway", "liquibase", "heapdump", "loggers", "auditevents"

spring.boot.admin.instance-auth.enabled

开启从spring properties配置文件中读取授权信息。

true

spring.boot.admin.instance-auth.default-user-name

服务注册所使用的默认用户名。前提是 spring.boot.admin.instance-auth.enabled 属性必须设置成 true

null

spring.boot.admin.instance-auth.default-password

服务注册所使用的默认密码。前提是 spring.boot.admin.instance-auth.enabled 属性必须设置成 true

null

spring.boot.admin.instance-auth.service-map.*.user-name

某个指定名称的服务注册所使用的用户名。前提是 spring.boot.admin.instance-auth.enabled 属性必须设置成 true

spring.boot.admin.instance-auth.service-map.*.user-password

某个指定名称的服务注册所使用的密码。前提是 spring.boot.admin.instance-auth.enabled 属性必须设置成 true

spring.boot.admin.instance-proxy.ignored-headers

向客户端转发请求时忽略哪些header。

"Cookie", "Set-Cookie", "Authorization"

spring.boot.admin.ui.public-url

构建页面的时候所使用的base href。

如果是通过反向代理进行请求(用到了path重写),那么可以使用该选项来配置正确的引用地址。如果 host/port 被省略了,那么会从请求中推断出来。

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.login-icon

登录页面所显示的图标。

"assets/img/icon-spring-boot-admin.svg"

spring.boot.admin.ui.favicon

配置默认的favicon,用作图标和桌面通知图标。

"assets/img/favicon.png"

spring.boot.admin.ui.favicon-danger

配置默认的favicon,用作图标和桌面通知图标,在服务挂掉的时候显示。

"assets/img/favicon-danger.png"

spring.boot.admin.ui.remember-me-enabled

切换在登录页面是否显示记住我复选框。

true

spring.boot.admin.ui.poll-timer.cache

获取最新缓存数据的间隔(单位毫秒ms)。

2500

spring.boot.admin.ui.poll-timer.datasource

获取最新数据源数据的间隔(单位毫秒ms)。

2500

spring.boot.admin.ui.poll-timer.gc

获取最新gc数据的间隔(单位毫秒ms)。

2500

spring.boot.admin.ui.poll-timer.process

获取最新cpu数据的间隔(单位毫秒ms)。

2500

spring.boot.admin.ui.poll-timer.memory

获取最新内存数据的间隔(单位毫秒ms)。

2500

spring.boot.admin.ui.poll-timer.threads

获取最新线程数据的间隔(单位毫秒ms)。

2500

4.3. Spring Cloud 服务发现

Spring Boot Admin服务端可以使用Spring Clouds 的 DiscoveryClient 来发现服务。 其优点是客户端不必依赖 spring-boot-admin-starter-client 了。 你只需在admin服务端添加一个 DiscoveryClient 的实现 - 其它一切都会自动配置完成。

4.3.1. 使用SimpleDiscoveryClient进行静态配置

Spring Cloud提供了一个 SimpleDiscoveryClient。它允许我们通过静态配置的方式指定客户端应用:

pom.xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter</artifactId>
</dependency>
application.yml
spring:
  cloud:
    discovery:
      client:
        simple:
          instances:
            test:
              - uri: http://instance1.intern:8080
                metadata:
                  management.context-path: /actuator
              - uri: http://instance2.intern:8080
                metadata:
                  management.context-path: /actuator

4.3.2. 其它方式的服务发现客户端

Spring Boot Admin同时也支持其它Spring Cloud DiscoveryClient 的实现(比如Eureka, Zookeeper, Consul, …​)。 只需要将他们添加到Spring Boot Admin服务端并正确配置即可。 这里有一份 使用Eureka作为实现 的示例。

4.3.3. 转换服务实例

服务的注册信息中是通过 ServiceInstanceConverter 来进行转换的。Spring Boot Admin提供了一个默认转换方式,还有一个Eureka转换方式的实现。 这些都是自动配置并选择的。

你也可以通过SBA服务端配置选项,来修改应用注册时使用哪些信息以及哪些实例元数据。元数据的值会优先于服务端的配置。 如果这么多选项仍然满足不了您的需求,那么您也可以自定义一个`ServiceInstanceConverter`。
在使用Eureka的时候,healthCheckUrl`选项会被Eureka用在健康检查上, 它也可以通过 `eureka.instance.healthCheckUrl 属性配置在您的客户端上。
表格 3. 实例支持的元数据选项
Key Value 默认值

user.name
user.password

访问接口所使用的凭证。

management.scheme

服务URL中使用的scheme,用于访问actuator接口。

management.address

服务URL中使用的address,用于访问actuator接口。

management.port

服务URL中使用的port,用于访问actuator接口。

management.context-path

服务URL后添加的上下文路径,用于访问actuator接口。

${spring.boot.admin.discovery.converter.management-context-path}

health.path

服务URL后添加的路径,用于健康检查。如果配置了 EurekaServiceInstanceConverter 则会被忽略。

${spring.boot.admin.discovery.converter.health-endpoint}

表格 4. 服务发现配置可选项
属性名 说明 默认值

spring.boot.admin.discovery.enabled

开启admin服务端的DiscoveryClient支持。

true

spring.boot.admin.discovery.converter.management-context-path

当management-url被 DefaultServiceInstanceConverter 转换时,这个路径会拼接到发现服务的service-url后面。

/actuator

spring.boot.admin.discovery.converter.health-endpoint-path

当health-url被 DefaultServiceInstanceConverter 转换时,这个路径会拼接到发现服务的management-url后面。

"health"

spring.boot.admin.discovery.ignored-services

在发现服务的时候,这些服务会被忽略,不会作为服务注册到服务端。支持一些简单的表达式(比如 "foo*", "*bar", "foo*bar*")。

spring.boot.admin.discovery.services

在发现服务的时候,这些服务会被包含进来,作为服务注册到服务端。支持一些简单的表达式(比如 "foo*", "*bar", "foo*bar*")。

"*"

spring.boot.admin.discovery.ignored-instances-metadata

如果服务实例的元数据被列表匹配到至少一项,那么这个服务就会被忽略。 (例如 "discoverable=false")

spring.boot.admin.discovery.instances-metadata

如果服务实例的元数据被列表匹配到至少一项,那么这个服务就会被引入进来。 (例如 "discoverable=false")

4.3.4. CloudFoundry

如果您想将应用部署到CloudFoundry上,那么就 必须 配置 vcap.application.application_id 以及 vcap.application.instance_index 这两个选项,它们会被添加到元数据中,这样才能正确注册到Spring Boot Admin服务端。 下面是一个针对Eureka的简单配置:

application.yml
eureka:
  instance:
    hostname: ${vcap.application.uris[0]}
    nonSecurePort: 80
    metadata-map:
      applicationId: ${vcap.application.application_id}
      instanceId: ${vcap.application.instance_index}

4.4. 集群

Spring Boot Admin服务端支持通过Hazelcast的方式建立集群。当提供 HazelcastConfigHazelcastInstance Bean的时候会自动开启。 你也可以持久化Hazelcast的配置,这样在服务重启之后仍然能保持之前的状态。 同时推荐参考 Spring Boot对Hazelcast的支持

  1. 将Hazelcast添加到依赖中:

    pom.xml
    <dependency>
        <groupId>com.hazelcast</groupId>
        <artifactId>hazelcast</artifactId>
    </dependency>
  2. 初始化HazelcastConfig:

    @Bean
    public Config hazelcastConfig() {
      // This map is used to store the events.
      // It should be configured to reliably hold all the data,
      // Spring Boot Admin will compact the events, if there are too many
      MapConfig eventStoreMap = new MapConfig(DEFAULT_NAME_EVENT_STORE_MAP).setInMemoryFormat(InMemoryFormat.OBJECT)
          .setBackupCount(1)
          .setMergePolicyConfig(new MergePolicyConfig(PutIfAbsentMergePolicy.class.getName(), 100));
    
      // This map is used to deduplicate the notifications.
      // If data in this map gets lost it should not be a big issue as it will atmost
      // lead to
      // the same notification to be sent by multiple instances
      MapConfig sentNotificationsMap = new MapConfig(DEFAULT_NAME_SENT_NOTIFICATIONS_MAP)
          .setInMemoryFormat(InMemoryFormat.OBJECT).setBackupCount(1)
          .setEvictionConfig(new EvictionConfig().setEvictionPolicy(EvictionPolicy.LRU)
              .setMaxSizePolicy(MaxSizePolicy.PER_NODE))
          .setMergePolicyConfig(new MergePolicyConfig(PutIfAbsentMergePolicy.class.getName(), 100));
    
      Config config = new Config();
      config.addMapConfig(eventStoreMap);
      config.addMapConfig(sentNotificationsMap);
      config.setProperty("hazelcast.jmx", "true");
    
      // WARNING: This setups a local cluster, you change it to fit your needs.
      config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(false);
      TcpIpConfig tcpIpConfig = config.getNetworkConfig().getJoin().getTcpIpConfig();
      tcpIpConfig.setEnabled(true);
      tcpIpConfig.setMembers(singletonList("127.0.0.1"));
      return config;
    }
表格 5. Hazelcast配置可选项
属性名 说明 默认值

spring.boot.admin.hazelcast.enabled

开启对Hazelcast的支持

true

spring.boot.admin.hazelcast.event-store

对Hazelcast-map事件的存储名称

"spring-boot-admin-event-store"

spring.boot.admin.hazelcast.sent-notifications

用于清除Hazelcast-map对应名称的重复通知

"spring-boot-admin-sent-notifications"

4.5. 消息通知

4.5.1. 邮件通知

邮件通知是以HTML格式渲染的电子邮件,它使用 Thymeleaf 作为模板。 要想开启邮件通知,需要使用 spring-boot-starter-mail 配置 JavaMailSender 并设置一个收件人。

Sample Mail Notification
图片 1. 邮件通知的例子
为了防止敏感信息被泄露,默认邮件模板中不显示任何实例的元数据。如果你想显示的话,可以自定义模板。
  1. 将spring-boot-starter-mail添加到依赖中:

    pom.xml
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
  2. 配置一个JavaMailSender

    application.properties
    spring.mail.host=smtp.example.com
    spring.boot.admin.notify.mail.to=admin@example.com
  3. 根据下面的可选项配置邮件

    表格 6. 邮件提醒配置的可选项
    属性名 说明 面若防治

    spring.boot.admin.notify.mail.enabled

    开启邮件提醒

    true

    spring.boot.admin.notify.mail.ignore-changes

    要忽略的状态变化,使用逗号分割。格式是: "<from-status>:<to-status>"。允许使用通配符

    "UNKNOWN:UP"

    spring.boot.admin.notify.mail.template

    用于渲染的Thymeleaf模板路径

    "classpath:/META-INF/spring-boot-admin-server/mail/status-changed.html"

    spring.boot.admin.notify.mail.to

    邮件收件人列表,用逗号进行分割

    "root@localhost"

    spring.boot.admin.notify.mail.cc

    副本收件人列表,用逗号分割

    spring.boot.admin.notify.mail.from

    邮件发送人

    "Spring Boot Admin <noreply@localhost>"

    spring.boot.admin.notify.mail.additional-properties

    可以从模板读取的其它属性

4.5.2. PagerDuty通知

To enable PagerDuty notifications you just have to add a generic service to your PagerDuty-account and set spring.boot.admin.notify.pagerduty.service-key to the service-key you received.

表格 7. PagerDuty notifications configuration options
Property name Description Default value

spring.boot.admin.notify.pagerduty.enabled

Enable mail notifications

true

spring.boot.admin.notify.pagerduty.ignore-changes

Comma-delimited list of status changes to be ignored. Format: "<from-status>:<to-status>". Wildcards allowed.

"UNKNOWN:UP"

spring.boot.admin.notify.pagerduty.service-key

Service-key to use for PagerDuty

spring.boot.admin.notify.pagerduty.url

The Pagerduty-rest-api url

"https://events.pagerduty.com/generic/2010-04-15/create_event.json"

spring.boot.admin.notify.pagerduty.description

Description to use in the event. SpEL-expressions are supported

"#{instance.registration.name}/#{instance.id} is #{instance.statusInfo.status}"

spring.boot.admin.notify.pagerduty.client

Client-name to use in the event

spring.boot.admin.notify.pagerduty.client-url

Client-url to use in the event

4.5.3. OpsGenie通知

To enable OpsGenie notifications you just have to add a new JSON Rest API integration to your OpsGenie account and set spring.boot.admin.notify.opsgenie.api-key to the apiKey you received.

表格 8. OpsGenie notifications configuration options
Property name Description Default value

spring.boot.admin.notify.opsgenie.enabled

Enable OpsGenie notifications

true

spring.boot.admin.notify.opsgenie.ignore-changes

Comma-delimited list of status changes to be ignored. Format: "<from-status>:<to-status>". Wildcards allowed.

"UNKNOWN:UP"

spring.boot.admin.notify.opsgenie.api-key

apiKey you received when creating the integration

spring.boot.admin.notify.opsgenie.url

OpsGenie Alert API url

"https://api.opsgenie.com/v2/alerts"

spring.boot.admin.notify.opsgenie.description

Description to use in the event. SpEL-expressions are supported

"#{instance.registration.name}/#{instance.id} is #{instance.statusInfo.status}"

spring.boot.admin.notify.opsgenie.actions

Comma separated list of actions that can be executed.

spring.boot.admin.notify.opsgenie.source

Field to specify source of alert. By default, it will be assigned to IP address of incoming request.

spring.boot.admin.notify.opsgenie.tags

Comma separated list of labels attached to the alert.

spring.boot.admin.notify.opsgenie.entity

The entity the alert is related to.

spring.boot.admin.notify.opsgenie.user

Default owner of the execution. If user is not specified, the system becomes owner of the execution.

4.5.4. Hipchat通知

To enable Hipchat notifications you need to create an API token on your Hipchat account and set the appropriate configuration properties.

表格 9. Hipchat notifications configuration options
Property name Description Default value

spring.boot.admin.notify.hipchat.enabled

Enable Hipchat notifications

true

spring.boot.admin.notify.hipchat.ignore-changes

Comma-delimited list of status changes to be ignored. Format: "<from-status>:<to-status>". Wildcards allowed.

"UNKNOWN:UP"

spring.boot.admin.notify.hipchat.url

The HipChat REST API (V2) URL

spring.boot.admin.notify.hipchat.auth-token

The API token with access to the notification room

spring.boot.admin.notify.hipchat.room-id

The ID or url-encoded name of the room to send notifications to

spring.boot.admin.notify.hipchat.notify

Whether the message should trigger a user notification

false

spring.boot.admin.notify.hipchat.description

Description to use in the event. SpEL-expressions are supported

"<strong>#{instance.registration.name}</strong>/#{instance.id} is <strong>#{event.statusInfo.status}</strong>"

4.5.5. Slack通知

To enable Slack notifications you need to add a incoming Webhook under custom integrations on your Slack account and configure it appropriately.

表格 10. Slack notifications configuration options
Property name Description Default value

spring.boot.admin.notify.slack.enabled

Enable Slack notifications

true

spring.boot.admin.notify.slack.ignore-changes

Comma-delimited list of status changes to be ignored. Format: "<from-status>:<to-status>". Wildcards allowed.

"UNKNOWN:UP"

spring.boot.admin.notify.slack.webhook-url

The Slack Webhook URL to send notifications to.

spring.boot.admin.notify.slack.channel

Optional channel name (without # at the beginning). If different than channel in Slack Webhooks settings

spring.boot.admin.notify.slack.icon

Optional icon name (without surrounding colons). If different than icon in Slack Webhooks settings

spring.boot.admin.notify.slack.username

Optional username to send notification if different than in Slack Webhooks settings

Spring Boot Admin

spring.boot.admin.notify.slack.message

Message to use in the event. SpEL-expressions and Slack markups are supported

"*#{instance.registration.name}* (#{instance.id}) is *#{event.statusInfo.status}*"

4.5.6. Let’s Chat通知

To enable Let’s Chat notifications you need to add the host url and add the API token and username from Let’s Chat

表格 11. Let’s Chat notifications configuration options
Property name Description Default value

spring.boot.admin.notify.letschat.enabled

Enable let´s Chat notifications

true

spring.boot.admin.notify.letschat.ignore-changes

Comma-delimited list of status changes to be ignored. Format: "<from-status>:<to-status>". Wildcards allowed.

"UNKNOWN:UP"

spring.boot.admin.notify.letschat.url

The let´s Chat Host URL to send notifications

spring.boot.admin.notify.letschat.room

the room where to send the messages

spring.boot.admin.notify.letschat.token

the token to access the let´s Chat API

spring.boot.admin.notify.letschat.username

The username for which the token was created

Spring Boot Admin

spring.boot.admin.notify.letschat.message

Message to use in the event. SpEL-expressions are supported

"*#{instance.registration.name}* (#{instance.id}) is *#{event.statusInfo.status}*"

4.5.7. Microsoft Teams通知

To enable Microsoft Teams notifications you need to setup a connector webhook url and set the appropriate configuration property.

表格 12. Microsoft Teams notifications configuration options
Property name Description Default value

spring.boot.admin.notify.ms-teams.enabled

Enable Microsoft Teams notifications

true

spring.boot.admin.notify.ms-teams.webhook-url

The Microsoft Teams webhook url to send the notifications to.

spring.boot.admin.notify.ms-teams.deRegisteredTitle

Title of the Teams message when an app de-registers.

De-Registered

spring.boot.admin.notify.ms-teams.registeredTitle

Title of the Teams message when an app dregisters.

Registered

spring.boot.admin.notify.ms-teams.statusChangedTitle

Title of the Teams message when an app changes status.

Status Changed

spring.boot.admin.notify.ms-teams.messageSummary

Summary section of every Teams message originating from Spring Boot Admin.

Spring Boot Admin Notification

spring.boot.admin.notify.ms-teams.theme_color

Set the theme color. SpEL-expressions are supported.

#{event.type == 'STATUS_CHANGED' ? (event.statusInfo.status=='UP' ? '6db33f' : 'b32d36') : '439fe0'}

spring.boot.admin.notify.ms-teams.deregister_activity_subtitle

Subtitle of the Activity section of the Teams message when an app de-registers. SpEL-expressions are supported.

#{instance.registration.name} with id #{instance.id} has de-registered from Spring Boot Admin

spring.boot.admin.notify.ms-teams.register_activity_subtitle

Subtitle of the Activity section of the Teams message when an app registers. SpEL-expressions are supported.

#{instance.registration.name} with id #{instance.id} has registered with Spring Boot Admin

spring.boot.admin.notify.ms-teams.status_activity_subtitle

Subtitle of the Activity section of the Teams message when an app changes status. SpEL-expressions are supported.

#{instance.registration.name} with id #{instance.id} changed status from #{lastStatus} to #{event.statusInfo.status}

4.5.8. Telegram通知

To enable Telegram notifications you need to create and authorize a telegram bot and set the appropriate configuration properties for auth-token and chat-id.

表格 13. Telegram notifications configuration options
Property name Description Default value

spring.boot.admin.notify.telegram.enabled

Enable Telegram notifications

true

spring.boot.admin.notify.telegram.auth-token

The token identifying und authorizing your Telegram bot (e.g. 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11).

spring.boot.admin.notify.telegram.chat-id

Unique identifier for the target chat or username of the target channel

spring.boot.admin.notify.telegram.disable-notify

If true users will receive a notification with no sound.

false

spring.boot.admin.notify.telegram.parse_mode

The parsing mode for the sent message. Currently `HTML' and 'Markdown' are supported.

'HTML'

spring.boot.admin.notify.telegram.message

Text to send. SpEL-expressions are supported.

"<strong>#{instance.registration.name}</strong>/#{instance.id} is <strong>#{event.statusInfo.status}</strong>"

4.5.9. Discord通知

To enable Discord notifications you need to create a webhook and set the appropriate configuration property.

表格 14. Discord notifications configuration options
Property name Description Default value

spring.boot.admin.notify.discord.enabled

Enable Discord notifications

true

spring.boot.admin.notify.discord.webhook-url

The Discord webhook url to send the notifications to.

spring.boot.admin.notify.discord.username

Optional username.

Default set in Discord

spring.boot.admin.notify.discord.avatar-url

Optional URL to avatar.

Default set in Discord

spring.boot.admin.notify.discord.tts

If the message is a text to speech message.

false

spring.boot.admin.notify.discord.message

Text to send. SpEL-expressions are supported.

"*#{instance.registration.name}* (#{instance.id}) is *#{event.statusInfo.status}*"

4.5.10. 为消息通知配置代理

所有的消息通知都是使用 RestTemplate 来进行发送的,所以我们可以为其配置一个代理。

表格 15. 通知代理的可选配置
属性名 说明 默认值

spring.boot.admin.notify.proxy.host

代理的 host

spring.boot.admin.notify.proxy.port

代理的 port

spring.boot.admin.notify.proxy.username

代理的 username (如果代理需要身份认证的话)

spring.boot.admin.notify.proxy.password

代理的 password (如果代理需要身份认证的话)

4.5.11. 通知发送程序

RemindingNotifier 会在应用停机/离线的时候发送消息通知,它会将通知的发送委托给另外一个通知发送程序。

默认情况下,这个通知发送程序会在一个已注册发生 停机离线 的时候触发。 你也可以通过 setReminderStatuses() 来修改这个行为。 当这个状态变成了无需触发,或者是相关服务注销了的话,这个通知发送程序就会结束。

默认情况下,通知发送程序每隔10分钟发送一次,可以使用 setReminderPeriod() 对这个间隔进行修改。 RemindingNotifier 本身不会开启后台线程来调用通知发送程序,你需要按照下面的示例来处理这个问题;

如何配置通知发送程序
@Configuration
public class NotifierConfiguration {
    @Autowired
    private Notifier notifier;

    @Primary
    @Bean(initMethod = "start", destroyMethod = "stop")
    public RemindingNotifier remindingNotifier() {
        RemindingNotifier notifier = new RemindingNotifier(notifier, repository);
        notifier.setReminderPeriod(Duration.ofMinutes(10)); (1)
        notifier.setCheckReminderInverval(Duration.ofSeconds(10)); (2)
        return notifier;
    }
}
1 通知发送程序会每隔10分钟发送一次。
2 每隔10秒种安排一次通知发送。

4.5.12. 过滤通知

FilteringNotifier 允许在运行时添加/删除消息通知过滤的规则。 它会将通知的发送委托给另一个发送程序。

如果向 ApplicationContext 添加了 FilteringNotifier,那么RESTful页面中的 消息通知/过滤器 就可以访问了。

尤其时在部署应用的时候,如果你不想接受提醒,此时过滤器就能帮到你。 在停止应用之前你可以通过 POST 请求发送一个(带有过期时间的)过滤条件。

如何配置过滤器
@Configuration(proxyBeanMethods = false)
public class NotifierConfig {

  private final InstanceRepository repository;

  private final ObjectProvider<List<Notifier>> otherNotifiers;

  public NotifierConfig(InstanceRepository repository, ObjectProvider<List<Notifier>> otherNotifiers) {
    this.repository = repository;
    this.otherNotifiers = otherNotifiers;
  }

  @Bean
  public FilteringNotifier filteringNotifier() { (1)
    CompositeNotifier delegate = new CompositeNotifier(this.otherNotifiers.getIfAvailable(Collections::emptyList));
    return new FilteringNotifier(delegate, this.repository);
  }

  @Primary
  @Bean(initMethod = "start", destroyMethod = "stop")
  public RemindingNotifier remindingNotifier() { (2)
    RemindingNotifier notifier = new RemindingNotifier(filteringNotifier(), this.repository);
    notifier.setReminderPeriod(Duration.ofMinutes(10));
    notifier.setCheckReminderInverval(Duration.ofSeconds(10));
    return notifier;
  }

}
1 使用delegate添加一个 FilteringNotifier Bean (例如在配置 MailNotifier 时)
2 使用 FilteringNotifier 作为delegate,将 RemindingNotifier 添加为primary bean。
这个示例结合了消息提醒和通知过滤。 这可以让你在部署应用后的一段时间内(直到过滤条件过期)不会收到消息通知。

4.5.13. 钉钉通知

要想启用 DingTalk 消息通知,你需要创建并配置钉钉机器人的授权,并为 webhookUrl 和 secret 提供正确的配置。

表格 16. 钉钉消息通知配置可选项
属性名 说明 默认值

spring.boot.admin.notify.dingtalk.enabled

开启钉钉消息通知。

true

spring.boot.admin.notify.dingtalk.webhook-url

钉钉通知将要发送的webhook url。

spring.boot.admin.notify.dingtalk.secret

消息认证的secret。

spring.boot.admin.notify.dingtalk.message

发送的文本,支持SpEL表达式。

"#{instance.registration.name} #{instance.id} is #{event.statusInfo.status} "

5. 安全

5.1. 保护SBA服务端的安全

由于在分布式web应用中,有好几种可以解决身份认证和授权的方法,所以Spring Boot Admin没有默认为您选择它们中的哪一个。 默认情况下可以使用 spring-boot-admin-server-ui 来提供一个登录页面和注销按钮。

下面是一个针对Spring的安全配置示例:

@Configuration(proxyBeanMethods = false)
public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {

  private final AdminServerProperties adminServer;

  private final SecurityProperties security;

  public SecuritySecureConfig(AdminServerProperties adminServer, SecurityProperties security) {
    this.adminServer = adminServer;
    this.security = security;
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
    successHandler.setTargetUrlParameter("redirectTo");
    successHandler.setDefaultTargetUrl(this.adminServer.path("/"));

    http.authorizeRequests(
        (authorizeRequests) -> authorizeRequests.antMatchers(this.adminServer.path("/assets/**")).permitAll() (1)
            .antMatchers(this.adminServer.path("/actuator/info")).permitAll()
            .antMatchers(this.adminServer.path("/actuator/health")).permitAll()
            .antMatchers(this.adminServer.path("/login")).permitAll().anyRequest().authenticated() (2)
    ).formLogin(
        (formLogin) -> formLogin.loginPage(this.adminServer.path("/login")).successHandler(successHandler).and() (3)
    ).logout((logout) -> logout.logoutUrl(this.adminServer.path("/logout"))).httpBasic(Customizer.withDefaults()) (4)
        .csrf((csrf) -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) (5)
            .ignoringRequestMatchers(
                new AntPathRequestMatcher(this.adminServer.path("/instances"),
                    HttpMethod.POST.toString()), (6)
                new AntPathRequestMatcher(this.adminServer.path("/instances/*"),
                    HttpMethod.DELETE.toString()), (6)
                new AntPathRequestMatcher(this.adminServer.path("/actuator/**")) (7)
            ))
        .rememberMe((rememberMe) -> rememberMe.key(UUID.randomUUID().toString()).tokenValiditySeconds(1209600));
  }

  // Required to provide UserDetailsService for "remember functionality"
  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication().withUser(security.getUser().getName())
        .password("{noop}" + security.getUser().getPassword()).roles("USER");
  }

}
1 对所有静态资源和登录页面进行放行处理。
2 其它所有请求都必须经过身份认证。
3 配置登录和注销逻辑。
4 开启HTTP-Basic认证。这是Spring Boot Admin客户端所需的。
5 启用Cookie的CSRF保护
6 禁用Spring Boot Admin客户端对于注册(注销)请求的CSRF保护
7 禁用Spring Boot Admin客户端对于actuator接口的CSRF保护

如果使用Spring Boot Admin客户端,它还需要添加访问服务端的凭证:

application.yml
spring.boot.admin.client:
   username: sba-client
   password: s3cret

有关完整的示例,请查看 spring-boot-admin-sample-servlet

如果你想要保护 /instances 接口,那么不要忘了在SBA客户端使用 spring.boot.admin.client.usernamespring.boot.admin.client.password 配置用户名和密码。

5.2. 保护客户端默认Actuator接口

当actuator默认接口使用HTTP Basic身份认证进行安全保护时候,SBA就需要凭证才能访问它们了。 你可以在注册应用的时候在元数据中提交这个凭证。 之后 BasicAuthHttpHeaderProvider 就会使用元数据中提供的信息,在header中添加 Authorization 然后访问客户端应用的actuator接口了。 你也可以自定义一个 HttpHeadersProvider 来改变这个默认的行为(例如添加一些加密揭秘的逻辑)或者是在header中添加额外信息。

SBA服务端会屏蔽元数据中的一些信息,以防止敏感信息的泄漏。
在元数据提交身份凭证时,应该为SBA服务端(或者是服务发现)配置HTTPS。
使用Spring Cloud服务发现的时候,你必须随时注意,任何可以查询服务注册的人都可以看到你的认证信息。
使用这种方法SBA服务端就可以决定用户能否访问已注册的应用。 还有更加复杂的解决方案(使用OAuth2)来让客户端决定用户能否访问接口。 关于这一点,请参考 joshiste/spring-boot-admin-samples

5.2.1. SBA客户端

application.yml
spring.boot.admin.client:
    url: http://localhost:8080
    instance:
      metadata:
        user.name: ${spring.security.user.name}
        user.password: ${spring.security.user.password}

5.2.2. SBA服务端

你可以通过admin服务端的配置文件来指定凭证。

你可以将它与 spring-cloud-kubernetes 结合起来一起使用,这样就能从 secrets 中读取凭证了。

要想从配置文件读取凭证,需要将 spring.boot.admin.instance-auth.enabled 设置为 true (默认情况就是这样)。

如果客户端通过元数据提供了凭证(例如通过服务注解),那么元数据将会替换配置文件中的配置。

你可以通过使用 spring.boot.admin.instance-auth.default-user-namespring.boot.admin.instance-auth.default-user-password 来提供默认的用户名和密码。 你也可以选择使用 spring.boot.admin.instance-auth.service-map.*.user-name 为指定名称的服务提供凭证,记得将 * 替换为服务名。

application.yml
spring.boot.admin:
  instance-auth:
    enabled: true
    default-user-name: "${some.user.name.from.secret}"
    default-password: "${some.user.password.from.secret}"
    service-map:
      my-first-service-to-monitor:
        user-name: "${some.user.name.from.secret}"
        user-password: "${some.user.password.from.secret}"
      my-second-service-to-monitor:
        user-name: "${some.user.name.from.secret}"
        user-password: "${some.user.password.from.secret}"

5.2.3. Eureka

application.yml
eureka:
  instance:
    metadata-map:
      user.name: ${spring.security.user.name}
      user.password: ${spring.security.user.password}

5.2.4. Consul

application.yml
spring.cloud.consul:
  discovery:
    metadata:
        user-name: ${spring.security.user.name}
        user-password: ${spring.security.user.password}
Consul在元数据不允许使用点 (".") 作为key,应该使用减号(横杠)代理。

5.2.5. 默认Actuator接口的CSRF保护

一些actuator接口 (例如 /loggers) 是支持POST请求的。 在使用Spring Security时需要禁用这些actuator接口的CSRF保护,因为Spring Boot Admin服务端目前缺乏对这方面的支持。

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf()
        .ignoringAntMatchers("/actuator/**");
}

5.3. 使用自定义TLS

SBA还可以在访问actuator接口的时候使用客户端证书进行身份认证。 在提供了 ClientHttpConnector bean时,Spring Boot就会用它自动配置 WebClient.Builder,之后供Spring Boot Admin使用。

@Bean
public ClientHttpConnector customHttpClient() {
    SslContextBuilder sslContext = SslContextBuilder.forClient();
    //Your sslContext customizations go here
    HttpClient httpClient = HttpClient.create().secure(
        ssl -> ssl.sslContext(sslContext)
    );
    return new ReactorClientHttpConnector(httpClient);
}

6. 自定义

6.1. 自定义通知器

你可以实现 Notifier 接口,以Spring Beans的形式添加自己的通知程序,当然最好是继承 AbstractEventNotifierAbstractStatusChangeNotifier 的方式。

public class CustomNotifier extends AbstractEventNotifier {

  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());
      }
      else {
        LOGGER.info("Instance {} ({}) {}", instance.getRegistration().getName(), event.getInstance(),
            event.getType());
      }
    });
  }

}

6.2. 自定义HTTP请求头

为了监控应用而发送的actuator接口,如果你需要在其中添加自定义HTTP请求头的话,可以使用 HttpHeadersProvider 来轻松的实现:

@Bean
public HttpHeadersProvider customHttpHeadersProvider() {
  return (instance) -> {
    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.add("X-CUSTOM", "My Custom Value");
    return httpHeaders;
  };
}

6.3. 对请求和响应进行拦截

为了监控应用而发送的actuator接口,如果你需要拦截并修改其请求以及响应的话,可以通过实现 InstanceExchangeFilterFunction 来完成。 这对审核或者是添加额外的安全检查很有作用。

@Bean
public InstanceExchangeFilterFunction auditLog() {
  return (instance, request, next) -> next.exchange(request).doOnSubscribe((s) -> {
    if (HttpMethod.DELETE.equals(request.method()) || HttpMethod.POST.equals(request.method())) {
      log.info("{} for {} on {}", request.method(), instance.getId(), request.url());
    }
  });
}

6.4. 链接/嵌入外部页面

你可以非常简单的通过配置添加一个外部页面的链接甚至是直接将他们嵌入进来 (添加 iframe=true 参数)。

spring:
  boot:
    admin:
      ui:
        external-views:
          - label: "🚀"
            url: http://codecentric.de
            order: 2000

6.5. 自定义页面

您也可以向前端添加自定义页面。页面必须是一个 Vue.js 组件。

js文件还有css样式表必须放在classpath下的 /META-INF/spring-boot-admin-server-ui/extensions/{name}/ 路径,这样服务端才能拿到它们。 spring-boot-admin-sample-custom-ui 模块中包含了一个示例,该示例展示了如何配置maven来成功的构建一个模块。

要想自定义拓展将自己注册,可以调用 SBA.use() 然后还需要暴露 install() 函数,这在配置路由参数的时候会被ui调用。 install() 函数在注册页面和/或是回调时接收以下参数:

如果前端添加了顶级路由,那么后端也必须知道。 可以在 /META-INF/spring-boot-admin-server-ui/extensions/{name}/routes.txt 文件配置所有的顶级路由,每个路由占一行。

6.5.1. 添加顶级页面

下面是一个简单的顶级页面示例,其中列表出所有已注册的应用:

<template>
  <pre v-text="stringify(applications, null, 4)" />
</template>

<script>
export default {
  props: {
    applications: { (1)
      type: Array,
      required: true
    }
  },
  methods: {
    stringify: JSON.stringify
  }
};
</script>
1 如果你在组件中定义了 applications 属性,组件会将所有已注册的应用注入进来。
应用中还提供了一些很有用的方法和可用的实例对象。可以参考 application.js 以及 instance.js

这里展示了如何注册顶级试图。

SBA.use({
  install({viewRegistry}) {
    viewRegistry.addView({
      name: 'custom',  (1)
      path: '/custom', (2)
      component: custom, (3)
      label: 'Custom', (4)
      order: 1000, (5)
    });
  }
});
1 试图以及路由名称
2 试图的访问路径
3 引用的自定义组件,将会在路由上渲染
4 在顶部导航栏显示自定义试图的label
5 对试图进行排序。顶部导航栏中的试图是按照升序进行排序的。

添加了路由的 routes.txt 文件:

/custom/**

6.5.2. 查看自定义接口

下面是调用自定义接口的试图:

<template>
  <div class="custom">
    <p>Instance: <span v-text="instance.id" /></p>
    <p>Output: <span v-text="text" /></p>
  </div>
</template>

<script>
  export default {
    props: {
      instance: { (1)
        type: Object,
        required: true
      }
    },
    data: () => ({
      text: ''
    }),
    async created() {
      const response = await this.instance.axios.get('actuator/custom'); (2)
      this.text = response.data;
    }
  };
</script>

<style>
  .custom {
    font-size: 20px;
    width: 80%;
  }
</style>
1 如果你在组件中定义了 instance 属性,组件会将需要渲染的对象注入进来。
2 所有的实例中都提前配置好了 axios 供您访问,您只需要输入正确的路径和请求头就好了。

注册实例的工作方式与顶级试图差不多,但有一些额外的附加属性:

SBA.use({
  install({viewRegistry, vueI18n}) {
    viewRegistry.addView({
      name: 'instances/custom',
      parent: 'instances', (1)
      path: 'custom',
      component: customEndpoint,
      label: 'Custom',
      group: 'custom', (2)
      order: 1000,
      isEnabled: ({instance}) => instance.hasEndpoint('custom') (3)
    });

    vueI18n.mergeLocaleMessage('en', { (4)
      sidebar: {
        custom : {
          title : "My Custom Extensions"
        }
      }
    });
  }
});
1 这里的parent必须是 'instances' ,这样才能为单例提供新的自定义试图。
2 可以对试图进行分组。
3 如果添加了 isEnabled 选项,则可以动态判断是否为特定实例显示试图。
4 注册自定义i18n翻译
你可以以同分组、同名试图的方式对默认试图进行覆盖。

6.6. 自定义顶部Logo和标题

你可以使用下列属性对标题中的信息(例如显示登录信息或者是公司名称)进行自定义:

  • spring.boot.admin.ui.brand: 这段HTML会渲染到导航标题中,默认是 <img src="assets/img/icon-spring-boot-admin.svg"><span>Spring Boot Admin</span>。 默认情况下这里会显示SBA的logo,后面加上名称。 你可以在 /META-INF/spring-boot-admin-server-ui/ 这个路径(SBA默认会从这个路径下注册 ResourceHandler )下添加图片,或者用其它方式确保正确的提供图片(比如手动注册 ResourceHandler )。

  • spring.boot.admin.ui.title: 使用这个选项可以自定义浏览器窗口标题。

你可以自定义登录页面的图片。

  1. 将图片放在http可以访问到的资源目录下(例如 /META-INF/spring-boot-admin-server-ui/assets/img/)。

  2. 使用下面的属性来配置要使用的图标:

    • spring.boot.admin.ui.login-icon: 用作登录页面上的图标(例 assets/img/custom-login-icon.svg)。

6.8. 自定义Favicon

可以使用自定义的favicon,它也会用在桌面通知上。 当有一个或多个应用关闭时,Spring Boot Admin会使用不同的图标。

  1. 将favicon图标(.png 格式,最低192x192像素)放在http可以访问到的资源目录下(例如 /META-INF/spring-boot-admin-server-ui/assets/img/)。

  2. 下面的属性可以配置要使用的图标:

    • spring.boot.admin.ui.favicon: 配置默认图标(例 assets/img/custom-favicon.png) 。

    • spring.boot.admin.ui.favicon-danger: 在一个或多个服务关闭时使用这个图标 (例 assets/img/custom-favicon-danger.png)。

6.9. 自定义可用语言

要想筛选所有支持的语言,可以使用下面的选项:

  • spring.boot.admin.ui.available-languages: 配置现有语言的过滤器 (例如 en,de out of existing de,en,fr,ko,pt-BR,ru,zh)。

6.10. 显示/隐藏页面

要想在导航栏中隐藏试图,可以很简单的实现:

spring:
  boot:
    admin:
      ui:
        view-settings:
          - name: "journal"
            enabled: false

7. 监听1.5.x版本的Spring Boot

使用 Spring Boot Admin 2.x 也可以监控 Spring Boot 1.5.x 版本的应用。 旧版本的Spring Boot Admin客户端可以注册到新版本的服务端上。 由于API有一些细微的变化,你可以在旧版本的客户端上添加下面的配置:

  1. 为 Spring Boot Admin 客户端1.5.x版本重新配置api路径:

    application.yml
    spring.boot.admin.api-path: instances

由于Spring Boot 2版本中,一些actuator接口发生了变化,并非所有选项都可用(比如 /metrics 接口); 对于这些接口,我们也提供了遗留接口的转换器。

8. 2.x版本的变化

  • Added stable automatic-module-name to all jars

8.1. 页面

  • 使用vue.js重写了ui页面

  • 将登录页面模块集成到主模块中

  • 删除了活动模块,因为没什么人使用它

  • 移除了Hystrix-Dashboard的集成(可能会改变)

  • 添加了session接口

  • 添加了元数据(屏蔽之后)的显示

  • 添加了重置日志级别的选项

  • 添加了 wallboard 试图

8.2. 后端

  • 将所有的类都移动到了 spring.boot.admin.server 包下

  • 与Spring cloud相关的拓展移动到了 spring-boot-admin-server-cloud

  • 使用event sourcing 原则对后端重新进行了设计

  • 添加了应用的概念(有1到n个实例组成)

  • 将检测接口移动到后端,通过 /actuator 地址发送OPTIONS请求进行索引或者是查看

  • 使用WebClient自定义代理代替Zuul

  • 移除spring-cloud-starter依赖

  • 添加了 CompositeHttpHeadersProvider 来适配同时有多个 HttpHeadersProviders 的情况

  • 添加了 InstanceExchangeFilterFunctions ,它允许对向被监控的实例所发出的请求进行拦截/修改

  • 添加了CloudFoundry开箱即用的支持

  • 添加了使用 LegacyEndpointConverters 对 Spring Boot 1.5.x 版本actuator接口的支持

  • 更新 OpsGenieNotifier 的api到v2版本

  • 使用Thymeleaf模板重写了 MailNotifier

8.3. 客户端

  • 将所有的配置移动到 spring.boot.admin.client. 以及 spring.boot.admin.client.instance.

  • 将所有源码移动到 spring.boot.admin.client 包下

  • 添加了对webflux应用的支持

  • 添加了CloudFoundry开箱即用的支持

9. 常见问题

我可以在我的业务系统应用中添加spring-boot-admin吗?

tl;dr 可以,但是不应该这么做。
你可以设置 spring.boot.admin.context-path 改变UI以及REST-API的访问路径,但是基于应用的业务复杂度,你还是有可能遇到一些问题。 另一方面,在我看来一个应用自己监控自己是没有意义的。如果你的应用挂掉了,那么监控它的工具也就同时挂掉了。