Microservices mit Spring Boot und Docker erstellen – Teil 1

Gastbeitrag von | 30.05.2018

In diesem Tutorial erfahren Sie, wie Sie Microservices mithilfe von Spring Boot und seinen verschiedenen Komponenten erstellen und mit Docker-Containern bereitstellen.

Wesentliche Komponenten

Bevor wir anfangen, möchte ich auf die wichtigsten Komponenten der Microservice-Architektur eingehen. Bei der Implementierung von Microservices sind die folgenden Komponenten wesentlich für die Architektur:

1. Konfigurationsserver

Zu Beginn erstellen wir einen Konfiguationsserver, der selbst ein Microservice ist. Der Konfigurationsserver verwaltet und versioniert alle Microservices-Eigenschaftsdateien, die in der Folge von allen Microservices gemeinsam genutzt werden. Jede Änderung einer Eigenschaft soll automatisch auf allen Microservices veröffentlicht werden, ohne die Dienste neu zu starten zu müssen. Für diese Form der Kommunikation der Microservices ist ein hoch verfügbarer Konfigurationsserver unverzichtbar, denn sobald die Kommunikation fehlschlägt und sich die Eigenschaftswerte nicht bestimmen lassen, scheitern alle Microservices. Aus diesem Grund sollte der Konfigurationsserver keinen Single Point of Failure darstellen. Zur Sicherheit empfiehlt sich daher die Verwendung mehrerer Container für den Konfigurationsserver.

2. Eureka-Discovery-Server

Das Hauptziel von Microservices ist die Dezentralisierung der verschiedenen Komponenten basierend auf Geschäftsfunktionen, so dass jede Komponente – also jeder Microservice – nach Bedarf skaliert werden kann. Für einen bestimmten Microservice gibt es mehrere Instanzen. Neue Instanzen lassen sich nach Bedarf hinzufügen und entsprechend entfernen. Services, die im laufenden Betrieb erzeugt werden, erhalten dynamische IP-Adressen. Um alle Instanzen im Blick zu behalten, benötigen Sie einen Manager-Dienst. Wird ein Service generiert, registriert er sich bei diesem Dienst. Wird ein Service entfernt, löscht der Manager-Dienst ihn aus der Registry. Kommunizieren verschiedene Dienste miteinander, kontaktieren diese einen Erkennungsdienst, um die Instanz eines anderen Dienstes abzurufen. Auch der Erkennungsdienst muss hoch verfügbar sein, denn bei Inaktivität scheitert die Kommunikation der Microservices. Zur Sicherheit sollte der Erkennungsdienst mehrere Instanzen besitzen.

3. Komponenten aka Services

Komponenten sind die wichtigsten Bestandteile der Microservice-Architektur. Unter Komponente verstehe ich ein Dienstprogramm oder eine Geschäftsfunktion, die unabhängig verwaltet oder aktualisiert werden kann. Sie hat eine vordefinierte Grenze und stellt eine API zur Verfügung, über die andere Komponenten mit diesem Dienst kommunizieren können. Die Idee von Microservices besteht darin, eine vollständige Geschäftsfunktionalität in mehrere unabhängige kleine Funktionen aufzuteilen, die miteinander kommunizieren, um die gesamte Geschäftsfunktionalität zu erzeugen. Wenn sich ein Teil der Funktionalität in der Zukunft ändert, können wir diese Komponente aktualisieren oder entfernen und der Architektur eine neue Komponente hinzufügen. Die Microservice-Architektur erzeugt also eine geeignete modulare Architektur mit einer Kapselung und ordnungsgemäß definierten Grenzen.

4. Gateway-Service

Ein Microservice ist eine Sammlung von unabhängigen Services, die zusammen eine Geschäftsfunktionalität erzeugen. Jeder Microservice veröffentlicht eine API, im Allgemeinen eine REST-API, so dass es als Client mühsam ist, so viele Endpunkt-URLs zu verwalten, mit denen kommuniziert werden kann. Wenn eine Anwendung ein Authentifizierungsframework oder eine Sicherheitsüberprüfung erstellen möchte, muss sie über alle Services hinweg implementiert werden. Wenn wir einen Gateway-Dienst haben, der mit dem Internet verbunden ist, ruft der Client nur einen Endpunkt auf und delegiert den Anruf an einen tatsächlichen Microservice, und alle Authentifizierungs- oder Sicherheitsprüfungen werden im Gateway-Dienst durchgeführt.

