«1. Обзор

Проект Spring Cloud Consul обеспечивает простую интеграцию с Consul для приложений Spring Boot.

Consul — это инструмент, предоставляющий компоненты для решения некоторых наиболее распространенных проблем в архитектуре микрослужб:

    Service Discovery — для автоматической регистрации и отмены регистрации сетевых расположений экземпляров службы Health Checking — для определить, когда экземпляр службы запущен и работает Распределенная конфигурация — чтобы убедиться, что все экземпляры службы используют одну и ту же конфигурацию

В этой статье мы увидим, как мы можем настроить приложение Spring Boot для использования этих функций.

2. Предварительные требования

Для начала рекомендуется быстро ознакомиться с Consul и всеми его функциями.

В этой статье мы будем использовать агент Consul, работающий на локальном хосте: 8500. Подробнее о том, как установить Консул и запустить агент, можно узнать по этой ссылке.

Во-первых, нам нужно добавить зависимость spring-cloud-starter-consul-all в наш pom.xml:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-all</artifactId>
    <version>1.3.0.RELEASE</version>
</dependency>

3. Обнаружение службы

Давайте напишем наше первое приложение Spring Boot и подключим up с запущенным агентом Consul:

@SpringBootApplication
public class ServiceDiscoveryApplication {

    public static void main(String[] args) {
        new SpringApplicationBuilder(ServiceDiscoveryApplication.class)
          .web(true).run(args);
    }
}

По умолчанию Spring Boot попытается подключиться к агенту Consul по адресу localhost:8500. Чтобы использовать другие настройки, нам нужно обновить файл application.yml:

spring:
  cloud:
    consul:
      host: localhost
      port: 8500

Затем, если мы зайдем на сайт агента Consul в браузере по адресу http://localhost:8500, мы увидим, что наше приложение было должным образом зарегистрированы в Консуле с идентификатором из «${spring.application.name}:${профили, разделенные запятой}:${server.port}».

Чтобы настроить этот идентификатор, нам нужно обновить свойство spring.cloud.discovery.instanceId другим выражением:

spring:
  application:
    name: myApp
  cloud:
    consul:
      discovery:
        instanceId: ${spring.application.name}:${random.value}

Если мы снова запустим приложение, мы увидим, что оно было зарегистрировано с использованием идентификатора â “MyApp” плюс случайное значение. Нам это нужно для запуска нескольких экземпляров нашего приложения на нашей локальной машине.

Наконец, чтобы отключить обнаружение служб, нам нужно установить для свойства spring.cloud.consul.discovery.enabled значение false.

3.1. Поиск сервисов

Наше приложение уже зарегистрировано в Consul, но как клиенты могут найти конечные точки сервиса? Нам нужна клиентская служба обнаружения, чтобы получить работающую и доступную службу от Consul.

Spring предоставляет для этого API DiscoveryClient, который мы можем включить с помощью аннотации @EnableDiscoveryClient:

@SpringBootApplication
@EnableDiscoveryClient
public class DiscoveryClientApplication {
    // ...
}

Затем мы можем внедрить bean-компонент DiscoveryClient в наш контроллер и получить доступ к экземплярам:

@RestController
public class DiscoveryClientController {
 
    @Autowired
    private DiscoveryClient discoveryClient;

    public Optional<URI> serviceUrl() {
        return discoveryClient.getInstances("myApp")
          .stream()
          .findFirst() 
          .map(si -> si.getUri());
    }
}

Наконец , мы определим конечные точки нашего приложения:

@GetMapping("/discoveryClient")
public String discoveryPing() throws RestClientException, 
  ServiceUnavailableException {
    URI service = serviceUrl()
      .map(s -> s.resolve("/ping"))
      .orElseThrow(ServiceUnavailableException::new);
    return restTemplate.getForEntity(service, String.class)
      .getBody();
}

@GetMapping("/ping")
public String ping() {
    return "pong";
}

Путь «myApp/ping» — это имя приложения Spring с конечной точкой службы. Consul предоставит все доступные приложения с именем «myApp».

