Łatwe zarządzanie konfiguracjami mikrousług dzięki microconfig.io

Jednym z głównych problemów przy tworzeniu i późniejszym użytkowaniu mikrousług jest prawidłowe i staranne skonfigurowanie ich instancji. W moim zdaniem może w tym pomóc nowy framework microconfig.io. Umożliwia on dość eleganckie rozwiązanie niektórych rutynowych zadań konfiguracyjnych aplikacji.

Jeśli masz wiele mikrousług, a każda z nich dostarczana jest z własnym plikiem lub plikami konfiguracyjnymi, to istnieje duże prawdopodobieństwo popełnienia błędu w jednym z nich, który bez odpowiedniego doświadczenia i systemu logowania może być bardzo trudno rozpoznać. Głównym zadaniem, jakie stawia przed sobą framework, jest zminimalizowanie duplikujących się parametrów konfiguracji instancji, tym samym zmniejszając prawdopodobieństwo wprowadzenia błędu.

Przyjrzyjmy się na przykładzie. Powiedzmy, że jest prosta aplikacja z plikiem konfiguracyjnym yaml. Może to być dowolna mikrousługa w dowolnym języku. Zobaczmy, jak można zastosować framework w tej usłudze.

Ale najpierw, dla większej wygody, stworzymy pusty projekt w Idea IDE, wcześniej instalując w niej wtyczkę microconfig.io:

Łatwe zarządzanie konfiguracjami mikrousług dzięki microconfig.io

Konfigurujemy konfigurację uruchamiania wtyczki, można użyć konfiguracji domyślnej, jak na powyższym zrzucie ekranu.

Nasza usługa nosi nazwę order, więc w nowym projekcie stworzymy podobną strukturę:

Łatwe zarządzanie konfiguracjami mikrousług dzięki microconfig.io

Do folderu o nazwie usługi umieszczamy plik konfiguracyjny — application.yaml. Wszystkie mikrousługi uruchamiane są w jakimś środowisku, więc oprócz stworzenia konfiguracji samej usługi, należy opisać samo środowisko: w tym celu stworzymy folder envs i dodamy do niego plik o nazwie naszego środowiska roboczego. Dzięki temu framework stworzy pliki konfiguracyjne dla usług w środowisku dev, ponieważ w ustawieniach wtyczki właśnie ten parametr został ustawiony.

Struktura pliku dev.yaml będzie dość prosty:

mainorder:
    components:
         - order

Framework pracuje z konfiguracjami, które są grupowane. Dla naszej usługi wybierzemy nazwę grupy mainorder. Framework znajduje każdą taką grupę aplikacji w pliku środowisk i tworzy dla wszystkich z nich konfiguracje, które znajduje w odpowiednich folderach.

W samym pliku konfiguracyjnym usługi order podamy na razie tylko jeden parametr:

spring.application.name: order

Teraz uruchamiamy wtyczkę, a ona wygeneruje nam potrzebną konfigurację naszej usługi zgodnie z podaną w właściwościach ścieżką:

Łatwe zarządzanie konfiguracjami mikrousług dzięki microconfig.io

Można obejść się i bez instalacji wtyczki, wystarczy pobrać dystrybucję frameworka i uruchomić go z linii poleceń.
Takie rozwiązanie będzie odpowiednie do użycia na serwerze build.

Warto zauważyć, że framework doskonale rozumie property synchronizacja, czyli zwykłe pliki property, które można używać razem z yaml konfiguracjami.

Dodajmy jeszcze jedną usługę payment i jednocześnie skomplikuje istniejącą.
W 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

W 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

Głównym problemem tych konfiguracji jest duża ilość kopiowania i wklejania w ustawieniach usług. Zobaczmy, jak framework pomoże się tego pozbyć. Zacznijmy od najbardziej oczywistej — obecności konfiguracji eureka w opisie każdego mikroserwisu. Utworzymy nowy katalog z plikiem konfiguracyjnym i dodamy do niego nową konfigurację:

Łatwe zarządzanie konfiguracjami mikrousług dzięki microconfig.io

I w każdym z naszych projektów teraz dodamy linię #include eureka.

Framework automatycznie znajdzie konfigurację eureka i skopiuje ją do plików konfiguracyjnych usług, przy czym osobna konfiguracja eureka nie zostanie utworzona, ponieważ nie wskażemy jej w pliku środowiska dev.yaml. Usługa order:

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

Możemy również przenieść ustawienia bazy danych do osobnej konfiguracji, zmieniając linię importu na #include eureka, oracle.

Warto zauważyć, że każda zmiana podczas regeneracji plików konfiguracyjnych jest śledzona przez framework i umieszczana w specjalnym pliku obok głównego pliku konfiguracyjnego. Zapis w jego dzienniku wygląda tak: “Zapisano 1 zmianę właściwości do order/diff-application.yaml”. To pozwala szybko zidentyfikować zmiany w dużych plikach konfiguracyjnych.