Unser Microservice-Projekt

Jetzt haben wir ein grundlegendes Verständnis dafür, wie verschiedene Teile eines Microservice zusammenarbeiten. In diesem Tutorial werde ich einen Mitarbeiter-Suchdienst erstellen, der Mitarbeiterinformationen zurückgibt, einen Mitarbeiter-Dashboard-Dienst, der den Suchdienst aufruft und die Ergebnisse anzeigt, einen Eureka-Server, bei dem sich diese Dienste selbst registrieren können, und einen Gateway-Service, auf den Services zugreifen können. Dann werden wir unsere Dienste im Andock-Container bereitstellen und DockerCompose verwenden, um die Docker-Container zu erstellen. Für das Tutorial verwende ich Spring Boot.

Microservice Architecture

Beginnen wir mit dem Aufbau unseres Microservice-Projekts, für das wir fünf einzelne Services erstellen müssen:

  1. Konfigurationsserver
  2. Eureka-Server
  3. Mitarbeiterservice
  4. Mitarbeiter-Dashboard-Dienst
  5. Zuul Proxy

Ein guter Ort zum Starten is http://start.spring.io/. Dort können Sie erforderliche Module erwerben und anschließend Ihr “Generate Project” (Projekt generieren).

Spring Initializer

Für dieses Tutorial verwenden wir Spring Boot 1.5.4.

Erstellen des Konfigurationsservers

Um den Konfigurationsserver zu erstellen, müssen wir zunächst das Config-Server-Modul von starts.spring.io überprüfen und den Aktuator prüfen, um die Endpunkte zu sehen. Laden Sie dann die Zip-Datei herunter und öffnen Sie sie in Eclipse. Die Pom-Datei sieht folgendermaßen aus:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.example</groupId>
   <artifactId>MicroserviceConfigServer</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>
   <name>MicroserviceConfigServer</name>
   <description>Demo project for Spring Boot</description>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>1.5.4.RELEASE</version>
      <relativePath />
      <!-- lookup parent from repository -->
   </parent>
   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <java.version>1.8</java.version>
      <spring-cloud.version>Dalston.SR1</spring-cloud.version>
   </properties>
   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-actuator</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-config-server</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>
   <dependencyManagement>
      <dependencies>
         <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
         </dependency>
      </dependencies>
   </dependencyManagement>
   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>
</project>

Es lädt die Spring-Cloud-Config-Server-Artefakte herunter. Als nächstes müssen wir eine bootstrap.properties-Datei erstellen, in der wir angeben, von welchem Ort der Konfigurationsserver die Eigenschaft liest. Im Produktionsmodus sollte es die URL des Git-Repositorys sein, aber da es sich um eine Demo handelt, verwende ich meine lokale Festplatte. Alle Eigenschaftsdateien werden dort platziert und vom Konfigurationsserver gelesen. Sehen wir uns die Datei bootstrap.properties an:

server.port=9090
spring.cloud.config.server.native.searchLocations=file://${user.home}/MicroService/centralProperties/
SPRING_PROFILES_ACTIVE=native

Hier beauftrage ich Spring Boot, den eingebetteten Server in Port 9090 zu erzeugen und einen centralProperties-Ordner zu verwenden, um alle Eigenschaftsdateien zu durchsuchen. Beachten Sie, dass Sie in unserem Docker-Container einen zentralen Eigenschaftsordner erstellen und alle Eigenschaftsdateien dort platzieren müssen. Jetzt sehen wir uns den Java-Teil an:

package com.example.MicroserviceConfigServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@EnableConfigServer
@SpringBootApplication
public class ConfigServer {
 public static void main(String[] args) {
  SpringApplication.run(ConfigServer.class, args);
 }
}

Hier verwende ich die Annotation @EnableConfigserver, mit der wir Spring Boot anweisen, diesen Dienst als eine Konfigurationsserveranwendung zu betrachten. Platzieren Sie nun einige Testeigenschaftendateien im Ordner “centralProperties”. Der Konfigurationsserver ist nun erstellt. Wenn wir diesen Dienst ausführen und die URL http://localhost:9090/config/default aufrufen, erhalten wir folgende Antwort:

