一、什麼是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
<code><project> <modelversion>4.0.0/<modelversion> <parent> <groupid>org.springframework.boot/<groupid> <artifactid>spring-boot-starter-parent/<artifactid> <version>2.1.0.RELEASE/<version> <relativepath> /<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>/<code>
application.yml
<code>spring: application: name: admin-serverserver: port: 8769/<code>
啟動類 AdminServerApplication
啟動類加上@EnableAdminServer註解,開啟AdminServer的功能:
<code>@SpringBootApplication@EnableAdminServerpublic class AdminServerApplication { public static void main(String[] args) { SpringApplication.run( AdminServerApplication.class, args ); }}/<code>
2. 創建 Spring Boot Admin Client
pom.xml
<code> <project> <modelversion>4.0.0/<modelversion> <parent> <groupid>org.springframework.boot/<groupid> <artifactid>spring-boot-starter-parent/<artifactid> <version>2.1.0.RELEASE/<version> <relativepath> /<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>/<code>
application.yml
- spring.boot.admin.client.url:要註冊的Spring Boot Admin Server的URL。
- management.endpoints.web.exposure.include:與Spring Boot 2一樣,默認情況下,大多數actuator的端口都不會通過http公開,* 代表公開所有這些端點。對於生產環境,應該仔細選擇要公開的端點。
<code>spring: application: name: admin-client boot: admin: client: url: http://localhost:8769server: port: 8768management: endpoints: web: exposure: include: '*' endpoint: health: show-details: ALWAYS/<code>
啟動類 AdminClientApplication
<code>@SpringBootApplicationpublic class AdminClientApplication { public static void main(String[] args) { SpringApplication.run( AdminClientApplication.class, args ); }}/<code>
啟動兩個工程,在瀏覽器上輸入localhost:8769 ,瀏覽器顯示的界面如下:
查看wallboard:
點擊wallboard,可以查看admin-client具體的信息,比如內存狀態信息:
查看spring bean的情況:
查看應用程序運行狀況,信息和詳細:
還有很多監控信息,多點一點就知道。
三、集成 Eureka
1. 創建 sc-eureka-server
這是一個 eureka-server 註冊中心。
pom.xml
<code><project> <modelversion>4.0.0/<modelversion> <parent> <groupid>org.springframework.boot/<groupid> <artifactid>spring-boot-starter-parent/<artifactid> <version>2.1.0.RELEASE/<version> <relativepath> /<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>/<code>
application.yml
<code>spring: application: name: sc-eureka-serverserver: port: 8761eureka: client: service-url: defaultZone: http://localhost:8761/eureka register-with-eureka: false fetch-registry: falsemanagement: endpoints: web: exposure: include: "*" endpoint: health: show-details: ALWAYS/<code>
啟動類 ScEurekaServerApplication
<code>@SpringBootApplication@EnableEurekaServerpublic class ScEurekaServerApplication { public static void main(String[] args) { SpringApplication.run( ScEurekaServerApplication.class, args ); }}/<code>
2. 創建 sc-admin-server
這是一個 Spring Boot Admin Server端。
pom.xml
<code><project> <modelversion>4.0.0/<modelversion> <parent> <groupid>org.springframework.boot/<groupid> <artifactid>spring-boot-starter-parent/<artifactid> <version>2.1.0.RELEASE/<version> <relativepath> /<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>/<code>
application.yml
<code>spring: application: name: admin-serverserver: port: 8769eureka: client: registryFetchIntervalSeconds: 5 service-url: defaultZone: ${EUREKA_SERVICE_URL:http://localhost:8761}/eureka/ instance: leaseRenewalIntervalInSeconds: 10 health-check-url-path: /actuator/healthmanagement: endpoints: web: exposure: include: "*" endpoint: health: show-details: ALWAYS/<code>
啟動類 ScAdminServerApplication
<code>@SpringBootApplication@EnableAdminServer@EnableDiscoveryClientpublic class ScAdminServerApplication { public static void main(String[] args) { SpringApplication.run( ScAdminServerApplication.class, args ); }}/<code>
3. 創建 sc-admin-client
這是一個 Spring Boot Admin client 端。
pom.xml
<code><project> <modelversion>4.0.0/<modelversion> <parent> <groupid>org.springframework.boot/<groupid> <artifactid>spring-boot-starter-parent/<artifactid> <version>2.1.0.RELEASE/<version> <relativepath> /<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>/<code>
application.yml
<code>spring: application: name: sc-admin-clienteureka: 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: ALWAYSserver: port: 8762/<code>
啟動類 ScAdminClientApplication
<code>@SpringBootApplication@EnableDiscoveryClientpublic class ScAdminClientApplication { public static void main(String[] args) { SpringApplication.run( ScAdminClientApplication.class, args ); }}/<code>
啟動三個工程,訪問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文件需要增加以下的依賴:
<code><dependency> <groupid>org.springframework.boot/<groupid> <artifactid>spring-boot-starter-security/<artifactid>/<dependency>/<code>
在 sc-admin-server工的配置文件 application.yml 中配置 spring security 的用戶名和密碼,這時需要在服務註冊時帶上 metadata-map 的信息,如下:
<code>spring: security: user: name: "admin" password: "admin" eureka: instance: metadata-map: user.name: ${spring.security.user.name} user.password: ${spring.security.user.password}/<code>
@EnableWebSecurity註解以及WebSecurityConfigurerAdapter一起配合提供基於web的security。繼承了WebSecurityConfigurerAdapter之後,再加上幾行代碼,我們就能實現要求用戶在進入應用的任何URL之前都進行驗證的功能,寫一個配置類SecuritySecureConfig繼承WebSecurityConfigurerAdapter,配置如下:
<code>@Configurationpublic 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 }}/<code>
重新訪問 http://localhost:8769/ 會出現登錄界面,密碼是 配置文件中配置好的,賬號 admin 密碼 admin,界面如下:
五、通知
1. 郵件通知
在 Spring Boot Admin 中 當註冊的應用程序狀態更改為DOWN、UNKNOWN、OFFLINE 都可以指定觸發通知,下面講解配置郵件通知。
在sc-admin-server工程pom文件,加上mail的依賴,如下:
<code><dependency> <groupid>org.springframework.boot/<groupid> <artifactid>spring-boot-starter-mail/<artifactid>/<dependency>/<code>
在配置文件application.yml文件中,配置收發郵件的配置:
<code>spring: mail: host: smtp.163.com username: [email protected] password: xxxx properties: mail: smtp: auth: true starttls: enable: true required: true boot: admin: notify: mail: from: [email protected] to: [email protected]/<code>
配置後,重啟sc-admin-server工程,之後若出現註冊的客戶端的狀態從 UP 變為 OFFLINE 或其他狀態,服務端就會自動將電子郵件發送到上面配置的收件地址。
注意 : 配置了郵件通知後,會出現 反覆通知 service offline / up。這個問題的原因在於 查詢應用程序的狀態和信息超時,下面給出兩種解決方案:
<code>#方法一:增加超時時間(單位:ms)spring.boot.admin.monitor.read-timeout=20000#方法二:關閉閉未使用或不重要的檢查點management.health.db.enabled=falsemanagement.health.mail.enabled=falsemanagement.health.redis.enabled=falsemanagement.health.mongo.enabled=false/<code>
2. 自定義通知
可以通過添加實現Notifier接口的Spring Beans來添加您自己的通知程序,最好通過擴展 AbstractEventNotifier或AbstractStatusChangeNotifier。在sc-admin-server工程中編寫一個自定義的通知器:
<code>@Componentpublic 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()); } }); }}/<void>/<code>
源碼下載:https://github.com/gf-huanchupk/SpringBootLearning/tree/master/springboot-admin
閱讀更多 程序員果果 的文章