4. Проверка работоспособности

Consul периодически проверяет работоспособность конечных точек службы.

По умолчанию Spring реализует конечную точку работоспособности для возврата 200 OK, если приложение запущено. Если мы хотим настроить конечную точку, мы должны обновить application.yml:

spring:
  cloud:
    consul:
      discovery:
        healthCheckPath: /my-health-check
        healthCheckInterval: 20s

В результате Consul будет опрашивать конечную точку «/my-health-check» каждые 20 секунд.

Давайте настроим нашу пользовательскую службу проверки работоспособности так, чтобы она возвращала статус ЗАПРЕЩЕНО:

@GetMapping("/my-health-check")
public ResponseEntity<String> myCustomCheck() {
    String message = "Testing my healh check function";
    return new ResponseEntity<>(message, HttpStatus.FORBIDDEN);
}

Если мы перейдем на сайт агента Consul, мы увидим, что наше приложение дает сбой. Чтобы исправить это, служба «/my-health-check» должна возвращать код состояния HTTP 200 OK.

5. Распределенная конфигурация

Эта функция позволяет синхронизировать конфигурацию между всеми сервисами. Consul будет следить за любыми изменениями конфигурации, а затем запускать обновление всех сервисов.

Во-первых, нам нужно добавить зависимость spring-cloud-starter-consul-config в наш pom.xml:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-config</artifactId>
    <version>1.3.0.RELEASE</version>
</dependency>

Нам также нужно переместить настройки имени приложения Consul и Spring из application.yml файл в файл bootstrap.yml, который Spring загружает первым.

Затем нам нужно включить Spring Cloud Consul Config:

spring:
  application:
    name: myApp
  cloud:
    consul:
      host: localhost
      port: 8500
      config:
        enabled: true

Spring Cloud Consul Config будет искать свойства в Consul в «/config/myApp». Итак, если у нас есть свойство с именем «my.prop», нам нужно будет создать это свойство на сайте агента Consul.

«Мы можем создать свойство, перейдя в раздел «KEY/VALUE», затем введя «/config/myApp/my/prop» в форме «Create Key» и «Hello World» в качестве значения. Наконец, нажмите кнопку «Создать».

Имейте в виду, что если мы используем профили Spring, нам нужно добавить профили рядом с именем приложения Spring. Например, если мы используем профиль dev, конечный путь в Consul будет «/config/myApp,dev».

Теперь давайте посмотрим, как выглядит наш контроллер с введенными свойствами:

@RestController
public class DistributedPropertiesController {

    @Value("${my.prop}")
    String value;

    @Autowired
    private MyProperties properties;

    @GetMapping("/getConfigFromValue")
    public String getConfigFromValue() {
        return value;
    }

    @GetMapping("/getConfigFromProperty")
    public String getConfigFromProperty() {
        return properties.getProp();
    }
}

И класс MyProperties:

@RefreshScope
@Configuration
@ConfigurationProperties("my")
public class MyProperties {
    private String prop;

    // standard getter, setter
}

Если мы запустим приложение, значение поля и свойства будут одинаковыми — Значение «Hello World» от Consul.

5.1. Обновление конфигурации

Как насчет обновления конфигурации без перезапуска приложения Spring Boot?

Если мы вернемся на сайт агента Consul и обновим свойство «/config/myApp/my/prop» другим значением, например «New Hello World», тогда значение поля не изменится, а поле свойства будут обновлены до «New Hello World», как и ожидалось.

Это связано с тем, что свойства поля — это класс MyProperties, имеющий аннотацию @RefreshScope. Все bean-компоненты, аннотированные аннотацией @RefreshScope, будут обновлены после изменения конфигурации.

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

6. Заключение

В этой статье мы увидели, как настроить наши приложения Spring Boot для работы с Consul для целей обнаружения служб, настроить правила проверки работоспособности и поделиться распределенной конфигурацией.

Мы также представили ряд подходов для клиентов, чтобы вызвать эти зарегистрированные службы.

Как обычно, исходники можно найти на GitHub.