{
   "name": "config",
   "profiles": [
      "default"
   ],
   "label": null,
   "version": null,
   "state": null,
   "propertySources": [
      {
         "name": "file:///home/shamik/MicroService/centralProperties/config.properties",
         "source": {
            "application.message": "Hello Shamik"
         }
      },
      {
         "name": "file:///home/shamik/MicroService/centralProperties/application.properties",
         "source": {
            "welcome.message": "Hello Spring Cloud"
         }
      }
   ]
}

Sie erhalten alle Dateinamen, Schlüssel und Werte, die ich im Ordner “centralProperties” abgelegt habe. Der nächste Schritt besteht darin, einen Eureka-Server für die Serviceerkennung zu erstellen.

Implementieren der Serviceerkennung

Wir werden Netflix’s Eureka-Server zur Serviceerkennung verwenden. Dazu wähle ich das Eureka-Server-Modul von start.spring.io und lade das Projekt herunter.Die pom.xml sieht folgendermaßen aus:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.example</groupId>
   <artifactId>EmployeeEurekaServer</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>
   <name>EmployeeEurekaServer</name>
   <description>Demo project for Spring Boot</description>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>1.5.4.RELEASE</version>
      <relativePath />
      <!-- lookup parent from repository -->
   </parent>
   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <java.version>1.8</java.version>
      <spring-cloud.version>Dalston.SR1</spring-cloud.version>
   </properties>
   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-actuator</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-config</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-eureka-server</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>
   <dependencyManagement>
      <dependencies>
         <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
         </dependency>
      </dependencies>
   </dependencyManagement>
   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>
</project>

Erstellen Sie nun die bootstrap.properties:

spring.application.name=EmployeeEurekaServer
eureka.client.serviceUrl.defaultZone:http://localhost:9091/
server.port=9091
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

Erstellen Sie nun die bootstrap.properties: Ich verwende den logischen Namen EmployeeEurekaServer für diese Anwendung und http://localhost:9091 als Speicherort. Bitte beachten Sie, dass der Eureka-Server selbst ein Eureka-Client sein kann. Da es mehrere Instanzen von Eureka-Servern geben kann, muss eine entsprechende Synchronisation stattfinden. Mit diesem eureka.client.register-with-eureka = false weise ich Spring Boot ausdrücklich an, den Eureka-Server nicht als Client zu behandeln, da ich nur einen Eureka-Server erstellt habe, so dass es nicht erforderlich ist, sich selbst als Client zu registrieren. Jetzt können Sie die Java-Datei erstellen:

package com.example.EmployeeEurekaServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class EmployeeEurekaServerApplication {
 public static void main(String[] args) {
  SpringApplication.run(EmployeeEurekaServerApplication.class, args);
 }
}

Mit der Annotation @EnableEurekaServer erstellt Spring Boot diesen Service als Eureka-Server. Nun ist es soweit :wenn ich den Dienst starte und http://localhost:9091/ aufrufe, erscheint folgender Bildschirm:

Eureka
In Teil 2 erstellen wir die Mitarbeitersuche und stellen die Microservices mit Docker bereit. Hier finden Sie Teil 2.

 

Hinweise:

Interessieren Sie sich für weitere Tipps aus der Praxis? Testen Sie unseren wöchentlichen Newsletter mit interessanten Beiträgen, Downloads, Empfehlungen und aktuellem Wissen.

Der Beitrag von Shamik Mitra ist im Original unter https://dzone.com/articles/buiding-microservice-using-springboot-and-docker erschienen. Dort finden Sie auch die verschiedenen Code-Schnipsel als Kopiervorlage. Mit Zustimmung von Shamik Mitra übersetzen wir verschiedene Beiträge von ihm hier in unserem Blog vom Englischen ins Deutsche.

Shamik Mitra
Shamik Mitra

Shamik Mitra ist ein selbsternannter Java Maniac. Er arbeitet als technischer Projektmanager bei Tata Consultancy Services (TCS), und war zuvor bei Cognizant als Architekt und bei IBM als technischer Leiter aktiv. Er ist der Most Valuable Blogger bei DZone und Techathon Coding Competition Jury Award Winner. Er veröffentlicht regelmäßig Tutorials bei A4Academics und er ist technischer Reviewer bei PACKT Publication. Auf vielen dieser Plattformen teilt er sein Wissen zu Java, Java EE, Hibernate, Spring, Entwurfsmuster, Micro-Service, Bigdata und Agile.