Dockering af en Spring Boot-applikation

1. Oversigt

I denne artikel vil vi fokusere på, hvordan man dockerize en Spring Boot ansøgning at køre det i et isoleret miljø, også kaldet beholder.

Desuden viser vi, hvordan man opretter en sammensætning af containere, der er afhængige af hinanden og er forbundet med hinanden i et virtuelt privat netværk. Vi ser også, hvordan de kan styres sammen med enkeltkommandoer.

Lad os starte med at oprette et Java-aktiveret, letvægtsbasisbillede, der kører Alpine Linux.

2. Buildpacks Support i Spring Boot 2.3

Spring Boot 2.3 tilføjede support til buildpacks. Enkelt sagt i stedet for at oprette vores egen Dockerfile og bygge den ved hjælp af noget lignende docker build, alt hvad vi skal er at udstede følgende kommando:

$ ./mvnw spring-boot: build-image

Eller i Gradle:

$ ./gradlew bootBuildImage

Hovedmotivationen bag buildpacks er at skabe den samme implementeringsoplevelse, som nogle kendte skytjenester som Heroku eller Cloud Foundry leverer i et stykke tid. Vi kører bare build-image mål og selve platformen tager sig af opbygningen og implementeringen af ​​artefakten.

Desuden kan det hjælpe os med at ændre den måde, vi bygger Docker-billeder mere effektivt på. I stedet for at anvende den samme ændring på mange Dockerfiles i forskellige projekter, er alt, hvad vi skal gøre, at ændre eller indstille buildpacks 'image builder.

Ud over brugervenlighed og bedre generel udvikleroplevelse kan det også være mere effektivt. For eksempel vil buildpacks-tilgangen oprette et lagret Docker-billede og bruger den eksploderede version af Jar-filen.

3. Fælles basisbillede

Vi skal bruge Dockers eget build-filformat: a Dockerfil.

EN Dockerfil er i princippet en linevis batchfil, der indeholder kommandoer til at oprette et billede. Det er ikke absolut nødvendigt at placere disse kommandoer i en fil, fordi vi også kan videregive dem til kommandolinjen - en fil er simpelthen mere praktisk.

Så lad os skrive vores første Dockerfil:

FRA alpine: kant VEDLIGEHOLDER baeldung.com KØR apk tilføj --no-cache openjdk8 KOPIER filer / UbegrænsetJCEPolicyJDK8 / * \usr/lib/jvm/java-1.8-openjdk/jre/lib/security/
  • FRA: Nøgleordet FRA, fortæller Docker at bruge et givet billede med dets tag som build-base. Hvis dette billede ikke findes i det lokale bibliotek, skal du søge på online DockerHub, eller på ethvert andet konfigureret fjernregister, udføres
  • VEDLIGEHOLDER: A VEDLIGEHOLDER er normalt en e-mail-adresse, der identificerer forfatteren af ​​et billede
  • LØB: Med LØB kommando, vi udfører en shell-kommandolinje inden for målsystemet. Her bruger vi Alpine Linux pakkehåndtering apk at installere Java 8 OpenJDK
  • KOPI: Den sidste kommando fortæller Docker til KOPI et par filer fra det lokale filsystem, specifikt en undermappe til buildmappen, ind i billedet i en given sti

KRAV: For at kunne køre selvstudiet skal du downloade Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files fra Oracle. Uddrag blot det downloadede arkiv i en lokal mappe med navnet 'Filer'.

For endelig at oprette billedet og gemme det i det lokale bibliotek, skal vi køre:

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

VARSEL: Det –Tag indstilling giver billedet sit navn og –Rm = sandt fjerner mellemliggende billeder, når de er bygget korrekt. Det sidste tegn i denne shell-kommando er en prik, der fungerer som et build-katalogargument.

4. Dockerize en enkeltstående Spring Boot-applikation

Som et eksempel på et program, som vi kan dockerize, tager vi spring-cloud-config / server fra konfigurationsvejledningen til forårskyen. Som et forberedelsestrin er vi nødt til at samle en kørbar jar-fil og kopiere den til vores Docker build-katalog:

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

Nu opretter vi en Dockerfil som hedder Dockerfile.server med følgende indhold:

FRA alpine-java: base VEDLIGEHOLDER baeldung.com KOPIER filer / 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
  • FRA: Som base for vores image tager vi Java-aktiveret Alpine Linux, oprettet i det foregående afsnit
  • KOPI: Vi lod Docker kopier vores jar-fil til billedet
  • ENV: Denne kommando giver os mulighed for at definere nogle miljøvariabler, som respekteres af applikationen, der kører i containeren. Her definerer vi en tilpasset Spring Boot ansøgning konfiguration for at overgive til jar-eksekverbar senere
  • INDGANG/CMD: Dette vil være den eksekverbare start, når containeren starter. Vi skal definere dem som JSON-Array, fordi vi bruger en INDGANG i kombination med en CMD for nogle applikationsargumenter
  • BIND: Da vores container kører i et isoleret miljø uden direkte netværksadgang, er vi nødt til at definere en mountpoint-pladsholder til vores konfigurationslager
  • UDSÆTTE: Her fortæller vi det Docker, på hvilken havn vores applikation er opført. Denne port vil blive offentliggjort til værten, når containeren starter

At skabe et billede fra vores Dockerfil, vi er nødt til at løbe 'Docker build', ligesom før:

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

Men inden vi kører en container fra vores image, skal vi oprette et volumen til montering:

$> docker-volumen opretter --navn = spring-cloud-config-repo

VARSEL: Mens en container er uforanderlig, vil data, der er gemt i et volumen, være vedholdende over flere containere, når de ikke er forpligtet til et billede, når applikationen er afsluttet.

Endelig er vi i stand til at køre containeren fra vores image:

$> docker run --name = config-server --publish = 8888: 8888 \ --volume = spring-cloud-config-repo: / var / lib / spring-cloud / config-repo \ config-server: seneste
  • Først skal vi -navn vores container. Hvis ikke, vælges en automatisk
  • Så skal vi -offentliggøre vores udsatte havn (se Dockerfil) til en havn på vores vært. Værdien er angivet i formularen 'Vært-port: container-port'. Hvis kun en container-port er givet, vil en tilfældigt valgt værts-port blive brugt. Hvis vi udelader denne mulighed, vil containeren være helt isoleret
  • Det -bind option giver adgang til enten en mappe på værten (når den bruges med en absolut sti) eller en tidligere oprettet Docker lydstyrke (når det bruges med en volumen-navn). Stien efter tyktarmen angiver monteringspunkt inden i containeren
  • Som argument er vi nødt til at fortælle Docker, hvilket billede der skal bruges. Her er vi nødt til at give billednavn fra det tidligere 'docker build'Trin
  • Nogle flere nyttige muligheder:
    • -det - Aktiver interaktiv tilstand og tildel en pseudo-tty
    • -d - løsnes fra beholderen efter opstart

Hvis vi kører containeren i løsrevet tilstand, kan vi inspicere dens detaljer, stoppe den og fjerne den med følgende kommandoer:

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

5. Dockerize afhængige applikationer i en sammensat

Docker kommandoer og Dockerfiler er særligt velegnede til at skabe individuelle containere Men hvis du vil operere på et netværk af isolerede applikationer, bliver containeradministrationen hurtigt rodet.

For at løse det, Docker giver et værktøj navngivet Docker komponere. Dette kommer med en egen build-fil i YAML format og er bedre egnet til styring af flere containere. For eksempel er det i stand til at starte eller stoppe en sammensætning af tjenester i en kommando eller flette loggeoutputtet fra flere tjenester sammen til en pseudo-tty.

Lad os bygge et eksempel på to applikationer, der kører i forskellige Docker-containere. De kommunikerer med hinanden og præsenteres som en "enkelt enhed" til værtssystemet. Vi bygger og kopierer spring-cloud-config / client eksempel beskrevet i foråret sky konfiguration tutorial til vores filer mappe, som vi har gjort før med konfigurationsserver.

Dette vil være vores docker-compose.yml:

version: '2' services: config-server: container_name: config-server build: context:. dockerfile: Dockerfile.server image: config-server: seneste eksponering: - 8888 netværk: - spring-cloud-netværksvolumener: - spring-cloud-config-repo: / var / lib / spring-cloud / config-repo logging: driver : json-fil config-client: container_name: config-client build: context:. dockerfile: Dockerfile.client image: config-client: seneste startpunkt: /opt/spring-cloud/bin/config-client-entrypoint.sh miljø: SPRING_APPLICATION_JSON: \ '{"spring": {"cloud": \ {"config ": {" uri ":" // config-server: 8888 "}}} 'eksponere: - 8080 porte: - 8080: 8080 netværk: - spring-cloud-netværkslinks: - config-server: config-server afhænger_on : - logning af konfigurationsserver: driver: json-filnetværk: spring-cloud-netværk: driver: brovolumener: spring-cloud-config-repo: ekstern: sand
  • version: Angiver hvilken formatversion der skal bruges. Dette er et obligatorisk felt. Her bruger vi den nyere version, mens ældre format er '1'
  • tjenester: Hvert objekt i denne tast definerer a service, altså en container. Dette afsnit er obligatorisk
    • bygge: Hvis givet, docker-komponere er i stand til at oprette et billede fra en Dockerfil
      • sammenhæng: Hvis det er angivet, specificerer det build-biblioteket, hvor Dockerfil er slået op
      • dockerfil: Hvis det er angivet, angiver det et alternativt navn for en Dockerfil
    • billede: Fortæller Docker hvilket navn det skal give billedet, når build-features bruges. Ellers søger det efter dette billede i biblioteket eller fjernregistrering
    • netværk: Dette er identifikatoren for de navngivne netværk, der skal bruges. En given navn-værdi skal være anført i netværk afsnit
    • volumener: Dette identificerer de navngivne diskenheder, der skal bruges, og de monteringspunkter, som enhederne monteres på, adskilt af et kolon. Ligeledes i netværk afsnit, a volumen-navn skal defineres separat volumener afsnit
    • links: Dette opretter en intern netværksforbindelse mellem det her service og den anførte service. Det her tjenesten vil være i stand til at oprette forbindelse til den anførte tjeneste, hvorved delen før kolon angiver en service-navn fra tjenester sektion og delen efter kolon angiver værtsnavnet, som tjenesten lytter til i en eksponeret port
    • afhænger af: Dette fortæller Docker kun for at starte en tjeneste, hvis de anførte tjenester er startet med succes. VARSEL: Dette fungerer kun på containerniveau! For at en løsning skal starte den afhængige Ansøgning først, se config-client-entrypoint.sh
    • logning: Her bruger vi 'Json-fil' driver, som er standard. Alternativt 'Syslog' med en given adresseindstilling eller 'ingen' Kan bruges
  • netværk: I dette afsnit specificerer vi netværk tilgængelige for vores tjenester. I dette eksempel lader vi docker-komponere oprette et navngivet netværk af typen 'bro' for os. Hvis indstillingen ekstern er indstillet til rigtigt, bruger den en eksisterende med det givne navn
  • volumener: Dette ligner meget på netværk afsnit

Før vi fortsætter, vil vi kontrollere vores build-fil for syntaksfejl:

$> docker-compose-konfiguration

Dette vil være vores Dockerfile.client at bygge config-klient billede fra. Det adskiller sig fra Dockerfile.server ved at vi derudover installerer OpenBSD netcat (hvilket er nødvendigt i næste trin) og lav indgang eksekverbar:

FRA alpine-java: base VEDLIGEHOLDER baeldung.com KØR apk --no-cache tilføj netcat-openbsd COPY filer / config-client.jar / opt / spring-cloud / lib / COPY filer / config-client-entrypoint.sh / opt / spring-cloud / bin / RUN chmod 755 /opt/spring-cloud/bin/config-client-entrypoint.sh

Og dette bliver tilpasset indgang for vores config-klient service. Her bruger vi netcat i en løkke for at kontrollere, om vores konfigurationsserver er klar. Du er nødt til at bemærke, at vi kan nå vores konfigurationsserver ved sin link-navn, i stedet for en IP-adresse:

#! / bin / sh mens! nc -z konfigurationsserver 8888; laver ekko "Venter på kommende Config Server" sove 2 gjort java -jar /opt/spring-cloud/lib/config-client.jar

Endelig kan vi bygge vores billeder, oprette de definerede containere og starte det i en kommando:

$> docker-compose up --build

For at stoppe beholderne skal du fjerne dem fra Docker og fjern det tilsluttede netværk og volumener ud fra det kan vi bruge den modsatte kommando:

$> docker-komponer ned

En dejlig funktion af docker-komponere er evne til at skalere tjenester. For eksempel kan vi fortælle Docker at køre en container til konfigurationsserver og tre containere til config-klient.

Men for at dette skal fungere ordentligt, skal vi fjerne containernavn fra vores docker-compose.yml, til udlejning Docker vælg en, og vi er nødt til at ændre eksponeret portkonfiguration, for at undgå sammenstød.

Derefter er vi i stand til at skalere vores tjenester således:

$> docker-compose build $> docker-compose op -d $> docker-compose skala config-server = 1 config-client = 3

6. Konklusion

Som vi har set, er vi nu i stand til at oprette brugerdefinerede Docker billeder, der kører en Spring Boot ansøgning som en Docker container og skabe afhængige containere med docker-komponere.

For yderligere læsning om build-filer henviser vi til den officielle Dockerfil-reference og docker-compose.yml reference.

Som normalt kan kildekoderne til denne vejledning findes på Github.