Eine der Hauptprobleme bei der Entwicklung und dem anschließenden Betrieb von Mikrodiensten ist die ordnungsgemäße und sorgfältige Konfiguration ihrer Instanzen. Ich glaube, dass ein neues Framework dabei helfen kann, . Es ermöglicht eine recht elegante Lösung einiger Routineaufgaben bei der Konfiguration von Anwendungen.
Wenn Sie viele Mikrodienste haben und jeder von ihnen mit seiner eigenen Konfigurationsdatei/-dateien kommt, besteht eine hohe Wahrscheinlichkeit, einen Fehler in einer dieser Dateien zu machen, den man ohne entsprechendes Geschick und ein Logging-System nur schwer finden kann. Die Hauptaufgabe des Frameworks besteht darin, doppelte Konfigurationsparameter zu minimieren, um so die Wahrscheinlichkeit von Fehlern zu verringern.
Betrachten wir ein Beispiel. Angenommen, es gibt eine einfache Anwendung mit einer Konfigurationsdatei yaml. Dies könnte jeder Mikrodienst in jeder Sprache sein. Schauen wir uns an, wie das Framework auf diesen Dienst angewendet werden kann.
Aber bevor wir beginnen, erstellen wir zu unserem Komfort ein leeres Projekt in der IDE Idea, nachdem wir das Plugin microconfig.io installiert haben:

Wir konfigurieren die Startkonfiguration des Plugins. Sie können die Standardkonfiguration wie im obigen Screenshot verwenden.
Unser Service heißt order, daher erstellen wir in dem neuen Projekt eine ähnliche Struktur:

In den Ordner mit dem Namen des Services legen wir die Konfigurationsdatei — application.yaml. Alle Mikrodienste laufen in einer bestimmten Umgebung, daher müssen wir neben der Erstellung der Konfiguration des Services auch die Umgebung beschreiben: dazu erstellen wir einen Ordner envs und fügen darin eine Datei mit dem Namen unserer Arbeitsumgebung hinzu. So erstellt das Framework die Konfigurationsdateien für die Services in der Umgebung dev, da in den Einstellungen des Plugins genau dieser Parameter festgelegt ist.
Die Struktur der Datei dev.yaml wird ziemlich einfach sein:
mainorder:
components:
- orderDas Framework arbeitet mit Konfigurationen, die in Gruppen zusammengefasst sind. Für unseren Service wählen wir einen Namen für die Gruppe mainorder. Das Framework findet jede solche Gruppe von Anwendungen in der Umgebungsdatei und erstellt für alle von ihnen die Konfigurationen, die in den entsprechenden Ordnern gefunden werden.
In der Konfigurationsdatei des Services order geben wir vorerst nur einen Parameter an:
spring.application.name: orderJetzt starten wir das Plugin, und es wird die benötigte Konfiguration unseres Dienstes nach dem im Eigenschaften angegebenen Pfad generieren:

Es ist möglich Diese Lösung ist für den Einsatz auf einem Build-Server geeignet.
Es ist zu beachten, dass das Framework den
property Syntax hervorragend versteht, das heißt, reguläre Property-Dateien, die man zusammen mit Konfigurationen verwenden kann. yaml Lassen Sie uns einen weiteren Dienst hinzufügen
payment und gleichzeitig den bestehenden Dienst komplexer gestalten. 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
In order:
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.100In und gleichzeitig den bestehenden Dienst komplexer gestalten.:
Das Hauptproblem dieser Konfigurationen ist die große Menge an Copy-Paste in den Diensteinrichtungen. Schauen wir uns an, wie das Framework dabei helfen kann, dies zu vermeiden. Beginnen wir mit dem offensichtlichsten – der Notwendigkeit einer Konfiguration voneureka in der Beschreibung jedes Microservices. Erstellen wir ein neues Verzeichnis mit einer Einstellungsdatei und fügen wir eine neue Konfiguration hinzu: Und fügen wir nun in jedes unserer Projekte die Zeile hinzu

Und in jedes unserer Projekte fügen wir jetzt eine Zeile hinzu #include eureka.
Das Framework findet automatisch die Eureka-Konfiguration und kopiert sie in die Konfigurationsdateien der Dienste, wobei keine separate Eureka-Konfiguration erstellt wird, da wir sie nicht in der Umgebungsdatei angeben. dev.yaml. Dienst order:
#include eureka
server.port: 9999
spring.application.name: order
db.url: 192.168.0.100Wir können auch die Datenbankeinstellungen in eine separate Konfiguration auslagern, indem wir die Importzeile in #include eureka, oracle.
Es ist erwähnenswert, dass das Framework bei der Neugenerierung der Konfigurationsdateien jede Änderung verfolgt und in eine spezielle Datei neben der Hauptkonfigurationsdatei schreibt. Der Eintrag in seinem Protokoll sieht folgendermaßen aus: „Speicherte 1 Eigenschaftsänderung in order/diff-application.yaml”. Dies ermöglicht eine schnelle Erkennung von Änderungen in großen Konfigurationsdateien.
Die Auslagerung allgemeiner Konfigurationsteile reduziert überflüssige Wiederholungen, ermöglicht jedoch keine flexible Erstellung von Konfigurationen für verschiedene Umgebungen – die Endpunkte unserer Dienste sind einzigartig und fest codiert, was negativ ist. Lassen Sie uns das beheben.
Eine gute Lösung wäre es, alle Endpunkte in einer einzigen Konfiguration zu halten, auf die die anderen verweisen können. Dafür wurde im Framework die Unterstützung von Platzhaltern implementiert. So wird sich die Konfigurationsdatei ändern. in der Beschreibung jedes Microservices. Erstellen wir ein neues Verzeichnis mit einer Einstellungsdatei und fügen wir eine neue Konfiguration hinzu::
client:
serviceUrl:
defaultZone: http://${endpoints@eurekaip}:6782/eureka/Schauen wir uns nun an, wie dieser Platzhalter funktioniert. Das System findet die Komponente mit dem Namen endpoints und sucht darin nach dem Wert eurekaip, danach wird dieser in unsere Konfiguration eingefügt. Aber wie gehen wir mit verschiedenen Umgebungen um? Dazu erstellen wir eine Einstellungsdatei im endpoints folgenden Format application.dev.yaml. Das Framework erkennt selbstständig anhand der Dateiendung, zu welcher Umgebung diese Konfiguration gehört und lädt sie:

Inhalt der dev-Datei:
eurekaip: 192.89.89.111
dbip: 192.168.0.100Eine ähnliche Konfiguration können wir auch für die Ports unserer Dienste erstellen:
server.port: ${ports@order}.Alle wichtigen Einstellungen sind an einem Ort, was die Wahrscheinlichkeit von Fehlern aufgrund verstreuter Parameter in den Konfigurationsdateien verringert.
Das Framework bietet zahlreiche bereits vorhandene Platzhalter, zum Beispiel kann man den Namen des Verzeichnisses, in dem sich die Konfigurationsdatei befindet, abrufen und ihm zuweisen:
#include eureka, oracle
server.port: ${ports@order}
spring.application.name: ${this@name}Dank dessen ist es nicht nötig, den Namen der Anwendung in der Konfiguration zusätzlich anzugeben, und er kann auch in ein gemeinsames Modul ausgelagert werden, zum Beispiel in dasselbe eureka:
client:
serviceUrl:
defaultZone: http://${endpoints@eurekaip}:6782/eureka/
spring.application.name: ${this@name}Konfigurationsdatei order wird auf eine Zeile reduziert:
#include eureka, oracle
server.port: ${ports@order}Falls wir eine Einstellung aus der übergeordneten Konfiguration nicht benötigen, können wir sie in unserer Konfiguration angeben, und genau diese wird bei der Generierung angewendet. Wenn wir aus einem bestimmten Grund einen einzigartigen Namen für den Dienst 'order' benötigen, lassen wir einfach den Parameter spring.application.name.
Angenommen, wir müssen benutzerdefinierte Protokollierungseinstellungen hinzufügen, die in einer separaten Datei gespeichert sind, zum Beispiel logback.xml. Wir erstellen eine eigene Gruppe von Einstellungen:

In der grundlegenden Konfiguration geben wir dem Framework an, wo es die benötigte Protokolldatei mit dem Platzhalter @ConfigDir:
microconfig.template.logback.fromFile: ${logback@configDir}/logback.xmlIn der Datei logback.xml konfigurieren Standard-Appender, die ebenfalls Platzhalter enthalten können, die das Framework während der Generierung der Konfigurationen ändert, zum Beispiel:
logs/${this@name}.logWenn wir in den Konfigurationen der Dienste importieren logback, erhalten wir automatisch eine konfigurierte Protokollierung für jeden Dienst:
#include eureka, oracle, logback
server.port: ${ports@order}Es ist an der Zeit, uns genauer mit allen verfügbaren Platzhaltern des Frameworks vertraut zu machen:
${this@env} — Gibt den Namen der aktuellen Umgebung zurück.
${…@name} — Gibt den Namen der Komponente zurück.
${…@configDir} — Gibt den vollständigen Pfad zum Konfigurationsverzeichnis der Komponente zurück.
${…@resultDir} — Gibt den vollständigen Pfad zum Zielverzeichnis der Komponente zurück (die erhaltenen Dateien werden in diesem Verzeichnis abgelegt).
${this@configRoot} — Gibt den vollständigen Pfad zum Stammverzeichnis der Konfigurationsspeicher zurück.
Das System ermöglicht auch den Zugriff auf Umgebungsvariablen, wie zum Beispiel den Pfad zu Java:
${env@JAVA_HOME}
Oder, da das Framework in JAVAgeschrieben ist, können wir Systemvariablen ähnlich dem Aufruf System::getProperty mithilfe einer solchen Struktur erhalten:
${system@os.name}
Es ist erwähnenswert, dass die Unterstützung der Erweiterungssprache Spring ELgegeben ist. In der Konfiguration sind solche Ausdrücke anwendbar:
connection.timeoutInMs: #{5 * 60 * 1000}
datasource.maximum-pool-size: #{${this@datasource.minimum-pool-size} + 10} und lokale Variablen können in Konfigurationsdateien mit Ausdrücken verwendet werden. #var:
#var feedRoot: ${system@user.home}/feed
folder:
root: ${this@feedRoot}
success: ${this@feedRoot}/archive
error: ${this@feedRoot}/errorDer Rahmen bietet ein leistungsstarkes Werkzeug für die präzise und flexible Anpassung von Mikrodiensten-Konfigurationen. Er erfüllt seine Hauptaufgabe ausgezeichnet — das Vermeiden von Kopien in den Einstellungen, die Konsolidierung von Konfigurationen und damit die Minimierung möglicher Fehler, während er gleichzeitig eine einfache Kombination und Anpassung der Konfigurationen für verschiedene Umgebungen ermöglicht.
Falls Sie an diesem Framework interessiert sind, empfehle ich Ihnen, dessen offizielle Seite zu besuchen und sich die vollständigen Informationen anzusehen. , oder die Quellcodes zu durchstöbern. .
Quelle: habr.com
