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

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

Рассмотрим на примере. Допустим, что есть простое приложение с файлом конфигурации yaml. Это может быть любой микросервис на любом языке. Посмотрим, как фреймворк можно применить к этому сервису.

Но прежде, для большего удобства, создадим пустой проект в Idea IDE, предварительно установив в ней плагин microconfig.io:

image

Настраиваем конфигурацию запуска плагина, можно использовать конфигурацию по умолчанию, как на скриншоте сверху.

Наш сервис называется order, тогда в новом проекте создадим подобную структуру:



В папку с именем сервиса помещаем файл конфигурации — application.yaml. Все микросервисы запускаются в каком-то окружении, так что, кроме создания конфига самого сервиса, необходимо описать саму среду: для этого создадим папку envs и добавим в нее файл с именем нашей рабочей среды. Таким образом, фреймворк создаст конфигурационные файлы для сервисов в среде dev, так как в настройках в плагина установлен именно этот параметр.

Структура файла dev.yaml будет довольно простая:

mainorder:
    components:
         - order

Фреймворк работает с конфигурациями, которые объединены в группы. Для нашего сервиса выберем имя для группы mainorder. Фреймворк находит каждую такую группу приложений в файле окружений и создает для всех из них конфигурации, которые находит в соответствующих папках.

В самом файле настроек сервиса order укажем пока только один параметр:

spring.application.name: order

Теперь запустим плагин, и он сгенерирует нам нужную конфигурацию нашего сервиса по указанному в свойствах пути:



Можно обойтись и без установки плагина, просто скачав дистрибутив фреймворка и запустив его из командной строки.
Такое решение подойдет для использования на сервере сборки.

Стоит отметить, что фреймворк отлично понимает property синтаксис, то есть обычные property файлы, которые можно использовать вместе в yaml конфигурациями.

Добавим еще один сервис payment и усложним одновременно существующий.
В order:

eureka:
 instance.preferIpAddress: true
 client:
   serviceUrl:
     defaultZone: http://192.89.89.111:6782/eureka/
server.port: 9999
spring.application.name: order
db.url: 192.168.0.100

В payment:

eureka:
 instance.preferIpAddress: true
 client:
   serviceUrl:
     defaultZone: http://192.89.89.111:6782/eureka/
server.port: 9998
spring.application.name: payments
db.url: 192.168.0.100

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



И в каждый из наших проектов теперь добавим строку #include eureka.

Фреймворк автоматически сам найдет конфигурацию eureka и скопирует ее в конфигурационные файлы сервисов, при этом отдельная конфигурация eureka не будет создана, так как мы не укажем ее в файле среды dev.yaml. Сервис order:

#include eureka
server.port: 9999
spring.application.name: order
db.url: 192.168.0.100

Также мы можем вынести настройки базы данных в отдельную конфигурацию, изменив строку импорта на #include eureka, oracle.

Стоит отметить, что каждое изменение при перегенерации конфигурационных файлов фреймворк отслеживает и помещает в специальный файл рядом с основным файлом конфигурации. Запись в его логе выглядит так: “Stored 1 property changes to order/diff-application.yaml”. Это позволяет быстро обнаружить изменения в больших конфигурационных файлах.

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

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

 client:
   serviceUrl:
     defaultZone: http://${endpoints@eurekaip}:6782/eureka/

Теперь посмотрим, как работает этот плейсхолдер. Система находит компонент с именем endpoints и ищет в нем значение eurekaip, после чего подставляет в нашу конфигурацию. Но как быть с различными средами? Для этого создадим файл настроек в endpoints следующего вида application.dev.yaml. Фреймворк самостоятельно, по расширению файла принимает решение к какой среде относится данная конфигурация и подгружает ее:



Содержимое dev файла:

eurekaip: 192.89.89.111
dbip: 192.168.0.100

Такую же конфигурацию мы можем создать и для портов наших сервисов:

server.port: ${ports@order}.

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

Фреймворк предоставляет множество уже готовых плейсхолдеров, например, можно получить название директории, в которой находится файл конфигурации и присвоить его:

#include eureka, oracle
server.port: ${ports@order}
spring.application.name: ${this@name}

Благодаря этому, не нужно дополнительно указывать имя приложения в конфигурации и его можно также вынести в общий модуль, например, в ту же eureka:

client:
   serviceUrl:
     defaultZone: http://${endpoints@eurekaip}:6782/eureka/
 spring.application.name: ${this@name}

Файл конфигурации order сократится до одной строчки:

#include eureka, oracle
server.port: ${ports@order}

В случае, если какая-либо настройка из родительской конфигурации нам не нужна мы можем указать ее в нашей конфигурации и именно она будет применена при генерации. То есть если по какой-то причине нам нужно уникальное имя для сервиса order, просто оставим параметр spring.application.name.

Допустим, в сервис необходимо добавить кастомизированные настройки логирования, которые хранятся в отдельном файле, например, logback.xml. Создадим для него отдельную группу настроек:



В базовой конфигурации укажем фреймворку куда размещать нужный нам файл настроек логирования с помощью плейсхолдера @ConfigDir:

microconfig.template.logback.fromFile: ${logback@configDir}/logback.xml

В файле logback.xml настраиваем стандартные аппендеры, которые так же в свою очередь могут содержать плейсхолдеры, которые фреймворк изменит во время генерации конфигов, например:

<file>logs/${this@name}.log</file>

Добавляя в конфигурации сервисов импорт logback, мы автоматически получаем настроенное логирование для каждого сервиса:

#include eureka, oracle, logback
server.port: ${ports@order}

Настало время более подробно ознакомится со всеми доступными плейсхолдерами фреймворка:

${this@env} — возвращает имя текущей среды.
${...@name} — возвращает имя компонента.
${...@configDir} — возвращает полный путь к каталогу config компонента.
${...@resultDir} — возвращает полный путь к каталогу назначения компонента (полученные файлы будут помещены в этот каталог).
${this@configRoot} — возвращает полный путь к корневому каталогу хранилища конфигураций.

Также система позволяет получить переменные среды, например путь к java:
${env@JAVA_HOME}
Либо, так как фреймворк написан на JAVA, можем получить системные переменные аналогичные вызову System::getProperty с помощью конструкции такого вида:
${system@os.name}
Стоит упомянуть про поддержку языка расширений Spring EL. В конфигурации применимы подобные выражения:

connection.timeoutInMs: #{5 * 60 * 1000}
datasource.maximum-pool-size: #{${this@datasource.minimum-pool-size} + 10} 

и можно использовать локальные переменные в конфигурационных файлах с помощью выражения #var:

#var feedRoot: ${system@user.home}/feed
folder:
 root: ${this@feedRoot}
 success: ${this@feedRoot}/archive
 error: ${this@feedRoot}/error

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

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

Комментарии (0)