spring-boot-admin基础搭建教程

spring-boot-admin为我们基于spring-boot的基础数据安全端口提供了基础的可视化监控功能。还可以通过spring-boot-admin的server程序对spring-boot程序提供简单的实时管理(例如修改日志输出级别)。
通过官方的英文指导文档和网上一些技术博客,可以很方便的学习spring-boot-admin的集成。根据个人的学习过程简单整理了一下,希望对想要学习的童鞋有所帮助。

个人习惯,搭建demo的过程中采用了maven来构建,在父pom中统一配置spring-boot、spring-cloud以及spring-boot-admin相关组件的版本,所以在子模块中,引入依赖时不会显示指明版本。
以下是父pom中的的主要配置

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.8.RELEASE</version>
    <relativePath/>
</parent>
<properties>
    <java.version>1.8</java.version>
    <admin.version>1.5.4</admin.version>
</properties>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Dalston.SR4</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
            <version>${admin.version}</version>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-server</artifactId>
            <version>${admin.version}</version>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-server-ui</artifactId>
            <version>${admin.version}</version>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-server-ui-hystrix</artifactId>
            <version>${admin.version}</version>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-server-ui-turbine</artifactId>
            <version>${admin.version}</version>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-server-ui-login</artifactId>
            <version>${admin.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

一、spring-boot + spring-boot-admin 集成基础

1.1、利用spring-boot-starter-actuator创建安全端点

添加maven依赖

首先,我们创建一个admin-client作为spring-boot-admin的客户端程序。该程序依赖如下两个依赖

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

application.properties文件配置

我们设置内嵌tomcat监听端口为8090

spring.application.name=admin-client
server.port=8090
#关闭安全控制
management.security.enabled=false

启动类配置

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

测试效果

直接启动main方法,可以看到日志中有如下几行记录,里面有spring-boot-starter-actuator为我们暴露的信息

2017-10-22 16:59:22.572  INFO 341860 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/loggers/{name:.*}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.LoggersMvcEndpoint.get(java.lang.String)
2017-10-22 16:59:22.573  INFO 341860 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/loggers/{name:.*}],methods=[POST],consumes=[application/vnd.spring-boot.actuator.v1+json || application/json],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.LoggersMvcEndpoint.set(java.lang.String,java.util.Map<java.lang.String, java.lang.String>)
2017-10-22 16:59:22.573  INFO 341860 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/loggers || /loggers.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2017-10-22 16:59:22.579  INFO 341860 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/health || /health.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.invoke(javax.servlet.http.HttpServletRequest,java.security.Principal)
2017-10-22 16:59:22.581  INFO 341860 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/mappings || /mappings.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2017-10-22 16:59:22.583  INFO 341860 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/info || /info.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2017-10-22 16:59:22.584  INFO 341860 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/autoconfig || /autoconfig.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2017-10-22 16:59:22.586  INFO 341860 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/heapdump || /heapdump.json],methods=[GET],produces=[application/octet-stream]}" onto public void org.springframework.boot.actuate.endpoint.mvc.HeapdumpMvcEndpoint.invoke(boolean,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.io.IOException,javax.servlet.ServletException
2017-10-22 16:59:22.587  INFO 341860 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/configprops || /configprops.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2017-10-22 16:59:22.591  INFO 341860 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/beans || /beans.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2017-10-22 16:59:22.598  INFO 341860 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/trace || /trace.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2017-10-22 16:59:22.600  INFO 341860 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/dump || /dump.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2017-10-22 16:59:22.601  INFO 341860 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/metrics/{name:.*}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint.value(java.lang.String)
2017-10-22 16:59:22.602  INFO 341860 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/metrics || /metrics.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2017-10-22 16:59:22.605  INFO 341860 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/auditevents || /auditevents.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public org.springframework.http.ResponseEntity<?> org.springframework.boot.actuate.endpoint.mvc.AuditEventsMvcEndpoint.findByPrincipalAndAfterAndType(java.lang.String,java.util.Date,java.lang.String)
2017-10-22 16:59:22.606  INFO 341860 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/env/{name:.*}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint.value(java.lang.String)
2017-10-22 16:59:22.607  INFO 341860 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/env || /env.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()

我们简单访问health端点地址:http://127.0.0.1:8090/health,可以得到如下程序健康信息结果

{"status":"UP","diskSpace":{"status":"UP","total":104857595904,"free":55882469376,"threshold":10485760}}

由于端点众多且与其他框架例如spring-cloud集成时还会增加其他端点,非常不方便记忆核操作。同时直接访问的时候返回的数据都是JSON格式的字符串,查看不太直观。所以这就有了spring-boot-admin,它可以为我们提供这些端点比较直观的UI界面效果,方便我们的运营、运维、技术等人员使用。

1.2、创建spring-boot-admin服务端程序admin-server

我们创建admin-server作为spring-boot-admin的server端程序,为该程序添加jar包依赖,该依赖包括自动装配依赖和UI依赖

<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-server</artifactId>
</dependency>
<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-server-ui</artifactId>
</dependency>

配置监听端口核程序名等

spring.application.name=admin-server
server.port=80

创建核配置启动类

@SpringBootApplication
@EnableAdminServer
public class AdminServer {
    public static void main(String[] args) {
        SpringApplication.run(AdminServer.class,args);
    }
}

@EnableAdminServer注解表示开启spring-boot-admin-server程序。直接启动main方法后,我们访问http://127.0.0.1,可以看到简单的界面效果,由于目前没有客户端程序所以列表中没有记录

接下来我们将之前的admin-client程序集成spring-boot-admin-starter-client,先修改maven依赖

<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>

其次,我们在配置文件中新增如下配置

#设置admin-server的地址
spring.boot.admin.url=http://127.0.0.1

然后我们启动admin-client程序,我们可以看看admin-client程序已经可以在admin-server程序的UI界面中看到了

点击Details按钮,可以看到更多程序的信息,例如

从图中我们可以看到内存使用的情况,这些数据都是通过admin-client程序的端点获取到的信息并展示给我们。信息非常多,更多细节功能可以自己探索,这里不做赘述。

小结

从以上简单的例子中,我们可以发现一般的spring-boot程序使用spring-boot-admin作为管理工具需要经过如下两个步骤:

  • 1、需要创建一个spring-boot-admin的server程序。
  • 2、为应用程序集成spring-boot-admin-stater-client客户端。
  • 3、客户端配置关闭掉端口的安全控制以及配置上admin-server的URL地址。
  • 4、spring-boot-admin的管理程序必须与客户端程序必须网络可达。

1.3 为admin-server程序添加安全访问控制

admin-server程序是spring-boot的安全端点管理程序,自身的安全也是比不可少的,所以我们需要为admin-server程序添加安全访问控制。官方已经提供了对应的支持,具体步骤如下:

  • 添加maven依赖

admin-server的登录安全采用的是spring-security来实现的,官方为我们提供了UI界面。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-server-ui-login</artifactId>
</dependency>
  • 配置用户名核密码

在配置文件application.properties中添加登录访问密码

security.user.name=user
security.user.password=123456
  • 配置WebSecurity安全拦截

最后,我们还需要在admin-server中配置security的拦截配置,同样官方也为我们提供了代码,如下

@Configuration
public static class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // Page with login form is served as /login.html and does a POST on /login
        http.formLogin().loginPage("/login.html").loginProcessingUrl("/login").permitAll();
        // The UI does a POST on /logout on logout
        http.logout().logoutUrl("/logout");
        // The ui currently doesn't support csrf
        http.csrf().disable();

        // Requests for the login page and the static assets are allowed
        http.authorizeRequests()
                .antMatchers("/login.html", "//*.css", "/img/", "/third-party/")
                .permitAll();
        // ... and any other request needs to be authorized
        http.authorizeRequests().antMatchers("/").authenticated();

        // Enable so that the clients can authenticate via HTTP basic for registering
        http.httpBasic();
    }
}

重启程序,再次访问时,就可以看到访问admin-server需要输入用户名和密码了

登录效果图

二、spring-cloud + spring-boot-admin集成

微服务盛行的今天,基于spring-boot的微服务框架spring-cloud进入大众视野,许多大公司也纷纷开始使用该框架,都在尝试适用于自己平台的组件。大家都知道spring-cloud框架程序间是通过微服务的注册发现来实现相互的感知的。
spring-boot-admin官方也为我们提供了基于spring-cloud框架的支持。下面我们逐步来实现spring-boot-admin在spring-cloud下的集成使用。

我们需要创建如下三个程序

程序名 功能说明
eureka-server spring-cloud的eureka实现的注册中心。
admin-cloud-server spring-boot-admin的服务端程序,类似与前面的admin-server。
admin-cloud-server spring-boot-admin的客户端程序,类似与前面的admin-client。

2.1 基于spring-cloud的基础搭建

2.1.1eureka-server创建和配置

我们使用spring-cloud提供的eureka组件搭建一个简单的注册中心程序。搭建非常简单。

  • 创建eureka-server程序并添加依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
  • application.properties文件配置
spring.application.name=eureka-server
server.port=8761
#配置不进行自我注册核信息拉取
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
#注册中心地址,其他程序通过次URL进行注册
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
eureka.instance.instance-id=${spring.cloud.client.ipAddress}:${server.port}
eureka.instance.prefer-ip-address=true

为了方便我们后边测试,在application.properties中可以添加如下配置来关闭掉注册中心自我保护模式以及剔除客户端的时间周期

#是否打开自我保护,如果设置为true,很容易会出现红色字体的自我保护提示,不方便测试
eureka.server.enable-self-preservation=false
#清理时间,默认是60*1000毫秒,修改短一点,保证开发时,客户端失效后,能够快速剔除客户端
eureka.server.eviction-interval-timer-in-ms=10000
  • 配置启动类

我们在启动类上添加注册中心相关注解

@SpringBootApplication
@EnableEurekaServer
public class EurekaServer {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServer.class,args);
    }
}

这样我们的注册中心就配置好了,启动主类即可。

2.1.2、admin-cloud-server创建和配置

与上一节中admin-server程序创建流程类似,我们创建spring-boot-admin的服务端程序admin-cloud-server

  • 添加maven依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-server</artifactId>
</dependency>
<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-server-ui</artifactId>
</dependency>
  • application.properties配置文件配置
spring.application.name=admin-cloud-server
server.port=80
#添加eureka注册信息
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
eureka.instance.instance-id=${spring.cloud.client.ipAddress}:${server.port}
eureka.instance.prefer-ip-address=true
management.security.enabled=false
  • 启动类AdminCloudServer配置
@SpringBootApplication
//注册到eureka
@EnableDiscoveryClient
//开启AdminServer
@EnableAdminServer
public class AdminCloudServer {
    public static void main(String[] args) {
        SpringApplication.run(AdminCloudServer.class, args);
    }
}

配置完成后启动配置,启动程序,访问http://127.0.0.1/,可以看到与上一节中admin-server相同的界面

2.13、admin-cloud-client创建和配置

我们创建一个名为admin-cloud-client的spring-boot-admin的客户端程序,同时它也是一个spring-cloud程序。

  • 添加maven依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

注意一定要添加spring-boot-starter-actuator

  • application.properties配置
spring.application.name=admin-cloud-client
server.port=8090
#注册中心地址
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
eureka.instance.instance-id=${spring.cloud.client.ipAddress}:${server.port}
eureka.instance.prefer-ip-address=true
#关闭安全控制
management.security.enabled=false
  • 启动类配置
@SpringBootApplication
@EnableDiscoveryClient
public class AdminCloudClient {
    public static void main(String[] args) {
        SpringApplication.run(AdminCloudClient.class,args);
    }
}

我们启动该程序,稍后刷新admin-cloud-server的管理页面,可以看到如下效果

可以看到,admin-cloud-client程序也出现在了管理列表中

我们查看eureka-server程序的管理页面http://127.0.0.1:8761,可以看到admin-cloud-server和admin-cloud-client都在注册中心列表中

这样,我们基于spring-cloud注册中心方式的spring-boot-admin管理程序就搭建好了。

小结

从原来的单纯的spring-boot版本改为当前的基于spring-cloud注册中心方式的版本非常简单,大致步骤如下:

  • 1、首先我们要添加eureka客户端支持,都需要添加spring-cloud-starter-eureka依赖
  • 2、配置文件中增加eureka注册中心地址。
  • 3、启动来添加eureka客户端注解@EnableDiscoveryClient来注册到注册中心。
    可以从上面看到,客户端不在需要任何spring-boot-admin客户端的依赖核配置,由于使用了注册中心,使用起来更加简单了。

2.2 基于spring-cloud的扩展监控集成

大家都知道spring-cloud做微服务的一个很重要的特性就是支持hystrix(断路器),解决系统雪崩还对短路情况进行了统计,并支持通过安全端点实时输出。spring-cloud已经提供了hystrix-bashbroad组件UI来动态显示单个断路器的情况,又提供了turbine组件来实现分布式时断路器的数据聚合。虽然原本都提供了UI界面,但并未进行统一集成,在生产环境中使用起来不太方便。
spring-boot-admin不仅添加了spring-cloud的支持,同时还增加了对spring-cloud扩展端点的UI支持。下面我们逐步改进程序来体验一下效果。

实现思路是这样:我们在admin-cloud-client中添加hystrix(断路器)功能支持,并创建一个定时器来让它访问一个不可达的地址。然后在admin-cloud-client中集成hystrix以及turbine监控的UI。观察是否能够达到效果。

2.2.1、admin-cloud-client改造

首先,我们增加hystrix和feign依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
</dependency>

并在启动类采用@EnableCircuitBreaker开启断路器自动装配

@SpringBootApplication
@EnableDiscoveryClient
//开启断路器装配
@EnableCircuitBreaker
//开启feign client
@EnableFeignClients
public class AdminCloudClient {
    public static void main(String[] args) {
        SpringApplication.run(AdminCloudClient.class,args);
    }
}

创建一个FeignClient,但是service-id我们配置为不存在的服务id(test-service)

@FeignClient("test-service")
public interface TestClient {
    @RequestMapping("/test")
    void test();
}

接下来,我们创建一个定时任务来调用FeignClient客户端访问test方法,方便稍后看到断路器变化代码如下

@Component
//开启定时任务
@EnableScheduling
public class HystrixJob {
    @Autowired
    private TestClient testClient;
    @Scheduled(cron = "0/20 * * * * ?")
    public void doJob(){
        try{
            testClient.test();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

2.2.2、admin-cloud-server改造

为admin-cloud-server程序添加hystrix的ui依赖

<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-server-ui-hystrix</artifactId>
</dependency>

先启动admin-cloud-client再启动admin-cloud-server程序。在控制面板中找到“ADMIN-CLOUD-CLIENT”程序点击右边Details按钮,进入admin-cloud-client程序的管理界面,点击hystrix可以看到断路器相关的统计信息

可以看到hystix的UI面板已经集成到了spring-boot-admin中。

接下来我们集成turbine面版UI,首先我们添加turbine的ui和自动装配相关的依赖

<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-server-ui-turbine</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-turbine</artifactId>
</dependency>

上面第一个依赖为我们添加了turbine聚合UI的入口,第二个依赖给程序添加了turbine相关的端点,这样程序访问当前程序才能通过访问自己访问到turbine端口
接着我们得在admin-cloud-server程序启动类上添加@EnableTurbine注解开启turbine支持,如下

@SpringBootApplication
//注册到eureka
@EnableDiscoveryClient
//开启AdminServer
@EnableAdminServer
#开启turbine
@EnableTurbine
public class AdminCloudServer {
    public static void main(String[] args) {
        SpringApplication.run(AdminCloudServer.class, args);
    }
}

最后,需要做turbine相关的配置

spring.boot.admin.turbine.clusters=default
#设置turbine端点的service-id,由于目前turbine功能已经集成到了admin-cloud-server程序中,所以这里填写的是该程序注册到注册中心的service-Id
spring.boot.admin.turbine.location=admin-cloud-server
turbine.clusterNameExpression=new String("default")
#设置需要监控的serviceId
turbine.app-config=admin-cloud-client

2.2.3、效果测试

接下来我们还是依次启动admin-cloud-client和admin-cloud-server程序。登录后admin管理页面,我们可以看到界面增加了新的Turbine入口,界面如下

点击该入口,可以看到一个聚合hystrix信息的turbine面板

这样spring-boot-admin就集成了spring-cloud中turbine组件的功能了。

注意:spirng-boot-admin服务端程序在访问hystrix相关页面的时候会报一个错误

2017-10-24 15:03:21.435  WARN 493284 --- [p-nio-80-exec-7] o.s.c.n.z.f.post.SendResponseFilter      : Error while sending response to client: java.io.IOException: 你的主机中的软件中止了一个已建立的连接。
2017-10-24 15:03:21.446  WARN 493284 --- [p-nio-80-exec-7] o.s.c.n.z.filters.post.SendErrorFilter   : Error during filtering

com.netflix.zuul.exception.ZuulException: Filter threw Exception
    at com.netflix.zuul.FilterProcessor.processZuulFilter(FilterProcessor.java:227) ~[zuul-core-1.3.0.jar:1.3.0]
    at com.netflix.zuul.FilterProcessor.runFilters(FilterProcessor.java:157) ~[zuul-core-1.3.0.jar:1.3.0]
    ......

官方也有人提了issue,不过这是zuul的bug,详情见github

2.3、基于MQ的hystrix(断路器)消息收集方式集成

大家都知道hystrix数据的收集是通过spring-boot-admin服务端访问hystrix端点获取的,如果在无法访问http或者我们想要减少http方式的请求时,可以使用MQ来作为消息手机通信方式。官方推荐使用RabbitMQ,所以我们需要先安装RabbitMQ。具体安装方法这里就不讲了。

2.3.1、admin-cloud-client改造

spring-cloud提供了hystri的MQ收集工具包,我们在client程序中增加如下两个依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-netflix-hystrix-stream</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>

由于采用了RabbitMQ,我们还需要在application.properties中增加MQ的连接配置

#RabbitMQ的连接配置
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

这样客户端的改造就完成了

2.3.2、admin-cloud-server改造

首先,我们在server端添加如下maven依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-turbine-amqp</artifactId>
</dependency>

该依赖会自动引入spring-cloud-starter-stream-rabbit与spring-cloud-starter-turbine-stream。

其次,我们删除掉原来的spring-cloud-starter-turbine依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-turbine</artifactId>
</dependency>

接着我们要改造启动类,使用 @EnableTurbineStream 替换 @EnableTurbine

@SpringBootApplication
//注册到eureka
@EnableDiscoveryClient
//开启AdminServer
@EnableAdminServer
//@EnableTurbine
@EnableTurbineStream
public class AdminCloudServer {
    public static void main(String[] args) {
        SpringApplication.run(AdminCloudServer.class, args);
    }
}

接着,application.properties中删除掉之前的如下配置

turbine.clusterNameExpression=new String("default")
#设置需要监控的serviceId
turbine.app-config=admin-cloud-client

除此之外,我们要配置MQ获取到数据后暴露到哪一个端口,假设我们将数据暴露在8088端口,配置如下

# 这是turbine即暴露监控数据的端口,必须跟server.port不同
turbine.stream.port=8088

最后,我们还需要将之前的spring.boot.admin.turbine.location的值admin-cloud-server改为URL的的方式,指向当前程序的8088端口,如下

spring.boot.admin.turbine.location=http://localhost:${turbine.stream.port}/

2.2.3、效果测试

注意: 如果spring.boot.admin.turbine.location不更改为url,会报如下错误,因为端点端口并未暴露到程序监听的80端口,而是暴露到了turbine.stream.port所配置的8088端口

Unable to connect to Command Metric Stream 'api/turbine/stream?cluster=default'.Error: {"isTrusted":true}

同样,我们依次启动admin-cloud-client和admin-cloud-server,在打开server端的turbine面板,我们又可以看到与之前非MQ模式的效果

三、其他功能集成

接下来我们简单集成核配置两个基础功能:客户端HTTP BASIC认证配置与服务端监控邮件通知

3.1、客户端HTTP BASIC认证配置

大家可以看到我们的客户程序中添加了management.security.enabled并设置其值为false,目的是关闭端点的安全访问。在生产环境中,我们的admin-client或者admin-cloud-client可能添加了安全访问可控制,这个时候访问端点就需要提供用户名和密码了。
spring-boot-admin支持客户端程序使用HTTP BASIC的安全认证,接下来我们改进一下客户端基于spring-boot-starter-security搭建的安全访问控制配置。
我们假设,admin-client或者admin-cloud-client中我们使用spring-boot-starter-security做了HTTP BASIC安全认证,配置文件中的密码配置为

security.user.name=test
security.user.password=123456

client为单纯的spring-boot程序

如果是单纯使用spring-boot构建(非spring-cloud)的程序,那么我们需要在客户端配置文件中增加如下配置

spring.boot.admin.client.metadata.user.name=${security.user.name}
spring.boot.admin.client.metadata.user.password=${security.user.password}

client为spring-cloud程序

如果使用了spring-cloud,因为我们使用的是没有spring-boot-admin-starter-client依赖的方式,而是通过eureka来获取客户端信息的,所以需要按照如下方式配置在元数据中

eureka.instance.metadata-map.user.name=${security.user.name}
eureka.instance.metadata-map.user.password=${security.user.password}

这样spring-boot-admin服务端程序就可以正常访问客户端程序了。

3.2、客户端上下线通知

spring-boot-admin作为监控管理程序,除了提供实时的程序安全数据端口UI监控外,官方还提供了spring-boot-admin客户端程序异常的通知预警功能。官网提供了八种通知方式,详情见官网,大家可以根据自己的需求集成不同的通知方式。接下来我们搭建一下使用邮件通知方式的预警功能。spring-boot-admin集成邮件通知功能与spring-boot集成邮件发送功能类似。接下来我们逐步集成改进spring-boot-admin服务端(我们以admin-cloud-server为例)。

添加maven依赖

我们在上一节中的admin-cloud-server中添加spring-boot邮件相关依赖

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

修改properties文件配置

我们在application.properties文件中添加如下配置

#邮件通知配置
#邮件服务器地址
spring.mail.host=smtp.qq.com
#发送邮件的邮箱地址
spring.mail.username=test0@qq.com
#QQ邮箱授权码或163邮箱密码
spring.mail.password=******
#添加邮件认证相关设置
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
#需要忽略的状态改变通知,逗号分隔,例如不通知离线到上线的状态,则填写为OFFLINE:UP
#spring.boot.admin.notify.mail.ignore-changes=
#接收通知的邮箱地址,逗号分隔
spring.boot.admin.notify.mail.to=test2@qq.com
#需要抄送的邮箱地址,逗号分隔
spring.boot.admin.notify.mail.cc=test1@qq.com
#邮件发送者,大部分情况与登录名相同
spring.boot.admin.notify.mail.from=${spring.mail.username}
#邮件主题,默认是:#{application.name} (#{application.id}) is #{to.status}
spring.boot.admin.notify.mail.subject=#{application.name} (#{application.id}) is #{to.status}
#邮件内容,默认是:#{application.name} (#{application.id})\nstatus changed from #{from.status} to #{to.status}\n\n#{application.healthUrl}
spring.boot.admin.notify.mail.text=#{application.name} (#{application.id})\nstatus changed from #{from.status} to #{to.status}

测试效果

还是分别启动eureka-server、admin-cloud-server、admin-cloud-client程序。片刻之后我们重启admin-cloud-client
可以在windows任务栏的QQ弹出了admin-client-client状态变表更的邮件提示,我们进入邮箱可以看到两封邮件,效果如下:

我们点击一个邮件进去可以看到如下的默认邮件内容

image.png

可以看到邮件详细内容的格式与spring.boot.admin.notify.mail.text参数配置的格式相同,所以我们可以通过更改该配置的内容格式来定制我们想要的预警内容。

小结

通过spring-boot-admin集成邮件通知可以更加丰富监控程序的功能。为生产环境中的安全稳定运行又提供了一层有效的保障。

总结

spring-boot-admin为我们基于spring-boot开发的程序(包括spring-cloud)提供了安全端点的基础监控,对有异常状态(客户端状态变更为上线、下线、未知等)支持多种通知方式。为生产环境的运营维护提供了直观的UI效果。
当然对于当前复杂的生产环境来说,spring-boot-admin所支持的还是一下小部分。未来希望能够看到更多的更开放的监控功能的集成(例如zipkin),并且支持更多自定义的监控开发。

参考资料:

http://codecentric.github.io/spring-boot-admin/1.5.4/

http://www.jianshu.com/p/add65b345be7

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容