Dockeriseren van een Spring Boot-applicatie

1. Overzicht

In dit artikel zullen we ons concentreren op het koppelen van een Spring Boot-applicatie om het in een geïsoleerde omgeving uit te voeren, a.k.a. container.

Verder laten we zien hoe u een compositie van containers maakt, die van elkaar afhankelijk zijn en in een virtueel privénetwerk met elkaar zijn verbonden. We zullen ook zien hoe ze samen met enkele commando's kunnen worden beheerd.

Laten we beginnen met het maken van een Java-enabled, lichtgewicht basisimage, running Alpine Linux.

2. Buildpacks-ondersteuning in Spring Boot 2.3

Spring Boot 2.3 heeft ondersteuning toegevoegd voor buildpacks. Simpel gezegd, in plaats van ons eigen Dockerfile te maken en het te bouwen met zoiets als docker build, alles wat we hoeven te doen is het volgende commando geven:

$ ./mvnw spring-boot: build-image

Of in Gradle:

$ ./gradlew bootBuildImage

De belangrijkste motivatie achter buildpacks is om dezelfde implementatie-ervaring te creëren die sommige bekende cloudservices zoals Heroku of Cloud Foundry al een tijdje bieden.. We voeren gewoon het build-afbeelding goal en het platform zelf zorgen voor het bouwen en inzetten van het artefact.

Bovendien kan het ons helpen om de manier waarop we Docker-images maken effectiever te veranderen. In plaats van dezelfde wijziging toe te passen op veel Dockerfiles in verschillende projecten, hoeven we alleen maar de image builder van de buildpacks te wijzigen of af te stemmen.

Naast gebruiksgemak en een betere algehele ontwikkelaarservaring, kan het ook efficiënter zijn. De buildpacks-benadering maakt bijvoorbeeld een gelaagde Docker-afbeelding en gebruikt de geëxplodeerde versie van het Jar-bestand.

3. Gemeenschappelijke basisafbeelding

We gaan gebruiken Docker's eigen build-bestandsformaat: a Dockerfile.

EEN Dockerfile is in principe een lijngewijs batchbestand, dat opdrachten bevat om een ​​afbeelding op te bouwen. Het is niet absoluut noodzakelijk om deze commando's in een bestand te plaatsen, omdat we ze ook naar de commandoregel kunnen doorgeven - een bestand is gewoon handiger.

Dus laten we onze eerste schrijven Dockerfile:

VAN alpine: edge MAINTAINER baeldung.com RUN apk add --no-cache openjdk8 COPY files / UnlimitedJCEPolicyJDK8 / * \ /usr/lib/jvm/java-1.8-openjdk/jre/lib/security/
  • VAN: Het sleutelwoord VAN, vertelt Docker om een ​​gegeven afbeelding met zijn tag als build-base te gebruiken. Als deze afbeelding niet in de plaatselijke bibliotheek staat, een online-zoekopdracht op DockerHub, of op een ander geconfigureerd register op afstand, wordt uitgevoerd
  • ONDERHOUDER: EEN ONDERHOUDER is meestal een e-mailadres dat de auteur van een afbeelding identificeert
  • RENNEN: Met de RENNEN commando voeren we een shell-opdrachtregel uit binnen het doelsysteem. Hier gebruiken we Van Alpine Linux pakket manager apk om het Java 8 OpenJDK
  • KOPIËREN: Het laatste commando vertelt Docker naar KOPIËREN een paar bestanden van het lokale bestandssysteem, specifiek een submap naar de build-directory, naar de afbeelding in een bepaald pad

VEREISTEN: Om de tutorial met succes uit te voeren, moet u het Java Cryptography Extension (JCE) Onbeperkte machtsbeleidsbestanden voor jurisdictie van Orakel. Pak het gedownloade archief eenvoudig uit in een lokale map met de naam ‘Bestanden '.

Om de afbeelding eindelijk te bouwen en op te slaan in de lokale bibliotheek, moeten we het volgende uitvoeren:

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

MERK OP: De -label optie geeft de afbeelding zijn naam en –Rm = waar zal tussenliggende afbeeldingen verwijderen nadat het met succes is gebouwd. Het laatste teken in deze shell-opdracht is een punt, die fungeert als een build-directory-argument.

4. Dockeriseer een zelfstandige Spring Boot-applicatie

Als voorbeeld voor een applicatie die we kunnen dockeriseren, nemen we de spring-cloud-config / server van de springcloud-configuratiehandleiding. Als voorbereidende stap moeten we een uitvoerbaar jar-bestand samenstellen en naar ons Docker build-directory:

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

Nu gaan we een Dockerfile genaamd Dockerfile.server met de volgende inhoud:

VAN alpine-java: base MAINTAINER baeldung.com KOPIE-bestanden / 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
  • VAN: Als basis voor ons imago nemen we de Java-ingeschakeld Alpine Linux, gemaakt in de vorige sectie
  • KOPIËREN: Wij laten Docker kopieer ons jar-bestand naar de afbeelding
  • ENV: Met deze opdracht kunnen we enkele omgevingsvariabelen definiëren, die worden gerespecteerd door de toepassing die in de container wordt uitgevoerd. Hier definiëren we een maatwerk Spring Boot-applicatie configuratie, om later over te dragen aan de jar-executable
  • INGANGSPUNT/CMD: Dit is het uitvoerbare bestand dat wordt gestart wanneer de container wordt opgestart. We moeten ze definiëren als JSON-array, omdat we een INGANGSPUNT in combinatie met een CMD voor sommige toepassingsargumenten
  • VOLUME: Omdat onze container zal draaien in een geïsoleerde omgeving, zonder directe netwerktoegang, moeten we een mountpoint-placeholder definiëren voor onze configuratierepository
  • BLOOTSTELLEN: Hier vertellen we het Docker, op welke poort onze applicatie vermeldt. Deze poort wordt naar de host gepubliceerd wanneer de container wordt opgestart

Om een ​​afbeelding te maken van onze Dockerfile, we moeten rennen ‘Docker build ', zoals eerder:

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

Maar voordat we een container van onze afbeelding gaan draaien, moeten we een volume maken om te mounten:

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

MERK OP: Hoewel een container onveranderlijk is, blijven de gegevens die in een volume zijn opgeslagen in verschillende containers, als ze niet worden toegewezen aan een afbeelding nadat de toepassing is afgesloten.

Eindelijk kunnen we de container vanuit onze afbeelding uitvoeren:

$> docker run --name = config-server --publish = 8888: 8888 \ --volume = spring-cloud-config-repo: / var / lib / spring-cloud / config-repo \ config-server: laatste
  • Ten eerste moeten we -naam onze container. Zo niet, dan wordt er automatisch een gekozen
  • Dan moeten we -publiceren onze blootgestelde poort (zie Dockerfile) naar een poort op onze host. De waarde wordt vermeld in het formulier ‘Host-port: container-port '. Als alleen een containerpoort is opgegeven, wordt een willekeurig gekozen hostpoort gebruikt. Als we deze optie weglaten, staat de container volledig geïsoleerd
  • De -volume optie geeft toegang tot een map op de host (indien gebruikt met een absoluut pad) of een eerder aangemaakt Docker volume (indien gebruikt met een volume-naam). Het pad na de dubbele punt geeft de koppelpunt binnen de container
  • Als argument moeten we het vertellen Docker, welke afbeelding moet worden gebruikt. Hier moeten we de afbeelding-naam van de eerdere ‘docker build‘Stap
  • Nog enkele handige opties:
    • -het - schakel de interactieve modus in en wijs een pseudo-tty
    • -d - na het opstarten losmaken van de container

Als we de container in ontkoppelde modus uitvoeren, kunnen we de details ervan inspecteren, stoppen en verwijderen met de volgende opdrachten:

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

5. Dockeriseer afhankelijke applicaties in een composiet

Docker commando's en Dockerfiles zijn bijzonder geschikt voor het maken van individuele containers. Maar als je wilt werken op een netwerk van geïsoleerde applicaties, raakt het containerbeheer snel onoverzichtelijk.

Om dat op te lossen, Docker biedt een tool met de naam Docker Compose. Dit wordt geleverd met een eigen build-bestand in YAML formaat en is beter geschikt voor het beheren van meerdere containers. Het is bijvoorbeeld in staat om een ​​samenstelling van services in één opdracht te starten of te stoppen, of de logboekuitvoer van meerdere services samen te voegen tot één pseudo-tty.

Laten we een voorbeeld maken van twee applicaties die in verschillende Docker-containers worden uitgevoerd. Ze communiceren met elkaar en worden aan het hostsysteem gepresenteerd als een "enkele eenheid". We zullen het spring-cloud-config / client voorbeeld beschreven in de springcloud-configuratiehandleiding voor onze bestanden map, zoals we eerder hebben gedaan met de config-server.

Dit wordt onze docker-compose.yml:

versie: '2' services: config-server: container_name: config-server build: context:. dockerfile: Dockerfile.server image: config-server: laatste blootstelling: - 8888 netwerken: - spring-cloud-netwerkvolumes: - 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 afbeelding: config-client: laatste toegangspunt: /opt/spring-cloud/bin/config-client-entrypoint.sh omgeving: SPRING_APPLICATION_JSON: \ '{"spring": {"cloud": \ {"config ": {" uri ":" // config-server: 8888 "}}}} 'blootstellen: - 8080 poorten: - 8080: 8080 netwerken: - spring-cloud-netwerkkoppelingen: - config-server: config-server afhankelijk_on : - config-server logging: driver: json-bestandsnetwerken: spring-cloud-network: driver: bridge volumes: spring-cloud-config-repo: extern: true
  • versie: Geeft aan welke formaatversie moet worden gebruikt. Dit is een verplicht veld. Hier gebruiken we de nieuwere versie, terwijl de legacy formaat is ‘1 '
  • Diensten: Elk object in deze sleutel definieert een onderhoud, ook wel een container genoemd. Deze sectie is verplicht
    • bouwen: Indien gegeven, docker-compose is in staat om een ​​afbeelding op te bouwen van een Dockerfile
      • context: Indien gegeven, specificeert het de build-directory, waar de Dockerfile wordt opgezocht
      • dockerfile: Indien gegeven, stelt het een alternatieve naam in voor een Dockerfile
    • beeld: Vertelt Docker welke naam het aan de afbeelding moet geven wanneer build-functies worden gebruikt. Anders zoekt het naar deze afbeelding in de bibliotheek of remote-registry
    • netwerken: Dit is de identificatie van de benoemde netwerken die moeten worden gebruikt. Een gegeven naam-waarde moet worden vermeld in de netwerken sectie
    • volumes: Dit identificeert de benoemde volumes die moeten worden gebruikt en de mountpoints waarnaar de volumes moeten worden gemount, gescheiden door een dubbele punt. Evenzo in netwerken sectie A volume-naam moet afzonderlijk worden gedefinieerd volumes sectie
    • links: Dit zorgt voor een interne netwerkverbinding tussen dit service en de vermelde service. Dit service kan verbinding maken met de vermelde service, waarbij het gedeelte vóór de dubbele punt een servicenaam van de Diensten sectie en het deel na de dubbele punt specificeert de hostnaam waarop de service luistert op een blootgestelde poort
    • hangt af van: Dit vertelt Docker om alleen een service te starten als de vermelde services met succes zijn gestart. MERK OP: Dit werkt alleen op containerniveau! Voor een tijdelijke oplossing om het afhankelijke te starten toepassing eerst, zie config-client-entrypoint.sh
    • logboekregistratie: Hier gebruiken we de ‘Json-bestand ' driver, wat de standaard is. alternatief ‘Syslog ' met een bepaalde adresoptie of 'geen' kan worden gebruikt
  • netwerken: In deze sectie specificeren we de netwerken beschikbaar voor onze diensten. In dit voorbeeld laten we docker-compose maak een naam netwerk van het type 'brug' voor ons. Als de option extern ingesteld op waar, het zal een bestaande gebruiken met de opgegeven naam
  • volumes: Dit lijkt erg op de netwerken sectie

Voordat we verder gaan, zullen we ons build-bestand controleren op syntaxisfouten:

$> docker-compose config

Dit wordt onze Dockerfile.client om het config-client afbeelding van. Het verschilt van de Dockerfile.server in dat we bovendien installeren OpenBSD netcat (wat nodig is in de volgende stap) en maak de ingangspunt uitvoerbaar:

VANUIT alpine-java: base MAINTAINER baeldung.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

En dit zal het aangepaste zijn ingangspunt voor onze config-client service. Hier gebruiken we netcat in een lus om te controleren of onze config-server is klaar. U moet opmerken, dat we onze kunnen bereiken config-server door zijn link-naam, in plaats van een IP-adres:

#! / bin / sh while! nc -z config-server 8888; echo "Wachten op aankomende Config Server" slaap 2 gedaan java -jar /opt/spring-cloud/lib/config-client.jar

Ten slotte kunnen we onze afbeeldingen bouwen, de gedefinieerde containers maken en deze met één opdracht starten:

$> docker-compose up --build

Om de containers te stoppen, verwijdert u deze uit Docker en verwijder de aangesloten netwerken en volumes daaruit kunnen we het tegenovergestelde commando gebruiken:

$> docker-compose down

Een leuke feature van docker-compose is de mogelijkheid om services te schalen. We kunnen het bijvoorbeeld vertellen Docker om één container uit te voeren voor de config-server en drie containers voor de config-client.

Maar om dit goed te laten werken, moeten we de container_name van onze docker-compose.yml, voor verhuur Docker kies er een, en we moeten de blootgestelde poortconfiguratie, om botsingen te voorkomen.

Daarna kunnen we onze diensten als volgt opschalen:

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

6. Conclusie

Zoals we hebben gezien, kunnen we nu maatwerk bouwen Docker afbeeldingen, met een Spring Boot-applicatie als een Docker container, en het maken van afhankelijke containers met docker-compose.

Voor meer informatie over de build-bestanden verwijzen we naar de officiële Dockerfile-referentie en de docker-compose.yml referentie.

Zoals gewoonlijk zijn de broncodes voor deze tutorial te vinden op Github.