Opprette Docker-bilder med Spring Boot

1. Introduksjon

Etter hvert som flere organisasjoner beveger seg mot containere og virtuelle servere, blir Docker en mer viktig del av arbeidsflytene for programvareutvikling. For det formål er en av de flotte nye funksjonene i Spring Boot 2.3 muligheten til å lage et Docker-bilde for Spring Boot-applikasjoner enkelt.

I denne opplæringen vil vi se på hvordan du lager Docker-bilder for en Spring Boot-applikasjon.

2. Tradisjonelle Docker-bygninger

Den tradisjonelle måten å bygge Docker-bilder med Spring Boot er å bruke en Dockerfile. Nedenfor er et enkelt eksempel:

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

Vi kunne da bruke docker bygge kommando for å opprette et Docker-bilde. Dette fungerer bra for de fleste applikasjoner, men det er et par ulemper.

Først bruker vi fettkrukken laget av Spring Boot. Dette kan påvirke oppstartstiden, spesielt i et containerisert miljø. Vi kan spare oppstartstid ved å legge til det eksploderte innholdet i jar-filen i stedet.

For det andre er Docker-bilder bygget i lag. Karakteren til Spring Boot-fettkrukker fører til at alle applikasjonskoder og tredjepartsbiblioteker blir satt i et enkelt lag. Dette betyr at selv når bare en enkelt kodelinje endres, må hele laget bygges om.

Ved å eksplodere glasset før bygging får applikasjonskode og tredjepartsbiblioteker hvert sitt lag. Dette gjør at vi kan dra nytte av Dockers cachemekanisme. Nå, når en linje med kode endres, trenger bare det tilsvarende laget å bygges om.

Med dette i tankene, la oss se på hvordan Spring Boot har forbedret prosessen med å lage Docker-bilder.

3. Buildpacks

Buildpacks er et verktøy som gir rammeverk og applikasjonsavhengighet.

For eksempel, gitt en Spring Boot-fettkrukke, vil en buildpack gi Java-kjøretiden for oss. Dette lar oss hoppe over Dockerfilen og få et fornuftig Docker-bilde automatisk.

Spring Boot inkluderer både Maven og Gradle støtte for buildpacks. Hvis vi for eksempel bygger med Maven, kjører vi kommandoen:

./mvnw spring-boot: build-image

La oss se på noen av de aktuelle resultatene for å se hva som skjer:

[INFO] Building jar: target / demo-0.0.1-SNAPSHOT.jar ... [INFO] Building image 'docker.io/library/demo:0.0.1-SNAPSHOT' ... [INFO]> Pulling builder image 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 100% ... [INFO] [creator] ===> DETECTING [INFO] [creator] 5 av 15 buildpacks som deltar [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 bilde 'docker.io/library/demo:0.0.1-SNAPSHOT' [INFO] Total tid: 44.796 s

Den første linjen viser at vi bygde vår vanlige fettkrukke, akkurat som en hvilken som helst typisk maven-pakke.

Den neste linjen begynner Docker-bildebyggingen. Rett etter ser vi byggingen trekker i Packeto-byggmesteren.

Packeto er en implementering av sky-native buildpacks. Det gjør arbeidet med å analysere prosjektet vårt og bestemme de nødvendige rammene og bibliotekene. I vårt tilfelle bestemmer det at vi har et Spring Boot-prosjekt og legger til de nødvendige buildpacks.

Til slutt ser vi det genererte Docker-bildet og den totale byggetiden. Legg merke til hvordan vi bruker en god del tid på å laste ned buildpacks og lage forskjellige lag første gang vi bygger.

En av de store egenskapene til buildpacks er at Docker-bildet er flere lag. Så hvis vi bare endrer applikasjonskoden, vil påfølgende bygg bli mye raskere:

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

4. Lagdelte krukker

I noen tilfeller foretrekker vi ikke å bruke buildpacks - kanskje er infrastrukturen vår allerede knyttet til et annet verktøy, eller vi har allerede tilpassede Dockerfiles vi vil bruke på nytt.

Av disse grunner støtter Spring Boot også å bygge Docker-bilder ved hjelp av lagdelte krukker. For å forstå hvordan det fungerer, la oss se på et typisk Spring Boot fettkrukkeoppsett:

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

Fettglasset består av 3 hovedområder:

  • Bootstrap-klasser kreves for å starte vårapplikasjonen
  • Søknadskode
  • Tredjepartsbiblioteker

Med lagdelte krukker ser strukturen ut, men vi får en ny lag.idx fil som tilordner hver katalog i fettburken til et lag:

- "avhengigheter": - "BOOT-INF / lib /" - "spring-boot-loader": - "org /" - "snapshot-dependencies": - "application": - "BOOT-INF / classes /" - "BOOT-INF / classpath.idx" - "BOOT-INF / layer.idx" - "META-INF /"

Out-of-the-box, Spring Boot tilbyr fire lag:

  • avhengigheter: typiske avhengigheter fra tredjeparter
  • øyeblikksbilde-avhengigheter: avhengighet av øyeblikksbilde fra tredjeparter
  • ressurser: statiske ressurser
  • applikasjon: applikasjonskode og ressurser

Målet er å plassere applikasjonskode og tredjepartsbiblioteker i lag som gjenspeiler hvor ofte de endres.

For eksempel er applikasjonskode sannsynligvis det som endres hyppigst, så den får sitt eget lag. Videre kan hvert lag utvikle seg alene, og bare når et lag har endret seg, vil det bli gjenoppbygd for Docker-bildet.

Nå som vi forstår den nye lagdelte krukkestrukturen, la oss se på hvordan vi kan bruke den til å lage Docker-bilder.

4.1. Lage lagdelte krukker

Først må vi sette opp prosjektet vårt for å lage en lagdelt krukke. Med Maven betyr dette å legge til en ny konfigurasjon til Spring Boot-plugin-delen i POM:

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

Med denne konfigurasjonen, Maven pakke kommandoen (sammen med noen av de avhengige kommandoene) vil generere en ny lagdelt jar ved hjelp av de fire standardlagene som er nevnt tidligere.

4.2. Vise og trekke ut lag

Deretter må vi trekke ut lagene fra krukken slik at Docker-bildet har de riktige lagene.

For å undersøke lagene i en hvilken som helst lagd jar, kan vi kjøre kommandoen:

java -Djarmode = lagverktøy -jar demo-0.0.1.jar liste

For å trekke dem ut, løp vi:

java -Djarmode = lekverktøy -jar demo-0.0.1.jar ekstrakt

4.3. Opprette Docker Image

Den enkleste måten å innlemme disse lagene i et Docker-bilde er ved å bruke en Dockerfile:

FRA adoptopenjdk: 11-jre-hotspot som byggmester ARG JAR_FILE = target / *. Jar COPY $ {JAR_FILE} application.jar RUN java -Djarmode = layertools -jar application.jar extract Fra adoptopenjdk: 11-jre-hotspot COPY --fra = byggeavhengigheter / ./ KOPIER - fra = øyeblikksavhengighet for byggherre / ./ KOPIER - fra = byggherrens fjær-start-laster / ./ KOPIER - fra = byggherreprogram / ./ ENTRYPOINT ["java", "org .springframework.boot.loader.JarLauncher "]

Denne Dockerfilen trekker ut lagene fra fettburken vår, og kopierer deretter hvert lag til Docker-bildet. Hver KOPIERE direktivet resulterer i et nytt lag i det endelige Docker-bildet.

Hvis vi bygger denne Dockerfilen, kan vi se hvert lag fra den lagdelte krukken bli lagt til Docker-bildet som sitt eget lag:

... Trinn 6/10: KOPIER - fra = avhengighet av byggherre / ./ ---> 2c631b8f9993 Trinn 7/10: KOPIER - fra = byggherre øyeblikksbilde-avhengigheter / ./ ---> 26e8ceb86b7d Trinn 8/10: KOPI - fra = byggmester vår-boot-loader / ./ ---> 6dd9eaddad7f Trinn 9/10: KOPI - fra = byggherre-applikasjon / ./ ---> dc80cc00a655 ...

5. Konklusjon

I denne opplæringen har vi sett forskjellige måter å bygge Docker-bilder med Spring Boot på. Ved hjelp av buildpacks kan vi få passende Docker-bilder uten kjele eller tilpassede konfigurasjoner. Eller med litt mer innsats kan vi bruke lagdelte krukker for å få et mer skreddersydd Docker-bilde.

Alle eksemplene i denne opplæringen finner du på GitHub.

For mer informasjon om bruk av Java og Docker, sjekk ut veiledningen om jib.