Andocken einer Spring Boot-Anwendung

Andocken einer Spring Boot-Anwendung

1. Überblick

In diesem Artikel konzentrieren wir uns darauf, wie Sie einSpring Boot Application andocken, um es in einer isolierten Umgebung auszuführen, a.k.a. container.

Außerdem zeigen wir, wie Sie eine Zusammensetzung von Containern erstellen, die voneinander abhängen und in einem virtuellen privaten Netzwerk miteinander verknüpft sind. Wir werden auch sehen, wie sie zusammen mit einzelnen Befehlen verwaltet werden können.

Beginnen wir mit der Erstellung eines Java-fähigen, leichtgewichtigen Basisimages mithttps://hub.docker.com//alpine/[_Alpine Linux].

2. Gemeinsames Basisbild

Wir werden das eigene Build-Dateiformat vonDocker’sverwenden: aDockerfile.

ADockerfile ist im Prinzip eine zeilenweise Batchdatei, die Befehle zum Erstellen eines Bildes enthält. Es ist nicht unbedingt erforderlich, diese Befehle in eine Datei einzufügen, da wir sie auch an die Befehlszeile übergeben können - eine Datei ist einfach bequemer.

Schreiben wir also unsere erstenDockerfile:

FROM alpine:edge
MAINTAINER example.com
RUN apk add --no-cache openjdk8
COPY files/UnlimitedJCEPolicyJDK8/* \
  /usr/lib/jvm/java-1.8-openjdk/jre/lib/security/
  • FROM: Das SchlüsselwortFROM weistDocker an, ein bestimmtes Bild mit seinem Tag als Build-Basis zu verwenden. Befindet sich dieses Image nicht in der lokalen Bibliothek, wird eine Online-Suche inDockerHub oder in einer anderen konfigurierten Remote-Registrierung durchgeführt

  • MAINTAINER: EinMAINTAINER ist normalerweise eine E-Mail-Adresse, die den Autor eines Bildes identifiziert

  • RUN: Mit dem BefehlRUN führen wir eine Shell-Befehlszeile im Zielsystem aus. Hier verwenden wirAlpine Linux’s Paketmanagerapk, um dieJava 8 OpenJDK zu installieren

  • COPY: Der letzte Befehl teiltDockerCOPY einige Dateien aus dem lokalen Dateisystem, insbesondere einen Unterordner des Erstellungsverzeichnisses, in das Image in einem bestimmten Pfad mit

REQUIREMENTS: Um das Tutorial erfolgreich auszuführen, müssen SieJava Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files vonOracle herunterladen. Extrahieren Sie einfach das heruntergeladene Archiv in einen lokalen Ordner mit dem Namen‘files'.

Um das Image endgültig zu erstellen und in der lokalen Bibliothek zu speichern, müssen wir Folgendes ausführen:

docker build --tag=alpine-java:base --rm=true .

NOTICE: Die Option–tag gibt dem Bild seinen Namen und–rm=true entfernt Zwischenbilder, nachdem es erfolgreich erstellt wurde. Das letzte Zeichen in diesem Shell-Befehl ist ein Punkt, der als Argument für das Build-Verzeichnis fungiert.

3. Dockerisieren Sie eine eigenständige Spring Boot-Anwendung

Als Beispiel für eine Anwendung, die wir andocken können, nehmen wir diespring-cloud-config/server von denspring cloud configuration tutorial. Als Vorbereitungsschritt müssen wir eine ausführbare JAR-Datei zusammenstellen und in das Build-Verzeichnis vonDockerkopieren:

tutorials $> cd spring-cloud-config/server
server    $> mvn package spring-boot:repackage
server    $> cp target/server-0.0.1-SNAPSHOT.jar \
               ../../spring-boot-docker/files/config-server.jar
server    $> cd ../../spring-boot-docker

Jetzt erstellen wir einDockerfile mit dem NamenDockerfile.server mit folgendem Inhalt:

FROM alpine-java:base
MAINTAINER example.com
COPY files/spring-cloud-config-server.jar /opt/spring-cloud/lib/
COPY files/spring-cloud-config-server-entrypoint.sh /opt/spring-cloud/bin/
ENV SPRING_APPLICATION_JSON= \
  '{"spring": {"cloud": {"config": {"server": \
  {"git": {"uri": "/var/lib/spring-cloud/config-repo", \
  "clone-on-start": true}}}}}}'
ENTRYPOINT ["/usr/bin/java"]
CMD ["-jar", "/opt/spring-cloud/lib/spring-cloud-config-server.jar"]
VOLUME /var/lib/spring-cloud/config-repo
EXPOSE 8888
  • FROM: Als Basis für unser Bild nehmen wir dieJava-fähigenAlpine Linux, die im vorherigen Abschnitt erstellt wurden

  • COPY: Wir lassenDocker unsere JAR-Datei in das Bild kopieren

  • ENV: Mit diesem Befehl können wir einige Umgebungsvariablen definieren, die von der im Container ausgeführten Anwendung berücksichtigt werden. Hier definieren wir ein angepasstesSpring Boot Application configuration, um es später an die jar-ausführbare Datei zu übergeben

  • ENTRYPOINT/CMD: This will be the executable to start when the container is booting. Wir müssen sie alsJSON-Array definieren, da wir für einige Anwendungsargumente einENTRYPOINT in Kombination mit einemCMD verwenden

  • VOLUME: Da unser Container in einer isolierten Umgebung ohne direkten Netzwerkzugriff ausgeführt wird, müssen wir einen Mountpoint-Platzhalter für unser Konfigurationsrepository definieren

  • EXPOSE: Hier teilen wirDocker mit, auf welchem ​​Port unsere Anwendung auflistet. Dieser Port wird beim Booten des Containers auf dem Host veröffentlicht

Um ein Bild aus unserenDockerfile zu erstellen, müssen wir‘docker build' wie zuvor ausführen:

$> docker build --file=Dockerfile.server \
     --tag=config-server:latest --rm=true .

Bevor wir jedoch einen Container aus unserem Image ausführen können, müssen wir ein Volume zum Mounten erstellen:

$> docker volume create --name=spring-cloud-config-repo

NOTICE: Während ein Container unveränderlich ist und nach dem Beenden der Anwendung nicht für ein Image festgeschrieben wird, bleiben die in einem Volume gespeicherten Daten über mehrere Container hinweg bestehen.

Endlich können wir den Container von unserem Bild aus ausführen:

$> docker run --name=config-server --publish=8888:8888 \
     --volume=spring-cloud-config-repo:/var/lib/spring-cloud/config-repo \
     config-server:latest
  • Zuerst müssen wir–name unseren Container. Wenn nicht, wird automatisch einer ausgewählt

  • Dann müssen wir–publish unseren exponierten Port (sieheDockerfile) zu einem Port auf unserem Host. Der Wert wird in der Form‘host-port:container-port' angegeben. Wenn nur ein Container-Port angegeben wird, wird ein zufällig ausgewählter Host-Port verwendet. Wenn wir diese Option auslassen, wird der Container vollständig isoliert

  • Die Option–volume ermöglicht den Zugriff entweder auf ein Verzeichnis auf dem Host (bei Verwendung mit einem absoluten Pfad) oder auf ein zuvor erstelltesDocker-Volume (bei Verwendung mitvolume-name). Der Pfad nach dem Doppelpunkt gibt diemountpoint im Container an

  • Als Argument müssen wirDocker mitteilen, welches Bild verwendet werden soll. Hier müssen wir dieimage-name aus dem vorherigen Schritt 'docker build' angeben

  • Einige weitere nützliche Optionen:

    • -it - Aktivieren Sie den interaktiven Modus und weisen Siepseudo-tty zu

    • -d - Nach dem Booten vom Container abnehmen

Wenn wir den Container im getrennten Modus ausgeführt haben, können wir seine Details überprüfen, ihn anhalten und mit den folgenden Befehlen entfernen:

$> docker inspect config-server
$> docker stop config-server
$> docker rm config-server

4. Abhängige Anwendungen in einem Composite andocken

Docker Befehle undDockerfiles eignen sich besonders zum Erstellen einzelner Container. Wenn Sie jedochoperate on a network of isolated applications möchten, wird die Containerverwaltung schnell unübersichtlich.

To solve that, Docker provides a tool named Docker Compose. Dies wird mit einer eigenen Build-Datei im FormatYAMLgeliefert und eignet sich besser für die Verwaltung mehrerer Container. Beispiel: Es kann eine Zusammenstellung von Diensten in einem Befehl starten oder stoppen oder die Protokollausgabe mehrerer Dienste zu einempseudo-ttyzusammenführen.

Erstellen wir ein Beispiel für zwei Anwendungen, die in unterschiedlichen Docker-Containern ausgeführt werden. Sie kommunizieren miteinander und werden dem Host-System als "einzelne Einheit" präsentiert. Wir werden das imspring cloud configuration tutorial beschriebene Beispiel fürspring-cloud-config/clienterstellen und in unseren Ordnerfiles kopieren, wie wir es zuvor mit denconfig-server getan haben.

Dies sind unseredocker-compose.yml:

version: '2'
services:
    config-server:
        container_name: config-server
        build:
            context: .
            dockerfile: Dockerfile.server
        image: config-server:latest
        expose:
            - 8888
        networks:
            - spring-cloud-network
        volumes:
            - spring-cloud-config-repo:/var/lib/spring-cloud/config-repo
        logging:
            driver: json-file
    config-client:
        container_name: config-client
        build:
            context: .
            dockerfile: Dockerfile.client
        image: config-client:latest
        entrypoint: /opt/spring-cloud/bin/config-client-entrypoint.sh
        environment:
            SPRING_APPLICATION_JSON: \
              '{"spring": {"cloud":  \
              {"config": {"uri": "http://config-server:8888"}}}}'
        expose:
            - 8080
        ports:
            - 8080:8080
        networks:
            - spring-cloud-network
        links:
            - config-server:config-server
        depends_on:
            - config-server
        logging:
            driver: json-file
networks:
    spring-cloud-network:
        driver: bridge
volumes:
    spring-cloud-config-repo:
        external: true
  • version: Gibt an, welche Formatversion verwendet werden soll. Dies ist ein Pflichtfeld. Hier verwenden wir die neuere Version, währendlegacy format '1' ist.

  • services: Jedes Objekt in diesem Schlüssel definiert einenservice, a.k.a. Container. Dieser Abschnitt ist obligatorisch

    • build: Wenn angegeben, kanndocker-compose ein Bild ausDockerfile erstellen

      • context: Wenn angegeben, gibt es das Build-Verzeichnis an, in dem nachDockerfile gesucht wird

      • dockerfile: Wenn angegeben, wird ein alternativer Name fürDockerfile festgelegt

    • image: GibtDocker an, welchen Namen es dem Image geben soll, wenn Build-Features verwendet werden. Andernfalls wird nach diesem Bild in der Bibliothek oder inremote-registry gesucht

    • networks: Dies ist die Kennung der zu verwendenden benannten Netzwerke. Ein gegebenesname-value muss im Abschnittnetworks aufgeführt sein

    • volumes: Gibt die benannten Volumes an, die verwendet werden sollen, und die Mountpunkte, an denen die Volumes bereitgestellt werden sollen, getrennt durch einen Doppelpunkt. Ebenso muss innetworks Abschnitt einvolume-name in einem separatenvolumes Abschnitt definiert werden

    • links: Dadurch wird eine interne Netzwerkverbindung zwischen dem Dienst vonthisund dem aufgelisteten Dienst hergestellt. Der Dienst vonThiskann eine Verbindung zum aufgelisteten Dienst herstellen, wobei der Teil vor dem Doppelpunktservice-name aus dem Abschnittservices und der Teil nach dem Doppelpunkt den Hostnamen angibt, unter dem der Dienst ausgeführt wird lauscht an einem exponierten Port

    • depends_on: Hiermit wirdDocker angewiesen, einen Dienst nur zu starten, wenn die aufgelisteten Dienste erfolgreich gestartet wurden. NOTICE: Dies funktioniert nur auf Containerebene! Eine Problemumgehung zum Starten der abhängigenapplication finden Sie unterconfig-client-entrypoint.sh

    • logging: Hier verwenden wir den‘json-file'-Treiber, der der Standardtreiber ist. Alternativ können‘syslog' mit einer bestimmten Adressoption oder‘none' verwendet werden

  • networks: In diesem Abschnitt geben wir dienetworks an, die für unsere Dienste verfügbar sind.. In diesem Beispiel lassen wirdocker-compose benanntenetwork vom Typ‘bridge' für uns. Wenn die Optionexternal auftrue gesetzt ist, wird eine vorhandene Option mit dem angegebenen Namen verwendet

  • volumes: Dies ist dem Abschnittnetworks sehr ähnlich

Bevor wir fortfahren, überprüfen wir unsere Build-Datei auf Syntaxfehler:

$> docker-compose config

Dies sind unsereDockerfile.client, aus denen dasconfig-client-Image erstellt wird. Es unterscheidet sich vonDockerfile.server darin, dass wir zusätzlichOpenBSD netcat installieren (was im nächsten Schritt benötigt wird) und dieentrypoint ausführbar machen:

FROM alpine-java:base
MAINTAINER example.com
RUN apk --no-cache add netcat-openbsd
COPY files/config-client.jar /opt/spring-cloud/lib/
COPY files/config-client-entrypoint.sh /opt/spring-cloud/bin/
RUN chmod 755 /opt/spring-cloud/bin/config-client-entrypoint.sh

Und dies sind die benutzerdefiniertenentrypoint für unsereconfig-client service. Hier verwenden wirnetcat in einer Schleife, um zu überprüfen, ob unsereconfig-server bereit sind. Sie müssen beachten, dass wir unsereconfig-server durch ihrelink-name, anstelle einer IP-Adresse erreichen können:

#!/bin/sh
while ! nc -z config-server 8888 ; do
    echo "Waiting for upcoming Config Server"
    sleep 2
done
java -jar /opt/spring-cloud/lib/config-client.jar

Schließlich können wir unsere Bilder erstellen, die definierten Container erstellen und mit einem Befehl starten:

$> docker-compose up --build

Um die Container zu stoppen, entfernen Sie sie ausDocker und entfernen Sie die verbundenennetworks undvolumes daraus. Wir können den entgegengesetzten Befehl verwenden:

$> docker-compose down

Ein schönes Merkmal vondocker-compose istability to scale services. Zum Beispiel können wirDocker anweisen, einen Container fürconfig-server und drei Container fürconfig-client auszuführen.

Damit dies jedoch ordnungsgemäß funktioniert, müssen wir diecontainer_name aus unserendocker-compose.yml entfernen, damitDocker eine auswählen können, und dieexposed port configuration ändern, um Konflikte zu vermeiden .

Danach können wir unsere Dienstleistungen wie folgt skalieren:

$> docker-compose build
$> docker-compose up -d
$> docker-compose scale config-server=1 config-client=3

5. Fazit

Wie wir gesehen haben, können wir jetzt benutzerdefinierteDocker-Bilder erstellen,Spring Boot Application alsDocker-Container ausführen und abhängige Container mitdocker-compose erstellen.

Weitere Informationen zu den Build-Dateien finden Sie in den offiziellenDockerfile reference unddocker-compose.yml reference.

Wie üblich finden Sie die Quellcodes für dieses Tutorial inon Github.