Меня зовут Дмитрий Демченко. Я главный разработчик (Java) в крупной российской строительной компании. На проектах мы активно используем новые технологии и подходы при разработке приложений, в том числе Spring Cloud и компоненты, входящие в общую экосистему этой технологии.
В данной статье я хочу поделиться с вами своим подходом к конфигурации Spring Boot приложений в облаке, где файлы конфигураций приложений находятся в Git репозитории, и который я применяю в работе и считаю одним из самых простых, удобных и легко поддерживаемых.
Плюсы и минусы данного подхода
Плюсы:
Работает из коробки
Легко настраивается
Версионирование в Git
Нет необходимости поднимать и обслуживать сторонние хранилища секретов
Минусы: по моему мнению очевидных минусов нет.
В рамках данной статьи я не буду затрагивать поднятие всего стека Spring Cloud, а расскажу лишь о примитивном применении Spring Cloud Config.
Выбор версии Java и Spring Boot
Многие проекты сейчас переписываются, а какие-то уже используют Java 17, поэтому и мы будем использовать Java 17 и Spring Boot 3.
Настройка Spring Cloud Config Server
Для начала нам нужно создать новый Spring Boot проект и подключить зависимость spring-cloud-config-server
Пример для Maven:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
Пример для Gradle:
implementation 'org.springframework.cloud:spring-cloud-config-server'
Далее нам нужно сконфигурировать сервис таким образом, чтобы он мог получать конфигурации наших Spring Boot приложений из нашего Git репозитория.
application.yml:
server:
port: 8888
spring:
application:
name: config-service
cloud:
config:
server:
git:
uri: git@github.com:dmitrii-demchenko/spring-boot-configs.git
username: username
password: password
default-label: main
search-paths: "{application}"
И добавить аннотацию @EnableConfigServer:
@SpringBootApplication
@EnableConfigServer
public class ConfigServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServiceApplication.class, args);
}
}
Репозиторий с конфигурациями приложений
Все конфигурации находятся в своих папках, где имя папки является именем приложения.
Представим, что у нас есть три приложения: clients, orders и couriers. Исходя из этого, структура нашего репозитория с конфигурациями будет выглядеть так:
Здесь можно увидеть 3 папки с конкретными конфигурациями наших приложений, а так же 2 общих файла: application.yml и application-dev.yml
Дело в том, что Spring Cloud Config позволяет объединять конфигурацию таким образом, чтобы мы могли избавиться от "копипаста" и не повторять общие свойства в каждом конфигурационном файле. А постфикс -dev
дает нам возможность задавать конфигурации для определенного профиля, с которым запускается приложение.
Посмотрим на содержимое этих файлов:
application.yml:
spring:
datasource:
driver-class-name: org.postgresql.Driver
jpa:
hibernate:
ddl-auto: validate
properties:
hibernate:
format_sql: true
show-sql: false
flyway:
enabled: true
application-dev.yml:
spring:
datasource:
hikari:
maximum-pool-size: 10
minimum-idle: 0
clients/application-dev.yml:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/clients
username: username
password: password
orders/application-dev.yml:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/orders
username: username
password: password
couriers/application-dev.yml:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/couriers
username: username
password: password
Получается, что, например, для приложения clients конфигурация должна выглядеть следующим образом:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/clients
username: username
password: password
driver-class-name: org.postgresql.Driver
hikari:
maximum-pool-size: 10
minimum-idle: 0
jpa:
hibernate:
ddl-auto: validate
properties:
hibernate:
format_sql: true
show-sql: false
flyway:
enabled: true
Запустим сервис конфигураций и проверим это.
Получение конфигурации (руками)
Выполнив запрос на эндпоинт http://localhost:8888/clients/dev получаем ответ:
{
"name": "clients",
"profiles": [
"dev"
],
"label": null,
"version": "2e6f884042d117b7298baa10955e5f1d0bf8f6f2",
"state": null,
"propertySources": [
{
"name": "https://github.com/dmitrii-demchenko/spring-boot-configs.git/clients/application-dev.yml",
"source": {
"spring.datasource.url": "jdbc:postgresql://localhost:5432/clients",
"spring.datasource.username": "username",
"spring.datasource.password": "password"
}
},
{
"name": "https://github.com/dmitrii-demchenko/spring-boot-configs.git/application-dev.yml",
"source": {
"spring.datasource.hikari.maximum-pool-size": 10,
"spring.datasource.hikari.minimum-idle": 0
}
},
{
"name": "https://github.com/dmitrii-demchenko/spring-boot-configs.git/clients/application.yml",
"source": {
"spring.application.name": "clients"
}
},
{
"name": "https://github.com/dmitrii-demchenko/spring-boot-configs.git/application.yml",
"source": {
"spring.datasource.driver-class-name": "org.postgresql.Driver",
"spring.jpa.hibernate.ddl-auto": "validate",
"spring.jpa.properties.hibernate.format_sql": true,
"spring.jpa.show-sql": false,
"spring.flyway.enabled": true
}
}
]
}
Так убеждаемся, что приложение clients, запущенное с профилем dev получит необходимую конфигурацию.
Подключение сервиса конфигураций к приложению
Подключение зависимости spring-cloud-starter-config в приложении, которое будет получать конфигурацию от сервиса конфигураций.
Пример для Maven:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
Пример для Gradle:
implementation 'org.springframework.cloud:spring-cloud-starter-config'
Осталось описать application.yml:
spring:
application:
name: clients
---
spring:
config:
activate:
on-profile: dev
import: optional:configserver:http://localhost:8888
cloud:
config:
fail-fast: true
Пройдемся по основным свойствам.
Во-первых, нужно задать имя приложения таким образом, чтобы оно совпадало с именем папки в репозитории с конфигурациями. Это свойство spring.application.name
Во-вторых, нужно указать приложению откуда получать конфигурации, за это отвечает свойство spring.config.import
Так же, в своем примере я добавил следующие свойства:
spring.config.activte.on-profile: dev
для того, чтобы сказать приложению при запуске с каким профилем получать конфигурации. Можно указать множество профилей.spring.cloud.config.fail-fast: true
этот параметр задан для того, чтобы, если приложению не удалось получить конфигурацию, оно не будет запущено. Такой режим рекомендуется использовать в реальных проектах.
Запустим приложение с профилем dev и убедимся, что оно успешно получило конфигурацию от нашего сервиса конфигураций:
Но что делать, если нужно приложение запустить локально и без получения конфигураций от сервиса конфигураций?
Как пример, которым я пользуюсь, это добавить файл application-local.yml и запускать приложение с профилем local:
spring:
cloud:
config:
enabled: false
Резюме
Можно легко и быстро развернуть готовое и централизованное решение, которое будет сообщать приложениям в облаке их конфигурации. Это вполне рабочий вариант, который вы можете применять в своей работе.
Ссылки
Комментарии (5)
breninsul
29.09.2023 15:46А в чем преимущество по сравнению с переменными окружения?
Приложения же скорее-всего в контейнере с автодеплоем при обновлении docker-compose в репозитории?
Dmitrii_Demchenko Автор
29.09.2023 15:46В том, что у вас может быть несколько окружений - девелоперское, для тестирования, продакшен и т. д., и тут преимуществом будет централизация конфигов. К тому же конфиги часто разбухают и хранить все свойства в переменных окружения станет не удобно.
stgunholy
Пароли открытым текстом в репозитории лежат?
Dmitrii_Demchenko Автор
Все зависит от требований безопасности. Хранить пароли можно не только в репозитории. Можно как и в переменных окружения, так и в секретах, если это Kubernetes. От проекта к проекту по разному может быть.