В MicroServices с использованием Spring Boot и Spring Cloud. Часть 1. Обзор мы кратко рассмотрели, что такое микро-сервисы и как мы можем использовать SpringBoot и SpringCloud для создания микро-сервисов.
В этом посте мы собираемся узнать:
- Зачем нужны Spring Cloud Config и Vault ?
- Создайте наш первый микро-сервис: каталог-сервис
- Создать сервер Spring Cloud Config
- Использование Vault для хранения конфиденциальных данных
Микроуслуги с использованием Spring Boot и Spring Cloud
- Часть 1. MicroServices с использованием Spring Boot и Spring Cloud: обзор
- Часть 2. MicroServices — Управление конфигурацией с помощью Spring Cloud Config и Vault
Зачем нужны Spring Cloud Config и Vault?
SpringBoot уже предоставляет множество опций для вывода свойств конфигурации . Однако после запуска приложения вы не сможете изменить эти значения свойств во время выполнения. Вам необходимо обновить свойства и перезапустить приложение, чтобы эти изменения вступили в силу.
В мире микросервисов может быть большое количество микросервисов, и несколько экземпляров этих микросервисов работают. Обновление свойств конфигурации и перезапуск всех этих экземпляров вручную или даже с помощью автоматических сценариев может оказаться невозможным. Spring Cloud Config решает эту проблему.
Мы можем создать сервер Spring Cloud Config, который предоставляет значения конфигурации для всех наших микросервисов. Мы можем использовать git , svn , database или Consul в качестве бэкэнда для хранения параметров конфигурации. Затем мы можем настроить расположение сервера Spring Cloud Config в нашем микросервисе, чтобы он загружал все свойства при запуске приложения. Кроме того, всякий раз, когда мы обновляем свойства, мы можем вызывать / обновлять конечную точку REST в нашем микросервисе, чтобы она перезагружала изменения конфигурации без необходимости перезапуска приложения.
В наших приложениях нам также необходимо настроить различные конфиденциальные данные, такие как учетные данные базы данных, ключи, токены и т. Д. Очевидно, что мы не хотим хранить их в виде простого текста. Лучшим подходом было бы хранить их в зашифрованном формате, а Spring Cloud Config Server предоставляет возможность шифровать и дешифровать данные. Еще лучше, мы должны использовать безопасные инструменты хранения данных, такие как Vault . Spring Cloud также обеспечивает интеграцию с Vault, поэтому мы можем хранить любые конфиденциальные свойства конфигурации в Vault.
Я уже написал несколько учебных пособий по Spring Cloud Config Server, к которым вы можете обратиться:
- Введение в Spring Cloud Config Server
- Автоматическое обновление изменений конфигурации с использованием Spring Cloud Bus
Создайте наш первый микро-сервис: каталог-сервис
Начнем с нашего первого микросервиса, то есть каталога-сервиса . Создайте приложение SpringBoot со стартерами в Интернете , JPA , MySQL , Actuator , DevTools , Lombok . Пока ничего необычного, типичное приложение SpringBoot.
Вы можете найти исходный код этой статьи по адресу https://github.com/sivaprasadreddy/spring-boot-microservices-series.
Во-первых, давайте реализуем конечную точку REST для предоставления данных о продуктах, а затем рефакторинг их для использования Cloud Config Server.
Мы собираемся использовать Docker и запускать MySQL как контейнер Docker.
докер-compose.yml
01
02
03
04
05
06
07
08
09
10
|
version: '3' services: mysqldb: image: mysql:5.7 container_name: mysqldb ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: admin MYSQL_DATABASE: catalog |
Настройте свойства источника данных в application.properties следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
server.port=8181 logging.level.com.sivalabs=debug spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql: //localhost :3306 /catalog ?useSSL= false spring.datasource.username=root spring.datasource.password=admin spring.datasource.initialization-mode=always spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql= true //expose all the Actuator endpoints management.endpoints.web.exposure.include=* |
Создайте сущность JPA Product.java следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
import lombok.Data; import javax.persistence.*; @Data @Entity @Table (name = "products" ) public class Product { @Id @GeneratedValue (strategy = GenerationType.AUTO) private Long id; @Column (nullable = false , unique = true ) private String code; @Column (nullable = false ) private String name; private String description; private double price; } |
Создайте репозиторий Spring Data JPA ProductRepository.java следующим образом:
1
2
3
4
5
6
7
|
import com.sivalabs.catalogservice.entities.Product; import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; public interface ProductRepository extends JpaRepository<Product, Long> { Optional<Product> findByCode(String code); } |
Создайте ProductService, который сейчас просто делегирован в ProductRepository . Мы можем напрямую внедрить Repository в наши компоненты веб-слоя (Controllers), но в будущем может возникнуть бизнес-логика, которую я не люблю вставлять ни в Controller, ни в Repository.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
import com.sivalabs.catalogservice.entities.Product; import com.sivalabs.catalogservice.repositories.ProductRepository; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.Optional; @Service @Transactional @Slf4j public class ProductService { private final ProductRepository productRepository; @Autowired public ProductService(ProductRepository productRepository) { this .productRepository = productRepository; } public List<Product> findAllProducts() { return productRepository.findAll(); } public Optional<Product> findProductByCode(String code) { return productRepository.findByCode(code); } } |
Наконец, создайте наш REST-контроллер ProductController.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
import com.sivalabs.catalogservice.entities.Product; import com.sivalabs.catalogservice.exceptions.ProductNotFoundException; import com.sivalabs.catalogservice.services.ProductService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController @RequestMapping ( "/api/products" ) @Slf4j public class ProductController { private final ProductService productService; @Autowired public ProductController(ProductService productService) { this .productService = productService; } @GetMapping ( "" ) public List<Product> allProducts() { return productService.findAllProducts(); } @GetMapping ( "/{code}" ) public Product productByCode( @PathVariable String code) { return productService.findProductByCode(code) .orElseThrow(() -> new ProductNotFoundException( "Product with code [" +code+ "] doesn't exist" )); } } |
Создайте исключение ProductNotFoundException, расширяющее RuntimeException, и аннотируйте его с помощью @ResponseStatus (HttpStatus.NOT_FOUND) .
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus (HttpStatus.NOT_FOUND) public class ProductNotFoundException extends RuntimeException { public ProductNotFoundException() { } public ProductNotFoundException(String message) { super (message); } public ProductNotFoundException(String message, Throwable cause) { super (message, cause); } public ProductNotFoundException(Throwable cause) { super (cause); } } |
Давайте добавим несколько примеров продуктов в нашу базу данных.
SRC / главная / ресурсы / data.sql
1
2
3
4
5
6
7
|
DELETE FROM products; insert into products(id, code, name , description, price) VALUES (1, 'P001' , 'Product 1' , 'Product 1 description' , 25), (2, 'P002' , 'Product 2' , 'Product 2 description' , 32), (3, 'P003' , 'Product 3' , 'Product 3 description' , 50) ; |
Хорошо, теперь мы можем запустить наше приложение SpringBoot и нажать http: // localhost: 8181 / api / products. Вы должны увидеть ответ JSON с информацией о продуктах.
Создать сервер Spring Cloud Config
мы собираемся создать Spring Cloud Config Server, используя Git backend. Spring Cloud Config Server — это не что иное, как проект SpringBoot. Создайте проект SpringBoot с помощью Config Server startter.
Сконфигурируйте местоположение репозитория git, в котором мы будем хранить все наши файлы конфигурации в файле application.properties .
1
2
3
4
5
6
7
|
spring.config.name=configserver server.port=8888 spring.cloud.config.server.git.uri=https: //github .com /sivaprasadreddy/microservices-config-repo spring.cloud.config.server.git.clone-on-start= true management.endpoints.web.exposure.include=* |
Теперь аннотируйте класс точки входа с помощью @EnableConfigServer .
01
02
03
04
05
06
07
08
09
10
11
12
|
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.config.server.EnableConfigServer; @EnableConfigServer @SpringBootApplication public class ConfigServerApplication { public static void main(String[] args) { SpringApplication.run(ConfigServerApplication. class , args); } } |
Вот и все. Это все, что вам нужно сделать для создания Spring Cloud Config Server, и вам просто нужно добавить специфичные для приложения файлы конфигурации в репозиторий git.
Если вы мысленно подготовили написать кучу кода для создания Spring Cloud Config Server, извините, что разочаровал вас :-).
Рефакторинг каталога-сервиса для использования Config Server
Наш каталог-сервис станет клиентом для Config Server. Итак, давайте добавим клиент Config Client в каталог-сервис, который добавит следующую зависимость.
1
2
3
4
|
< dependency > < groupId >org.springframework.cloud</ groupId > < artifactId >spring-cloud-starter-config</ artifactId > </ dependency > |
Убедитесь, что вы также добавили спецификацию spring-cloud-dependencies и в раздел <properties> .
При использовании Spring Cloud Config Server процесс загрузки свойств происходит в несколько этапов, сначала загружая bootstrap.properties/ yml, а затем с сервера конфигурации.
Итак, давайте переименуем application.properties в bootstrap.properties и обновим его, чтобы он имел следующие свойства.
1
2
3
4
|
spring.application.name=catalog-service server.port=8181 management.endpoints.web.exposure.include=* spring.cloud.config.uri=http: //localhost :8888 |
Здесь мы настроили расположение нашего сервера Config и дали имя в качестве службы каталогов нашему приложению, используя spring.application.name .
Теперь нам нужно добавить все свойства нашего каталога-сервиса в catalog-service.properties и зафиксировать / отправить его в наше git repo microservices-config-repo .
microservices-конфигурации-репо / catalog-service.properties
01
02
03
04
05
06
07
08
09
10
|
logging.level.com.sivalabs=debug spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql: //localhost :3306 /catalog ?useSSL= false spring.datasource.username=root spring.datasource.password=admin spring.datasource.initialization-mode=always spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql= true |
Вы также можете добавить отдельные файлы конфигурации для разных файлов, таких как catalog-service-qa.properties , catalog-service-prod.properties и т. Д.
Теперь сначала запустите приложение Config Server, а затем приложение службы каталогов. Это должно работать нормально. Вы можете проверить журналы консоли, что служба каталогов извлекает свойства с сервера конфигурации http: // localhost: 8888 / при запуске.
Сейчас мы немного приближаемся к нашей цели, но мы все еще храним учетные данные в виде простого текста. Давайте переместим конфиденциальные свойства конфигурации в Vault.
Использование Vault для хранения конфиденциальных данных
Vault — это инструмент для безопасного хранения и доступа к секретам. Вы можете прочитать больше о Vault здесь https://www.vaultproject.io/intro/index.html . Vault поставляется в виде одного двоичного файла, который можно загрузить по адресу https://www.vaultproject.io/downloads.html .
Теперь запустите Vault в режиме разработки с помощью следующей команды:
$ vault server -dev
В консоли вы можете увидеть информацию о том, как использовать Vault и Root токен .
Откройте новое окно терминала, установите переменную среды VAULT_ADDR .
$ export VAULT_ADDR = ‘http: //127.0.0.1: 8200 ′
ПРИМЕЧАНИЕ. Режим разработки хранилища предназначен только для разработки и не предназначен для производственного использования.
Мы можем записать секретные данные в хранилище, используя секретную запись / хранилище ключей ключ1 = значение1 ключ2 = значение2
Мы также можем поместить все наши секреты в файл JSON и записать из него файл. Давайте создадим файл JSON с учетными данными базы данных MySQL и запишем в Vault.
Каталог-сервис-credentials.json
1
2
3
4
|
{ "spring.datasource.username" : "root" , "spring.datasource.password" : "admin" } |
$ vault write secret / catalog-service @ catalog-service-credentials.json
Вы можете проверить значения, запустив хранилище read secret / catalog-service .
Мы можем автоматизировать весь этот процесс настройки Vault и инициализации с использованием секретов с помощью Docker. Пожалуйста, посмотрите на репозиторий исходных текстов на github, чтобы узнать, как это сделать. Один из способов сделать это.
Теперь, когда Vault настроен и инициализирован с секретами. Давайте проведем рефакторинг каталога-сервиса для использования Vault.
Добавьте Vault Configuration starter в каталог-сервис, который добавит следующую зависимость.
1
2
3
4
|
< dependency > < groupId >org.springframework.cloud</ groupId > < artifactId >spring-cloud-starter-vault-config</ artifactId > </ dependency > |
Удалите следующие учетные данные из microservices-config-repo / catalog-service.properties и зафиксируйте их.
1
2
|
spring.datasource.username=root spring.datasource.password=admin |
Добавьте свойства конфигурации Vault в bootstrap.properties .
1
2
3
4
5
|
spring.cloud.vault.host=localhost spring.cloud.vault.port=8200 spring.cloud.vault.scheme=http spring.cloud.vault.authentication=token spring.cloud.vault.token=934f9eae-31ff-a8ef-e1ca-4bea9e07aa09 |
Мы настроили свойства Vault с использованием аутентификации на основе токенов и настроили Root Taken, который печатается в журнале консоли при запуске сервера хранилища.
У нас все готово. Мы перенесли свойства сервиса на внешний сервер конфигурации и конфиденциальные данные в Vault.
Теперь запустите Config Server и каталог-сервис, и он должен работать нормально.
Резюме
В этом посте мы узнали, как использовать Spring Cloud Config для вывода свойств конфигурации и Vault для хранения секретов. Вы можете использовать Spring Cloud Bus для автоматического обновления изменений конфигурации, как описано в Учебных пособиях Spring Cloud — Автоматическое обновление изменений конфигурации с использованием Spring Cloud Bus .
Вы можете найти исходный код этой статьи по адресу https://github.com/sivaprasadreddy/spring-boot-microservices-series
В следующей статье мы рассмотрим, как использовать Netflix Eureka для Service Registry и Service Discovery .
Опубликовано на Java Code Geeks с разрешения Сивы Редди, партнера нашей программы JCG . См. Оригинальную статью здесь: MicroServices. Часть 2. Управление конфигурацией с помощью Spring Cloud Config и Vault.
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |