Microservices mit Spring Cloud, Teil 3 Microservice-Konfiguration per Config Server

Von Dr. Dirk Koller

Der Betrieb von Microservices hat allein schon wegen der Masse an verschiedenen Diensten seine eigenen Tücken. Eine zentralisierte Konfiguration mit dem Spring Config Server nimmt einem viel Arbeit ab.

Anbieter zum Thema

Erforderliche Abhängigkeiten zum Erstellen des Config-Servers.
Erforderliche Abhängigkeiten zum Erstellen des Config-Servers.
(Bild: Dr. Koller / Spring.io)

In Spring Boot-Anwendungen wird die Konfiguration getrennt vom Code in den Dateien application.properties oder application.yml aufbewahrt; im Normalfall werden sie dann aber trotzdem zusammen in einer Jar-Datei paketiert. Im Microservices-Umfeld kann das schnell zum Problem ausarten.

Oft hat man es mit sehr vielen Services zu tun. Jeder Service liegt womöglich in mehreren Instanzen und für verschiedene Umgebungen vor. Bei Änderungen an der Konfiguration müssten alle Instanzen neu deployt werden. Eine Lösung für dieses Problem ist die Verwaltung der Konfigurationen mit einem separaten Server.

Wir vertrauen dabei in unserem Beispiel auf den Spring Config Server. Dieser bezieht die Key/Value-Paare aus einem Git-Repository oder einer Datenbank und stellt sie die den vorhandenen Diensten über HTTP zur Verfügung – im besten Fall ohne Neustart der Services bei Änderung eines Wertes.

Anlegen des Repositories

In diesem Beitrag kommen die Daten aus Gründen der einfachen Nachvollziehbarkeit aus einem lokalen Git-Repository, das die Properties-Files enthält. Eine Umstellung auf ein Remote-Repo ist aber kein Problem. Das Repository wird angelegt, indem ein neuer Ordner erstellt und darin git init aufgerufen wird:

mkdir config-repo
cd config-repo
git init

Anschließend wird in dem neuen Ordner eine Properties-Datei erstellt und mit einem Key-Value-Paar zum Testen versehen. Der Name der Properties-Datei entspricht dabei dem Namen des Client-Services. Hier werden Properties für einen Client namens config-server-client angelegt, die Datei heißt deshalb config-server-client.properties. Darin enthalten ist eine einfache Property namens message:

message=Hello from config server

Die Datei wird dem Git-Repository zugefügt und committet:

git add .
git commit -m "inital config"

Erstellen des Config-Servers

Erforderliche Abhängigkeiten zum Erstellen des Config-Servers.
Erforderliche Abhängigkeiten zum Erstellen des Config-Servers.
(Bild: Dr. Koller / Spring.io)

Der Server selbst wird erstellt, indem einem neuen Spring-Boot-Projekt zum Beispiel in STS oder mithilfe des Initializr neben Spring Web die DependencyConfig Server“ zugefügt wird. Die Klasse mit der main-Methode erhält die Annotation _@EnableConfigServer_:

@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {
  public static void main(String[] args) {
    SpringApplication.run(ConfigServerApplication.class, args);
  }
}

Schließlich ist noch die Konfigurationsdatei application.properties des neu erstellten Server-Projekts anzupassen. Hier wird der Port auf den für Config-Server üblichen Wert 8888 eingestellt, der Name für die Anwendung vergeben und der Pfad zum Git-Repository beschrieben. Wer macOS oder Linux nutzt, braucht bei der Angabe des Pfades nach file: lediglich zwei Slashes:

server.port=8888
spring.application.name=config-server
spring.cloud.config.server.git.uri=file:///C:/Users/dirkk/projekte/config-server-repo

Der Server kann danach gestartet werden. Die URL, unter der die Properties erreichbar sind, ergibt sich aus Host, Port, Name der Properties-Datei und Umgebung. Ein Aufruf http://localhost:8888/config-server-client/default im Browser führt zu folgender JSON-Antwort:

{
  "name": "config-server-client",
  "profiles": [
    "default"
  ],
  "label": null,
  "version": "28c5801cdab7f1e42ddfc63f792858586ab0599d",
  "state": null,
  "propertySources": [
    {
      "name": "file:///C:/Users/dirkk/projekte/config-server-repo/file:C:\\Users\\dirkk\\projekte\\config-server-repo\\config-server-client.properties",
      "source": {
        "message": "Hello from config server"
      }
    }
  ]
}

Erscheint die Ausgabe, dann ist der Config-Server funktionsbereit.

Anlegen des Config-Server-Client

Die Daten werden im Normalfall nicht vom Browser abgerufen, sondern von einem Service, der als Client des Config-Servers fungiert. Auch er wird als Spring Boot-Anwendung zum Beispiel mit dem Initializr angelegt. Erforderlich sind die Abhängigkeiten Spring Web und Config Client.

Der Service erhält in application.properties einen Namen und bei Bedarf einen vom Default-Wert abweichenden Port. Ein vorhandener Config-Server wird seit Spring Boot 2.4 mithilfe der Property spring.config.import angegeben. Das sieht beispielsweise so aus:

spring.application.name=config-server-client
server.port=8080
spring.config.import=optional:configserver:

Diese Anpassungen genügen im einfachsten Fall bereits, der Service bezieht eine (hier optionale) Konfiguration vom Config-Server auf localhost und Default-Port 8888. Um das auszuprobieren, wird hier eine Methode angelegt, die die Property message als String zurückgibt:

@SpringBootApplication
@RestController
public class ConfigServerClientApplication {

  @Value("${message}")
  private String message;

  public static void main(String[] args) {
    SpringApplication.run(ConfigServerClientApplication.class, args);
  }

  @GetMapping("/")
  public String getMessage() {
    return message;
  }

Ein Aufruf des Dienstes im Browser unter http://localhost:8080 bringt die vom Config-Server ausgelieferte Property aus dem Repository zur Anzeige. Im Normalfall wird man Host und Port des Config-Server konfigurieren wollen:

Jetzt Newsletter abonnieren

Täglich die wichtigsten Infos zu Softwareentwicklung und DevOps

Mit Klick auf „Newsletter abonnieren“ erkläre ich mich mit der Verarbeitung und Nutzung meiner Daten gemäß Einwilligungserklärung (bitte aufklappen für Details) einverstanden und akzeptiere die Nutzungsbedingungen. Weitere Informationen finde ich in unserer Datenschutzerklärung.

Aufklappen für Details zu Ihrer Einwilligung
spring.config.import=optional:configserver:http://myhost:8888

Lässt man „optional:“ weg, ist eine Verbindung zum Config-Server auf jeden Fall erforderlich.

Änderungen zur Laufzeit

Ändert man nun den Wert in der Properties-Datei im Repo, kann man mit http://localhost:8888/config-server-client/default überprüfen, dass der Config-Server die Änderung auswertet. Der Client dagegen bekommt die Änderung erst nach einem Neustart mit.

Das ist nicht ganz optimal, lässt sich aber beheben. Dazu wird im Client-Projekt zunächst das Actuator-Framework mit Hilfe der Dependency „Spring Boot Actuator“ zugefügt und in application.properties der Endpunkt refresh verfügbar gemacht:

management.endpoints.web.exposure.include=refresh

Außerdem wird die Klasse mit der zu aktualisierenden Variable mit @RefreshScope annotiert:

@SpringBootApplication
@RestController
@RefreshScope
public class ConfigServerClientApplication {
  ...
}

Beim Neustart des Service sollte im Log der Eintrag “Exposing 1 endpoint(s) beneath base path ‘/actuator’” auftauchen. Nun kann man mit Hilfe eines POST-Requests den Actuator-Endpunkt refresh aufrufen. Das geht zum Beispiel mit Postman oder wie hier gezeigt mit curl:

curl --location --request POST 'http://localhost:8080/actuator/refresh' \
--header 'Content-Type: application/json' \
--data-raw '{}'

Der Client sieht dann ohne Neustart eine zur Laufzeit geänderte Property. Der Beitrag hat nur die grundlegende Funktion des Config-Servers demonstriert, es gibt eine Menge mehr zu entdecken. Weitere Informationen finden sich in der Spring-Dokumentation zum Spring Cloud Config Server.

(ID:47835839)