Wydzielenie wspólnych części konfiguracji pozwala pozbyć się wielu niepotrzebnych powtórzeń, ale nie umożliwia elastycznego tworzenia konfiguracji dla różnych środowisk — punkty końcowe naszych usług są jedyne i zakodowane na stałe, co jest złe. Spróbujmy to usunąć.

Dobre rozwiązanie to trzymanie wszystkich punktów końcowych w jednej konfiguracji, do której mogłyby odnosić się pozostałe. Do tego framework wprowadza wsparcie dla placeholderów. Oto jak zmieni się plik konfiguracyjny eureka:

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

Teraz zobaczmy, jak działa ten placeholder. System znajduje komponent o nazwie endpoints i szuka w nim wartości eurekaip, po czym wprowadza do naszej konfiguracji. Co w przypadku różnych środowisk? W tym celu utworzymy plik konfiguracyjny w endpoints następującym formacie application.dev.yaml. Framework automatycznie, na podstawie rozszerzenia pliku, decyduje, do którego środowiska należy ta konfiguracja i ładuje ją:

Łatwe zarządzanie konfiguracjami mikrousług dzięki microconfig.io

Zawartość pliku dev:

eurekaip: 192.89.89.111
dbip: 192.168.0.100

Podobną konfigurację możemy stworzyć dla portów naszych usług:

server.port: ${ports@order}.

Wszystkie istotne ustawienia znajdują się w jednym miejscu, co zmniejsza ryzyko błędów spowodowanych rozproszonymi parametrami w plikach konfiguracyjnych.

Framework oferuje wiele gotowych placeholderów, na przykład możemy uzyskać nazwę katalogu, w którym znajduje się plik konfiguracyjny i przypisać ją:

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

Dzięki temu nie trzeba dodatkowo podawać nazwy aplikacji w konfiguracji, można ją również przenieść do wspólnego modułu, na przykład do eureka:

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

Plik konfiguracyjny order skróci się do jednej linii:

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

W przypadku, gdy jakiekolwiek ustawienie z nadrzędnej konfiguracji jest nam niepotrzebne, możemy je określić w naszej konfiguracji, a to właśnie ono będzie zastosowane podczas generacji. To znaczy, jeśli z jakiegoś powodu potrzebujemy unikalnej nazwy dla usługi order, po prostu zostawiamy parametr spring.application.name.

Załóżmy, że do usługi należy dodać dostosowane ustawienia logowania, które są przechowywane w osobnym pliku, na przykład logback.xml. Stworzymy dla niego oddzielną grupę ustawień:

Łatwe zarządzanie konfiguracjami mikrousług dzięki microconfig.io

W bazowej konfiguracji wskażemy frameworkowi, gdzie umieścić potrzebny plik ustawień logowania za pomocą placeholdera @ConfigDir:

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

W pliku logback.xml konfigurujemy standardowe appendery, które również mogą zawierać placeholdery, które framework zmieni podczas generacji konfiguracji, na przykład:

logs/${this@name}.log

Dodając do konfiguracji usług import logback, automatycznie uzyskujemy skonfigurowane logowanie dla każdej usługi:

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

Nadszedł czas, aby bliżej zapoznać się ze wszystkimi dostępnymi placeholderami frameworka:

${this@env} — zwraca nazwę bieżącego środowiska.
${…@name} — zwraca nazwę komponentu.
${…@configDir} — zwraca pełną ścieżkę do katalogu config komponentu.
${…@resultDir} — zwraca pełną ścieżkę do katalogu docelowego komponentu (otrzymane pliki będą umieszczone w tym katalogu).
${this@configRoot} — zwraca pełną ścieżkę do głównego katalogu magazynu konfiguracji.

System pozwala również uzyskać zmienne środowiskowe, na przykład ścieżkę do java:
${env@JAVA_HOME}
Albo, ponieważ framework jest napisany w JAVA, możemy uzyskać zmienne systemowe analogicznie do wywołania System::getProperty z użyciem konstrukcji takiego typu:
${system@os.name}
Warto wspomnieć o wsparciu dla języka rozszerzeń Spring EL. W konfiguracji stosowane są podobne wyrażenia:

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

i można wykorzystać lokalne zmienne w plikach konfiguracyjnych za pomocą wyrażenia. #var:

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

Tak więc, framework stanowi dość potężne narzędzie do precyzyjnego i elastycznego dostosowywania konfiguracji mikroserwisów. Doskonale spełnia swoją podstawową rolę — eliminację kopiowania i wklejania w ustawieniach, konsolidację ustawień i w rezultacie minimalizację możliwości błędów, jednocześnie umożliwiając łatwe łączenie konfiguracji i dostosowywanie ich do różnych środowisk.

Jeżeli zainteresował Cię ten framework, polecam odwiedzenie jego oficjalnej strony oraz zapoznanie się z pełną dokumentacją, albo przeszukać źródła. tutaj.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster