ProHoster > Blog > Bestjoer > Bouwe optimisearre Docker-ôfbyldings foar in Spring Boot-applikaasje
Bouwe optimisearre Docker-ôfbyldings foar in Spring Boot-applikaasje
Containers binne it foarkommende middel wurden wurden om in applikaasje te ferpakken mei al syn software- en bestjoeringssysteemôfhinklikens en se dan oan ferskate omjouwings te leverjen.
Dit artikel behannelt ferskate manieren om in Spring Boot-applikaasje te kontenerearjen:
it bouwen fan in dockerôfbylding mei in dockerfile,
it bouwen fan in OCI-ôfbylding fan boarne mei Cloud-Native Buildpack,
en ôfbyldingsoptimalisaasje by runtime troch JAR-dielen te skieden yn ferskate nivo's mei laach ark.
Koade foarbyld
Dit artikel wurdt begelaat troch in foarbyld fan wurkkoade op GitHub .
Container terminology
Wy sille begjinne mei de kontenerterminology dy't yn it heule artikel wurdt brûkt:
Container ôfbylding: in bestân fan in spesifyk formaat. Wy konvertearje ús applikaasje yn in kontenerôfbylding troch it build-ark út te fieren.
Kontener: In útfierbere eksimplaar fan de kontenerôfbylding.
Container motor: It daemonproses ferantwurdlik foar it útfieren fan de kontener.
Container host: De hostmasine dêr't de kontenermotor op rint.
Container registraasje: De algemiene lokaasje dy't brûkt wurdt om de kontenerôfbylding te publisearjen en te fersprieden.
OCI standert: Open Container Initiative (OCI) is in lichtgewicht, iepen-boarne-behearskader foarme troch de Linux Foundation. De OCI Image Specification definieart yndustrynormen foar kontenerôfbyldingsformaten en de runtime om te soargjen dat alle kontenermotoren kontenerôfbyldings kinne útfiere dy't makke binne troch elk bouwark.
Om in applikaasje te kontenerearjen, ferpakke wy ús applikaasje yn in kontenerôfbylding en publisearje dy ôfbylding yn it iepenbiere register. De kontener-runtime hellet dizze ôfbylding út it register, pakt it út en rint de applikaasje deryn.
Ferzje 2.3 fan Spring Boot biedt plugins foar it bouwen fan OCI-ôfbyldings.
Havenarbeider is de meast brûkte kontener-ymplemintaasje, en wy brûke Docker yn ús foarbylden, dus alle folgjende kontenerferwizings yn dit artikel sille ferwize nei Docker.
It bouwen fan in kontenerôfbylding op 'e tradisjonele manier
Docker-ôfbyldings bouwe foar Spring Boot-applikaasjes is heul maklik troch in pear ynstruksjes ta te foegjen oan jo Dockerfile.
Wy meitsje earst in útfierbere JAR en, as ûnderdiel fan 'e Dockerfile-ynstruksjes, kopiearje de útfierbere JAR boppe op' e basis JRE-ôfbylding nei it tapassen fan de nedige oanpassingen.
Litte wy ús Spring-applikaasje oanmeitsje Spring Initializr mei ôfhinklikens web, lombokи actuator. Wy foegje ek in restcontroller ta om in API te leverjen GETmetoade.
In Dockerfile oanmeitsje
Wy pleatse dizze applikaasje dan yn in kontener troch tafoegjen Dockerfile:
Us Dockerfile befettet in basisôfbylding, fan adoptopenjdk, wêrop wy ús JAR-bestân kopiearje en dan de poarte iepenje, 8080dy't sil harkje nei fersiken.
Applikaasje gearkomste
Earst moatte jo in applikaasje oanmeitsje mei Maven of Gradle. Hjir brûke wy Maven:
mvn clean package
Dit makket in útfierber JAR-bestân foar de applikaasje. Wy moatte dizze útfierbere JAR konvertearje nei in Docker-ôfbylding om op 'e Docker-motor te rinnen.
Meitsje in kontenerôfbylding
Wy sette dan dizze JAR-útfierbere yn 'e Docker-ôfbylding troch it kommando út te fieren docker buildfan 'e root-map fan it projekt mei de Dockerfile dy't earder makke is:
docker build -t usersignup:v1 .
Wy kinne ús ôfbylding sjen yn 'e list mei it kommando:
docker images
De útfier fan it boppesteande kommando befettet ús ôfbylding usersignuptegearre mei de basisôfbylding, adoptopenjdkspesifisearre yn ús Dockerfile.
REPOSITORY TAG SIZE
usersignup v1 249MB
adoptopenjdk 11-jre-hotspot 229MB
Besjoch lagen binnen in kontenerôfbylding
Litte wy nei de stapel lagen yn 'e ôfbylding sjen. Wy sille brûke ynstrumint dûke, om dizze lagen te besjen:
dive usersignup:v1
Hjir is in diel fan 'e útfier fan it kommando Dive:
Lykas wy kinne sjen, makket de tapassingslaach in signifikant diel út fan 'e ôfbyldingsgrutte. Wy wolle de grutte fan dizze laach ferminderje yn 'e folgjende seksjes as ûnderdiel fan ús optimalisaasje.
It bouwen fan in kontenerôfbylding mei Buildpack
Assembly pakketten (Buildpacks) is in generike term dy't brûkt wurdt troch ferskate Platform as in Service (PAAS) oanbiedingen om in kontenerôfbylding te meitsjen fan boarnekoade. It waard lansearre troch Heroku yn 2011 en is sûnt oannommen troch Cloud Foundry, Google App Engine, Gitlab, Knative en in pear oaren.
Foardiel fan Cloud Build Packages
Ien fan 'e wichtichste foardielen fan it brûken fan Buildpack om ôfbyldings te bouwen is dat image konfiguraasje feroarings kinne wurde beheard sintraal (bouwer) en propagearre nei alle applikaasjes mei help fan de bouwer.
De boupakketten wiene nau bûn oan it platfoarm. Cloud-Native Buildpacks leverje standerdisearring oer platfoarms troch it OCI-ôfbyldingsformaat te stypjen, wat soarget dat de ôfbylding kin wurde útfierd troch de Docker-motor.
Mei help fan de Spring Boot Plugin
De Spring Boot-plugin bout OCI-ôfbyldings fan boarne mei Buildpack. Ofbyldings wurde makke mei bootBuildImagetaken (Gradle) of spring-boot:build-imagedoel (Maven) en lokale Docker ynstallaasje.
Wy kinne de namme fan 'e ôfbylding oanpasse dy't wy moatte drukke nei it Docker-register troch de namme yn te spesifisearjen image tag:
Litte wy Maven brûke om út te fieren build-imagedoelen foar it meitsjen fan in applikaasje en it meitsjen fan in kontenerôfbylding. Wy brûke op it stuit gjin Dockerfiles.
Ut de útfier sjogge wy dat paketo Cloud-Native buildpackbrûkt om in wurkjende OCI-ôfbylding te meitsjen. Lykas earder kinne wy de ôfbylding sjen litte as in Docker-ôfbylding troch it kommando út te fieren:
Dêrnei rinne wy de Jib-plugin mei it Maven-kommando om de applikaasje te bouwen en de kontenerôfbylding te meitsjen. Lykas earder brûke wy hjir gjin Dockerfiles:
Nei it útfieren fan it boppesteande Maven-kommando krije wy de folgjende útfier:
[INFO] Containerizing application to pratikdas/usersignup:v1...
.
.
[INFO] Container entrypoint set to [java, -cp, /app/resources:/app/classes:/app/libs/*, io.pratik.users.UsersignupApplication]
[INFO]
[INFO] Built and pushed image as pratikdas/usersignup:v1
[INFO] Executing tasks:
[INFO] [==============================] 100.0% complete
De útfier lit sjen dat de kontenerôfbylding is makke en pleatst yn it register.
Motivaasjes en metoaden foar it meitsjen fan optimalisearre ôfbyldings
Wy hawwe twa haadredenen foar optimalisearjen:
Produktiviteit: Yn in kontenerorkestraasjesysteem wurdt de kontenerôfbylding lutsen fan it byldregister nei de host dy't de kontenermotor draait. Dit proses wurdt planning neamd. It lûken fan grutte ôfbyldings út it register resultearret yn lange skematiden yn kontenerorkestraasjesystemen en lange bouwtiden yn CI-pipelines.
Feiligens: grutte bylden hawwe ek in grut gebiet foar kwetsberens.
In Docker-ôfbylding is opboud út in stapel lagen, elk dy't in ferklearring yn ús Dockerfile fertsjintwurdiget. Elke laach stiet foar de delta fan feroaringen yn 'e ûnderlizzende laach. As wy in Docker-ôfbylding út it register lûke, wurdt it yn lagen lutsen en op 'e host bewarre.
Spring Boot brûkt "fat JAR" yn as it standert ferpakkingsformaat. As wy sjogge nei in fet JAR, wy sjogge dat de applikaasje is in hiel lyts part fan de hiele JAR. Dit is it diel dat it meast feroaret. De rest bestiet út Spring Framework ôfhinklikens.
De optimalisaasjeformule is sintraal om it isolearjen fan de applikaasje op in apart nivo fan Spring Framework-ôfhinklikens.
De ôfhinklikheidslaach dy't it grutste part fan it dikke JAR-bestân foarmet, wurdt mar ien kear ynladen en yn it cache op it hostsysteem bewarre.
Allinich in tinne laach fan 'e app wurdt lutsen tidens app-updates en kontenerplanning, lykas werjûn yn dit diagram:
Yn 'e folgjende seksjes sille wy sjen hoe't jo dizze optimalisearre ôfbyldings kinne meitsje foar in Spring Boot-applikaasje.
Bouwe in optimisearre kontenerôfbylding foar in Spring Boot-applikaasje mei Buildpack
Spring Boot 2.3 stipet lagen troch dielen fan in dikke JAR-bestân te ekstrahearjen yn aparte lagen. De lagenfunksje is standert útskeakele en moat eksplisyt ynskeakele wurde mei it Spring Boot Maven-plugin:
Wy sille dizze konfiguraasje brûke om ús kontenerôfbylding earst te bouwen mei Buildpack en dan mei Docker yn 'e folgjende seksjes.
Litte wy drave build-imageMaven doel om in kontenerôfbylding te meitsjen:
mvn spring-boot:build-image
As wy Dive útfiere om de lagen yn 'e resultearjende ôfbylding te sjen, kinne wy sjogge dat de applikaasjelaach (omjûn yn read) folle lytser is yn it kilobyteberik yn ferliking mei wat wy krigen mei it dikke JAR-formaat:
Bouwe in optimisearre kontenerôfbylding foar in Spring Boot-applikaasje mei Docker
Ynstee fan in Maven- of Gradle-plugin te brûken, kinne wy ek in lagen Docker JAR-ôfbylding meitsje mei in Docker-bestân.
As wy Docker brûke, moatte wy twa ekstra stappen nimme om de lagen te ekstrahearjen en te kopiearjen yn 'e definitive ôfbylding.
De ynhâld fan 'e resultearjende JAR nei it bouwen mei Maven mei lagen ynskeakele sil der sa útsjen:
De útfier toant in ekstra JAR neamd spring-boot-jarmode-layertoolsи layersfle.idxmap. Dit ekstra JAR-bestân leveret laachmooglikheden, lykas beskreaun yn 'e folgjende paragraaf.
Extract ôfhinklikens op aparte lagen
Om lagen te besjen en te ekstrahearjen fan ús lagen JAR, brûke wy it systeemeigenskip -Djarmode=layertoolsfoar start spring-boot-jarmode-layertoolsJAR ynstee fan tapassing:
It útfieren fan dit kommando produsearret in útfier mei de beskikbere kommando-opsjes:
Usage:
java -Djarmode=layertools -jar usersignup-0.0.1-SNAPSHOT.jar
Available commands:
list List layers from the jar that can be extracted
extract Extracts layers from the jar for image creation
help Help about any command
De útfier toant de kommando's list, extractи helpс helpde standert wêze. Litte wy it kommando útfiere mei listopsje:
java -Djarmode=layertools -jar target/usersignup-0.0.1-SNAPSHOT.jar list
Wy sjogge in list mei ôfhinklikens dy't kinne wurde tafoege as lagen.
Standert lagen:
Laach namme
Ynhâld
dependencies
elke ôfhinklikens waans ferzje gjin SNAPSHOT befettet
spring-boot-loader
JAR Loader Classes
snapshot-dependencies
elke ôfhinklikens waans ferzje SNAPSHOT befettet
application
applikaasje klassen en boarnen
Lagen wurde definiearre yn layers.idxtriem yn 'e folchoarder wêryn't se moatte wurde tafoege oan de Docker-ôfbylding. Dizze lagen wurde nei it earste opheljen op 'e host yn 'e cache bewarre, om't se net feroarje. Allinich de bywurke applikaasjelaach wurdt ynladen nei de host, wat rapper is troch de fermindere grutte .
It bouwen fan in ôfbylding mei ôfhinklikens ekstrahearre yn aparte lagen
Wy sille bouwe de definitive ôfbylding yn twa stappen mei help fan in metoade neamd multi-stage gearkomste . Yn 'e earste stap sille wy de ôfhinklikens ekstrahearje en yn' e twadde stap sille wy de ekstrahearre ôfhinklikens kopiearje nei de finale.
Litte wy ús Dockerfile wizigje foar in multi-stage build:
# the first stage of our build will extract the layers
FROM adoptopenjdk:14-jre-hotspot as builder
WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract
# the second stage of our build will copy the extracted layers
FROM adoptopenjdk:14-jre-hotspot
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
Wy bewarje dizze konfiguraasje yn in apart bestân - Dockerfile2.
Wy bouwe de Docker-ôfbylding mei it kommando:
docker build -f Dockerfile2 -t usersignup:v1 .
Nei it útfieren fan dit kommando krije wy de folgjende útfier:
Sending build context to Docker daemon 20.41MB
Step 1/12 : FROM adoptopenjdk:14-jre-hotspot as builder
14-jre-hotspot: Pulling from library/adoptopenjdk
.
.
Successfully built a9ebf6970841
Successfully tagged userssignup:v1
Wy kinne sjen dat de Docker-ôfbylding is makke mei in ôfbyldings-ID en dan tagged.
Uteinlik rinne wy it kommando Dive lykas earder om de lagen yn 'e generearre Docker-ôfbylding te kontrolearjen. Wy kinne in ôfbyldings-ID of tag leverje as ynfier foar it Dive-kommando:
dive userssignup:v1
Lykas jo kinne sjen fan 'e útfier, is de laach mei de applikaasje no mar 11 KB en de ôfhinklikens wurde yn aparte lagen bewarre.
Extract ynterne ôfhinklikens op aparte lagen
Wy kinne de grutte fan 'e applikaasjelaach fierder ferminderje troch ien fan ús oanpaste ôfhinklikens te ekstrahearjen yn in aparte laach ynstee fan se te ferpakken mei de applikaasje troch se te ferklearjen yn ymlferlykbere triem neamd layers.idx:
Yn dizze triem layers.idxwy hawwe in oanpaste ôfhinklikens tafoege mei de namme, io.myorgmei organisaasjeôfhinklikens ophelle út it dielde repository.
konklúzje
Yn dit artikel hawwe wy sjoen nei it brûken fan Cloud-Native Buildpacks om in kontenerôfbylding direkt fan boarne te bouwen. Dit is in alternatyf foar it brûken fan Docker om in kontenerôfbylding op 'e gewoane manier te meitsjen: earst wurdt in dikke útfierbere JAR-bestân oanmakke en dan ferpakt yn in kontenerôfbylding troch de ynstruksjes yn' e Dockerfile op te jaan.
Wy hawwe ek sjoen nei it optimalisearjen fan ús kontener troch in lagenfunksje op te nimmen dy't ôfhinklikens ekstrahearret yn aparte lagen dy't yn 'e cache binne op' e host en in tinne applikaasjelaach wurdt laden op 'e skematiid yn' e útfieringsmotoren fan 'e kontener.
Jo kinne fine alle boarne koade brûkt yn it artikel op Github .
Kommando Referinsje
Hjir is in gearfetting fan 'e kommando's dy't wy yn dit artikel hawwe brûkt foar in rappe referinsje.
Kontekst wiskje:
docker system prune -a
Bouwe in kontenerôfbylding mei in Dockerfile:
docker build -f <Docker file name> -t <tag> .
Bou containerôfbylding fan boarne (sûnder Dockerfile):
mvn spring-boot:build-image
Besjoch ôfhinklikheidlagen. Foardat jo it applikaasje-jar-bestân bouwe, soargje derfoar dat de lagenfunksje ynskeakele is yn 'e spring-boot-maven-plugin:
java -Djarmode=layertools -jar application.jar list
Extract ôfhinklikheid lagen. Foardat jo it applikaasje-jar-bestân bouwe, soargje derfoar dat de lagenfunksje ynskeakele is yn 'e spring-boot-maven-plugin: