Статьи

Настройка Spring Spring Boot Admin

Spring Boot Admin — это крутая панель мониторинга ваших приложений весенней загрузки. Однако его настройка не так тривиальна. В документации изложены два варианта :

  • Включение клиентской библиотеки в ваше загрузочное приложение, которое подключается к приложению администратора — для этого необходимо, чтобы приложение администратора было развернуто где-то общедоступно или, по крайней мере, доступно из вашего приложения, а также информировало ваше приложение о том, что оно отслеживается.
  • Использование облачного обнаружения, что означает, что ваше приложение является частью инфраструктуры обнаружения услуг, например, с использованием микросервисов.

Оба варианта не очень хороши для более простых сценариев, таких как монолитное приложение , запускаемое на некотором IaaS, и развертывание приложения администратора на локальном компьютере или в какой-либо локальной инфраструктуре компании. Обнаружение в облаке является излишним, если оно вам еще не нужно, и включение клиентской библиотеки усложняет доступ к административному серверу для вашего приложения, а не наоборот. И, кроме того, эта двусторонняя зависимость звучит неправильно.

К счастью, существует недокументированный, но реализованный SimpleDiscoveryClient который позволяет просто запустить Spring Boot Admin с некоторой конфигурацией на любой машине и подключить ее к приложению весенней загрузки.

Первым требованием является настройка привода с пружинной загрузкой в загрузочном приложении. Привод предоставляет все необходимые конечные точки для работы приложения администратора. Это звучит тривиально для установки — вы просто добавляете кучу зависимостей и, возможно, указываете некоторые параметры конфигурации и все. На самом деле, в реальном приложении это не так просто, особенно в отношении базовой аутентификации для конечных точек привода. Вам нужна отдельная защита пружины (в дополнение к существующей конфигурации защиты пружины), чтобы применить базовую аутентификацию только к конечным точкам привода. Например:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
@Configuration
@Order(99) // the default security configuration has order 100
public class ActuatorSecurityConfiguration extends WebSecurityConfigurerAdapter {
 
    @Value("${security.user.name}")
    private String username;
     
    @Value("${security.user.password}")
    private String password;
     
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername(username).password(password).roles("ACTUATOR","ADMIN").build());
         
        http.antMatcher("/manage/**").authorizeRequests().anyRequest().hasRole("ACTUATOR").and().httpBasic()
                .and().userDetailsService(manager);
    }
}

Это немного нелогично, но это работает. Не уверен, что это идиоматично — с пружинной защитой и пружинной загрузкой вы никогда не знаете, что идиоматично. Примечание: предположительно должно быть возможным автоматическое включение security.user.name (и пароля) в некоторый менеджер, но я не смог его найти, поэтому я просто создал экземпляр в памяти. Обратите внимание на путь /manage/** — для того, чтобы все конечные точки привода находились под этим путем, вам нужно указать файл management.context-path=/manage в файле свойств вашего приложения.

Теперь, когда конечные точки привода настроены, мы должны прикрепить наше приложение администратора для пружин. Это выглядит так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
@Configuration
@EnableAutoConfiguration
@PropertySource("classpath:/application.properties")
@EnableAdminServer
public class BootAdminApplication {
    public static void main(String[] args) {
        SpringApplication.run(BootAdminApplication.class, args);
    }
 
    @Autowired
    private ApplicationDiscoveryListener listener;
     
    @PostConstruct
    public void init() {
        // we have to fire this event in order to trigger the service registration
        InstanceRegisteredEvent<?> event = new InstanceRegisteredEvent<>("prod", null);
        // for some reason publising doesn't work, so we invoke directly
        listener.onInstanceRegistered(event);
    }
}

Обычно нужно внедрить ApplicationEventPublisher и отправить туда сообщение, а не напрямую вызывать слушателя, как показано выше. Мне не удалось заставить его работать легко, поэтому я обошел это.

Упомянутый файл application.properties должен находиться в src / main / resources и выглядит так:

1
2
3
4
5
spring.cloud.discovery.client.simple.instances.prod[0].uri=https://your-spring-boot-application-url.com
spring.cloud.discovery.client.simple.instances.prod[0].metadata.user.name=<basic-auth-username>
spring.cloud.discovery.client.simple.instances.prod[0].metadata.user.password=<basic-auth-password>
spring.boot.admin.discovery.converter.management-context-path=/manage
spring.boot.admin.discovery.services=*

Что это делает? Он использует SimpleDiscoveryClient который SimpleDiscoveryClient с помощью автоконфигурации. На самом деле, этот клиент не работал до последней версии — он генерировал исключение NullPointerException, потому что метаданные (которые обрабатывают имя пользователя и пароль) всегда были нулевыми. В 1.2.2 облачных сообществ они исправили это:

1
2
3
4
5
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-commons</artifactId>
    <version>1.2.2.RELEASE</version>
</dependency>

Простой клиент обнаружения именно такой: вы указываете URL-адрес вашего загрузочного приложения, и он периодически извлекает данные из конечных точек привода. Почему это не задокументировано и почему это не сработало до недавнего времени — я понятия не имею. Кроме того, я не знаю, почему вы должны вручную отправить событие, которое вызывает обнаружение. Может быть, это не идиоматично, но это не происходит автоматически, и это заставило его работать.

Как обычно с вещами, которые «просто работают» и имеют «простые настройки» — это никогда не бывает так. Если у вас есть что-то немного более сложное, чем мир приветствия, вы должны выкопать несколько непонятных классов и отправиться в путь. К счастью, в этом случае это действительно работает, а не требует отвратительных обходных путей.