Oprettelse af Docker-billeder med Spring Boot

1. Introduktion

Da flere organisationer bevæger sig mod containere og virtuelle servere, bliver Docker en mere vigtig del af softwareudviklingsarbejdsprocesser. Til dette formål er en af ​​de store nye funktioner i Spring Boot 2.3 muligheden for nemt at oprette et Docker-billede til Spring Boot-applikationer.

I denne vejledning ser vi på, hvordan du opretter Docker-billeder til en Spring Boot-applikation.

2. Traditionelle Docker-bygninger

Den traditionelle måde at opbygge Docker-billeder med Spring Boot på er at bruge en Dockerfil. Nedenfor er et simpelt eksempel:

FRA openjdk: 8-jdk-alpine EXPOSE 8080 ARG JAR_FILE = target / demo-app-1.0.0.jar TILFØJ $ {JAR_FILE} app.jar ENTRYPOINT ["java", "- jar", "/ app.jar"]

Vi kunne derefter bruge docker build kommando til at oprette et Docker-billede. Dette fungerer fint for de fleste applikationer, men der er et par ulemper.

For det første bruger vi den fede krukke oprettet af Spring Boot. Dette kan påvirke opstartstiden, især i et containeriseret miljø. Vi kan spare opstartstid ved at tilføje det eksploderede indhold af jar-filen i stedet.

For det andet er Docker-billeder bygget i lag. Spring Boot-fedtkrukker medfører, at alle applikationskoder og tredjepartsbiblioteker placeres i et enkelt lag. Dette betyder, at selv når kun en enkelt kodelinje ændres, skal hele laget genopbygges.

Ved at eksplodere krukken før bygning får applikationskode og tredjepartsbiblioteker hver deres lag. Dette giver os mulighed for at drage fordel af Dockers cachemekanisme. Når en kode kode ændres, skal kun det tilsvarende lag genopbygges.

Med dette i tankerne, lad os se på, hvordan Spring Boot har forbedret processen med at oprette Docker-billeder.

3. Buildpacks

Buildpacks er et værktøj, der giver rammer og applikationsafhængigheder.

For eksempel, givet en Spring Boot fedtkrukke, ville en buildpack give Java-runtime for os. Dette giver os mulighed for at springe Dockerfilen over og få et fornuftigt Docker-billede automatisk.

Spring Boot inkluderer både Maven og Gradle support til buildpacks. For eksempel ved at bygge med Maven kører vi kommandoen:

./mvnw spring-boot: build-image

Lad os se på nogle af de relevante output for at se, hvad der sker:

[INFO] Bygningskrukke: target / demo-0.0.1-SNAPSHOT.jar ... [INFO] Bygningsbillede 'docker.io/library/demo:0.0.1-SNAPSHOT' ... [INFO]> Trækker bygherrebilledet 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 100% ... [INFO] [creator] ===> DETECTING [INFO] [creator] 5 af 15 buildpacks, der deltager [INFO] [ creator] paketo-buildpacks / bellsoft-liberica 2.8.1 [INFO] [creator] paketo-buildpacks / executable-jar 1.2.8 [INFO] [creator] paketo-buildpacks / apache-tomcat 1.3.1 [INFO] [creator] paketo-buildpacks / dist-zip 1.3.6 [INFO] [creator] paketo-buildpacks / spring-boot 1.9.1 ... [INFO] Vellykket bygget billede 'docker.io/library/demo:0.0.1-SNAPSHOT' [INFO] Samlet tid: 44.796 s

Den første linje viser, at vi byggede vores standardfedtkrukke, ligesom enhver typisk maven-pakke.

Den næste linje begynder Docker-billedopbygningen. Lige efter ser vi build trækker i Packeto builder.

Packeto er en implementering af cloud-native buildpacks. Det gør arbejdet med at analysere vores projekt og bestemme de krævede rammer og biblioteker. I vores tilfælde bestemmer det, at vi har et Spring Boot-projekt og tilføjer de nødvendige buildpacks.

Endelig ser vi det genererede Docker-billede og den samlede byggetid. Læg mærke til, hvordan vi bruger en hel del tid på at downloade buildpacks og skabe forskellige lag, første gang vi bygger.

En af de store funktioner i buildpacks er, at Docker-billedet er flere lag. Så hvis vi kun ændrer vores applikationskode, vil efterfølgende build være meget hurtigere:

... [INFO] [creator] Genbrug af lag 'paketo-buildpacks / executable-jar: class-path' [INFO] [creator] Genbrug af lag 'paketo-buildpacks / spring-boot: web-application-type' ... [INFO] Vellykket bygget billede 'docker.io/library/demo:0.0.1-SNAPSHOT' ... [INFO] Samlet tid: 10.591 s

4. Lagdelte krukker

I nogle tilfælde foretrækker vi måske ikke at bruge buildpacks - måske er vores infrastruktur allerede bundet til et andet værktøj, eller vi har allerede brugerdefinerede Dockerfiles, som vi vil genbruge.

Af disse grunde understøtter Spring Boot også bygning af Docker-billeder ved hjælp af lagdelte krukker. For at forstå hvordan det fungerer, lad os se på et typisk Spring Boot fedtkrukke-layout:

org / springframework / boot / loader / ... BOOT-INF / klasser / ... lib / ...

Fedtbeholderen består af 3 hovedområder:

  • Bootstrap-klasser kræves for at starte Spring-applikationen
  • Ansøgningskode
  • Tredjepartsbiblioteker

Med lagdelte krukker ser strukturen ud, men vi får en ny lag.idx fil, der kortlægger hver mappe i fedtbeholderen til et lag:

- "afhængigheder": - "BOOT-INF / lib /" - "spring-boot-loader": - "org /" - "snapshot-afhængigheder": - "applikation": - "BOOT-INF / klasser /" - "BOOT-INF / classpath.idx" - "BOOT-INF / layer.idx" - "META-INF /"

Spring-out-of-the-box indeholder fire lag:

  • afhængigheder: typiske afhængigheder fra tredjeparter
  • øjebliksbillede-afhængigheder: afhængighed af øjebliksbillede fra tredjeparter
  • ressourcer: statiske ressourcer
  • Ansøgning: applikationskode og ressourcer

Målet er at placere applikationskode og tredjepartsbiblioteker i lag, der afspejler, hvor ofte de ændres.

For eksempel er applikationskode sandsynligvis det, der ændres hyppigst, så den får sit eget lag. Yderligere kan hvert lag udvikle sig alene, og kun når et lag er ændret, bliver det genopbygget til Docker-billedet.

Nu hvor vi forstår den nye lagdelte jar-struktur, lad os se på, hvordan vi kan bruge den til at lave Docker-billeder.

4.1. Oprettelse af lagdelte krukker

Først skal vi oprette vores projekt for at skabe en lagdelt krukke. Med Maven betyder det at tilføje en ny konfiguration til Spring Boot-pluginsektionen i vores POM:

 org.springframework.boot spring-boot-maven-plugin true 

Med denne konfiguration, Maven pakke kommando (sammen med en hvilken som helst af dens afhængige kommandoer) vil generere en ny lagdelt jar ved hjælp af de fire tidligere nævnte standardlag.

4.2. Visning og udpakning af lag

Dernæst skal vi udtrække lagene fra krukken, så Docker-billedet har de rigtige lag.

For at undersøge lagene i en hvilken som helst lagdelt krukke kan vi køre kommandoen:

java -Djarmode = lageværktøjer -jar demo-0.0.1.jar liste

Derefter løb vi for at udtrække dem:

java -Djarmode = lægeværktøjer -jar demo-0.0.1.jar ekstrakt

4.3. Oprettelse af Docker-billedet

Den nemmeste måde at inkorporere disse lag i et Docker-billede er ved hjælp af en Dockerfil:

FRA adoptopenjdk: 11-jre-hotspot som bygherre ARG JAR_FILE = mål / *. Jar KOPIER $ {JAR_FILE} application.jar KØR java -Djarmode = layertools -jar application.jar-ekstrakt FRA adoptopenjdk: 11-jre-hotspot COPY --fra = bygherrens afhængigheder / ./ COPY --fra = bygherrens snapshotafhængigheder / ./ COPY - fra = bygherrens spring-boot-loader / ./ COPY - fra = bygherre-applikation / ./ ENTRYPOINT ["java", "org .springframework.boot.loader.JarLauncher "]

Denne Dockerfil udtrækker lagene fra vores fede krukke og kopierer derefter hvert lag til Docker-billedet. Hver KOPI direktivet resulterer i et nyt lag i det endelige Docker-billede.

Hvis vi bygger denne Docker-fil, kan vi se hvert lag fra den lagdelte krukke blive tilføjet til Docker-billedet som sit eget lag:

... Trin 6/10: KOPIER - fra = bygherrens afhængigheder / ./ ---> 2c631b8f9993 Trin 7/10: KOPIER - fra = bygherrens snapshot-afhængigheder / ./ ---> 26e8ceb86b7d Trin 8/10: COPY --from = builder spring-boot-loader / ./ ---> 6dd9eaddad7f Trin 9/10: COPY --from = builder-applikation / ./ ---> dc80cc00a655 ...

5. Konklusion

I denne vejledning har vi set forskellige måder at opbygge Docker-billeder med Spring Boot på. Ved hjælp af buildpacks kan vi få passende Docker-billeder uden kedelplade eller brugerdefinerede konfigurationer. Eller med lidt mere indsats kan vi bruge lagede krukker til at få et mere skræddersyet Docker-billede.

Alle eksemplerne i denne vejledning kan findes på GitHub.

For yderligere information om brug af Java og Docker, se vejledningen om jib.