Pagtukod og Optimized Docker Images alang sa usa ka Spring Boot Application

Ang mga sudlanan nahimo nang pinalabi nga paagi sa pagputos sa usa ka aplikasyon sa tanan nga mga dependency sa software ug operating system ug dayon ihatud kini sa lainlaing mga palibot.

Kini nga artikulo naglangkob sa lainlaing mga paagi sa pag-container sa usa ka aplikasyon sa Spring Boot:

  • paghimo og docker image gamit ang dockerfile,
  • paghimo og OCI nga imahe gikan sa gigikanan gamit ang Cloud-Native Buildpack,
  • ug pag-optimize sa imahe sa runtime pinaagi sa pagbulag sa mga bahin sa JAR sa lainlaing lebel gamit ang mga layered nga himan.

 Pananglitan sa code

Kini nga artikulo giubanan sa usa ka pananglitan sa pagtrabaho nga code sa GitHub .

Terminolohiya sa sudlanan

Magsugod kami sa terminolohiya sa sudlanan nga gigamit sa tibuuk nga artikulo:

  • Imahe sa sudlanan: usa ka file sa usa ka piho nga format. Gibag-o namon ang among aplikasyon sa usa ka sulud nga imahe pinaagi sa pagpadagan sa tool sa pagtukod.
  • Kontainer: Usa ka executable nga pananglitan sa hulagway sa sudlanan.
  • Kontainer nga makina: Ang proseso sa daemon nga responsable sa pagpadagan sa sudlanan.
  • Container host: Ang host computer diin nagdagan ang container engine.
  • Rehistro sa sudlanan: Ang kinatibuk-ang lokasyon nga gigamit sa pagmantala ug pag-apod-apod sa imahen sa sudlanan.
  • OCI nga sumbananOpen Container Initiative (OCI) usa ka gaan, bukas nga gigikanan nga balangkas sa pagdumala nga naporma sa Linux Foundation. Ang OCI Image Specification naghubit sa mga sumbanan sa industriya alang sa mga format sa imahe sa sudlanan ug ang runtime aron masiguro nga ang tanan nga mga makina sa sulud mahimo’g makadagan ang mga imahe sa sulud nga gihimo sa bisan unsang himan sa pagtukod.

Aron ma-container ang usa ka aplikasyon, among giputos ang among aplikasyon sa usa ka sulud nga imahe ug gipatik kana nga imahe sa publiko nga rehistro. Ang container runtime nagkuha niini nga hulagway gikan sa registry, nag-unpack niini, ug nagpadagan sa aplikasyon sulod niini.

Ang Bersyon 2.3 sa Spring Boot naghatag og mga plugins alang sa paghimo og mga imahe sa OCI.

Docker mao ang labing kasagarang gigamit nga pagpatuman sa sudlanan, ug gigamit namon ang Docker sa among mga pananglitan, mao nga ang tanan nga nagsunod nga mga pakisayran sa sulud sa kini nga artikulo magtumong sa Docker.

Pagtukod og imahen sa sudlanan sa tradisyonal nga paagi

Ang paghimo sa mga imahe sa Docker alang sa mga aplikasyon sa Spring Boot dali ra pinaagi sa pagdugang pipila ka mga panudlo sa imong Dockerfile.

Naghimo una kami og usa ka executable JAR ug, isip kabahin sa mga instruksyon sa Dockerfile, kopyaha ang executable JAR sa ibabaw sa base nga JRE nga imahe human magamit ang gikinahanglan nga mga customization.

Himoon nato ang atong Spring application sa Spring Initializr uban sa dependencies weblombokΠΈ actuator. Nagdugang usab kami usa ka tigkontrol sa pagpahulay aron mahatagan usa ka API GETpamaagi.

Paghimo usa ka Dockerfile

Among ibutang kini nga aplikasyon sa usa ka sudlanan pinaagi sa pagdugang Dockerfile:

FROM adoptopenjdk:11-jre-hotspot
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/application.jar"]

Ang among Dockerfile adunay usa ka base nga imahe, gikan sa adoptopenjdk, sa ibabaw niini gikopya namo ang among JAR file ug dayon ablihan ang pantalan, 8080nga maminaw sa mga hangyo.

Asembliya sa aplikasyon

Una kinahanglan nimo nga maghimo usa ka aplikasyon gamit ang Maven o Gradle. Dinhi among gigamit ang Maven:

mvn clean package

Naghimo kini og executable nga JAR file alang sa aplikasyon. Kinahanglan natong i-convert kining executable JAR ngadto sa Docker image aron modagan sa Docker engine.

Paghimo og hulagway sa sudlanan

Gibutang namon kini nga JAR nga ma-executable sa imahe sa Docker pinaagi sa pagpadagan sa mando docker buildgikan sa root directory sa proyekto nga naglangkob sa Dockerfile nga gihimo sa sayo pa:

docker build  -t usersignup:v1 .

Makita namon ang among imahe sa lista nga adunay mando:

docker images 

Ang output sa sugo sa ibabaw naglakip sa atong larawan usersignupkauban ang base nga imahe, adoptopenjdkgipiho sa among Dockerfile.

REPOSITORY          TAG                 SIZE
usersignup          v1                  249MB
adoptopenjdk        11-jre-hotspot      229MB

Tan-awa ang mga layer sa sulod sa usa ka sulud nga imahe

Atong tan-awon ang stack sa mga layer sa sulod sa imahe. Atong gamiton instrumento  dive aron makita kini nga mga layer:

dive usersignup:v1

Ania ang bahin sa output sa Dive command: 

Pagtukod og Optimized Docker Images alang sa usa ka Spring Boot Application

Sama sa atong nakita, ang layer sa aplikasyon naglangkob sa usa ka hinungdanon nga bahin sa gidak-on sa imahe. Gusto namong pakunhuran ang gidak-on niini nga layer sa mosunod nga mga seksyon isip kabahin sa among pag-optimize.

Paghimo usa ka sulud nga imahe gamit ang Buildpack

Mga pakete sa asembliya (Mga Buildpack) kay usa ka generic nga termino nga gigamit sa nagkalain-laing Platform as a Service (PAAS) nga mga tanyag aron makamugna og container image gikan sa source code. Gilunsad kini ni Heroku kaniadtong 2011 ug sukad gisagop sa Cloud Foundry, Google App Engine, Gitlab, Knative ug uban pa.

Pagtukod og Optimized Docker Images alang sa usa ka Spring Boot Application

Bentaha sa Cloud Build Packages

Usa sa mga nag-unang bentaha sa paggamit sa Buildpack sa paghimo og mga imahe mao kana Ang mga pagbag-o sa pagsumpo sa imahe mahimong madumala sa sentro (magtutukod) ug ipakaylap sa tanan nga mga aplikasyon gamit ang tigtukod.

Ang mga pakete sa pagtukod hugot nga gihigot sa plataporma. Ang Cloud-Native Buildpacks naghatag og standardization sa mga platform pinaagi sa pagsuporta sa OCI image format, nga nagsiguro nga ang imahe mahimong ipadagan sa Docker engine.

Paggamit sa Spring Boot Plugin

Ang Spring Boot plugin nagtukod og OCI nga mga hulagway gikan sa tinubdan gamit ang Buildpack. Ang mga imahe gihimo gamit ang bootBuildImagemga buluhaton (Gradle) o spring-boot:build-imagetarget (Maven) ug lokal nga pag-instalar sa Docker.

Mahimo namon nga ipasibo ang ngalan sa imahe nga kinahanglan namon nga iduso sa rehistro sa Docker pinaagi sa pagtino sa ngalan sa image tag:

<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <configuration>
    <image>
      <name>docker.io/pratikdas/${project.artifactId}:v1</name>
    </image>
  </configuration>
</plugin>

Atong gamiton ang Maven sa pag-execute build-imagemga tumong alang sa paghimo sa usa ka aplikasyon ug paghimo sa usa ka sudlanan nga imahe. Wala kami karon naggamit bisan unsang Dockerfiles.

mvn spring-boot:build-image

Ang resulta mahimong sama niini:

[INFO] --- spring-boot-maven-plugin:2.3.3.RELEASE:build-image (default-cli) @ usersignup ---
[INFO] Building image 'docker.io/pratikdas/usersignup:v1'
[INFO] 
[INFO]  > Pulling builder image 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 0%
.
.
.. [creator]     Adding label 'org.springframework.boot.version'
.. [creator]     *** Images (c311fe74ec73):
.. [creator]           docker.io/pratikdas/usersignup:v1
[INFO] 
[INFO] Successfully built image 'docker.io/pratikdas/usersignup:v1'

Gikan sa output, atong makita kana paketo Cloud-Native buildpackgigamit sa paghimo sa usa ka nagtrabaho nga OCI nga imahe. Sama kaniadto, atong makita ang imahe nga gilista ingon usa ka imahe sa Docker pinaagi sa pagpadagan sa mando:

docker images 

Panapos:

REPOSITORY                             SIZE
paketobuildpacks/run                  84.3MB
gcr.io/paketo-buildpacks/builder      652MB
pratikdas/usersignup                  257MB

Paghimo og Imahe sa Kontainer nga adunay Jib

Ang Jib kay usa ka image authoring plugin gikan sa Google nga naghatag ug alternatibong pamaagi sa paghimo og container image gikan sa tinubdan.

Pag-configure jib-maven-pluginsa pom.xml:

      <plugin>
        <groupId>com.google.cloud.tools</groupId>
        <artifactId>jib-maven-plugin</artifactId>
        <version>2.5.2</version>
      </plugin>

Sunod, gipadagan namon ang Jib plugin gamit ang Maven command aron matukod ang aplikasyon ug maghimo sa sulud nga imahe. Sama kaniadto, wala kami naggamit bisan unsang Dockerfiles dinhi:

mvn compile jib:build -Dimage=<docker registry name>/usersignup:v1

Human sa pagpatuman sa labaw sa Maven nga sugo, atong makuha ang mosunod nga output:

[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

Ang output nagpakita nga ang sudlanan nga imahen gihimo ug gibutang sa registry.

Mga motibo ug mga pamaagi sa paghimo og mga optimized nga mga imahe

Adunay kami duha ka panguna nga hinungdan sa pag-optimize:

  • Pag-uswag: Sa usa ka container orchestration system, usa ka container image ang gikuha gikan sa image registry ngadto sa host nga nagpadagan sa container engine. Kini nga proseso gitawag nga pagplano. Ang pagbira sa dagkong mga hulagway gikan sa rehistro moresulta sa taas nga mga oras sa pag-iskedyul sa mga container orchestration system ug taas nga mga panahon sa pagtukod sa mga pipeline sa CI.
  • Kasegurohan: dako nga mga hulagway usab adunay usa ka dako nga dapit alang sa mga kahuyang.

Ang usa ka imahe sa Docker gilangkuban sa usa ka stack sa mga layer, ang matag usa nagrepresentar sa usa ka pahayag sa among Dockerfile. Ang matag layer nagrepresentar sa delta sa mga pagbag-o sa nagpahiping layer. Kung gibira namon ang usa ka imahe sa Docker gikan sa rehistro, gibira kini sa mga layer ug gi-cache sa host.

Gigamit ang Spring Boot "tambok nga JAR" sa isip default nga pormat sa pagputos. Kung atong tan-awon ang usa ka tambok nga JAR, atong makita nga ang aplikasyon usa ka gamay nga bahin sa tibuuk nga JAR. Kini ang bahin nga labing nagbag-o. Ang uban naglangkob sa Spring Framework dependencies.

Ang pormula sa pag-optimize nasentro sa pag-isolate sa aplikasyon sa lahi nga lebel gikan sa mga dependency sa Spring Framework.

Ang dependency layer nga nagporma sa kinabag-an sa baga nga JAR file kausa ra ma-download ug gi-cache sa host system.

Usa lang ka nipis nga layer sa app ang makuha sa panahon sa pag-update sa app ug pag-iskedyul sa sudlanan, sama sa gipakita niini nga diagram:

Pagtukod og Optimized Docker Images alang sa usa ka Spring Boot Application

Sa mosunud nga mga seksyon, atong tan-awon kung giunsa paghimo kini nga na-optimize nga mga imahe para sa aplikasyon sa Spring Boot.

Pagtukod ug Optimized Container Image para sa Spring Boot Application gamit ang Buildpack

Ang Spring Boot 2.3 nagsuporta sa layering pinaagi sa pagkuha sa mga bahin sa usa ka baga nga JAR file ngadto sa lain nga mga layer. Ang bahin sa layering gi-disable pinaagi sa default ug kinahanglan nga klaro nga magamit gamit ang Spring Boot Maven plugin:

<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <configuration>
    <layers>
      <enabled>true</enabled>
    </layers>
  </configuration> 
</plugin>

Gamiton namo kini nga configuration aron matukod una ang among container image sa Buildpack ug dayon sa Docker sa mosunod nga mga seksyon.

Dagan ta build-imageTarget sa Maven nga maghimo usa ka sulud nga imahe:

mvn spring-boot:build-image

Kung kita modagan sa Dive aron makita ang mga lut-od sa resulta nga hulagway, atong makita nga ang application layer (gilingin nga pula) mas gamay sa kilobyte range kon itandi sa atong nakuha gamit ang baga nga JAR format:

Pagtukod og Optimized Docker Images alang sa usa ka Spring Boot Application

Pagtukod og usa ka Optimized Container Image alang sa usa ka Spring Boot Application uban sa Docker

Imbis nga mogamit usa ka plugin nga Maven o Gradle, mahimo usab naton maghimo usa ka layered nga Docker JAR nga imahe nga adunay usa ka Docker file.

Kung gigamit namon ang Docker, kinahanglan namon nga maghimo og duha ka dugang nga mga lakang aron makuha ang mga layer ug kopyahon kini sa katapusan nga imahe.

Ang sulod sa resulta nga JAR human sa pagtukod uban sa Maven nga adunay layering enabled mahimong sama niini:

META-INF/
.
BOOT-INF/lib/
.
BOOT-INF/lib/spring-boot-jarmode-layertools-2.3.3.RELEASE.jar
BOOT-INF/classpath.idx
BOOT-INF/layers.idx

Ang output nagpakita sa usa ka dugang nga JAR nga ginganlan spring-boot-jarmode-layertoolsΠΈ layersfle.idxfile. Kining dugang nga JAR file naghatag og mga kapabilidad sa pagpatong, sama sa gihulagway sa sunod nga seksyon.

I-extract ang mga dependency sa separado nga mga layer

Aron matan-aw ug makuha ang mga layer gikan sa among layered JAR, among gigamit ang system property -Djarmode=layertoolsalang sa pagsugod spring-boot-jarmode-layertoolsJAR imbes nga aplikasyon:

java -Djarmode=layertools -jar target/usersignup-0.0.1-SNAPSHOT.jar

Ang pagpadagan niini nga sugo nagpatunghag usa ka output nga adunay anaa nga mga kapilian sa sugo:

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

Ang output nagpakita sa mga sugo listextractΠΈ helpс helpmahimong default. Atong padagan ang sugo sa listkapilian:

java -Djarmode=layertools -jar target/usersignup-0.0.1-SNAPSHOT.jar list
dependencies
spring-boot-loader
snapshot-dependencies
application

Nakita namon ang usa ka lista sa mga dependency nga mahimong idugang ingon mga layer.

Mga lut-od pinaagi sa default:

Ngalan sa layer

Mga sulod

dependencies

bisan unsang dependency kansang bersyon walay SNAPSHOT

spring-boot-loader

Mga Klase sa JAR Loader

snapshot-dependencies

bisan unsang dependency kansang bersyon adunay SNAPSHOT

application

mga klase sa aplikasyon ug mga kapanguhaan

Ang mga lut-od gihubit sa layers.idxfile sa han-ay diin sila kinahanglan nga idugang sa imahe sa Docker. Kini nga mga layer gi-cache sa host pagkahuman sa una nga pagkuha tungod kay wala kini mausab. Ang gi-update nga layer sa aplikasyon lamang ang na-download sa host, nga mas paspas tungod sa pagkunhod sa gidak-on .

Pagtukod og usa ka hulagway nga adunay mga dependency nga gikuha ngadto sa lain nga mga layer

Atong tukuron ang kataposang hulagway sa duha ka lakang gamit ang pamaagi nga gitawag multi-stage nga asembliya . Sa unang lakang atong kuhaon ang mga dependency ug sa ikaduhang lakang atong kopyahon ang gikuha nga dependencies ngadto sa final .

Atong usbon ang atong Dockerfile alang sa usa ka multi-stage nga pagtukod:

# 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"]

Gitipigan namon kini nga pag-configure sa usa ka lahi nga file - Dockerfile2.

Gitukod namon ang imahe sa Docker gamit ang mando:

docker build -f Dockerfile2 -t usersignup:v1 .

Human sa pagpatuman niini nga sugo, atong makuha ang mosunod nga output:

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

Atong makita nga ang imahe sa Docker gihimo gamit ang usa ka ID sa imahe ug dayon gi-tag.

Sa katapusan, among gipadagan ang Dive command sama kaniadto aron susihon ang mga layer sa sulod sa namugna nga Docker nga imahe. Makahatag kami ug image ID o tag isip input sa Dive command:

dive userssignup:v1

Sama sa imong makita gikan sa output, ang layer nga adunay sulud nga aplikasyon karon 11 KB na lang ug ang mga dependency gi-cache sa lainlaing mga layer. 

Pagtukod og Optimized Docker Images alang sa usa ka Spring Boot Application

I-extract ang internal dependencies sa separado nga layers

Mahimo pa namon nga mapakunhod ang gidak-on sa layer sa aplikasyon pinaagi sa pagkuha sa bisan unsa sa among naandan nga mga dependency sa usa ka lahi nga layer imbis nga iputos kini sa aplikasyon pinaagi sa pagdeklarar niini sa ymlparehas nga file nga gihinganlan layers.idx:

- "dependencies":
  - "BOOT-INF/lib/"
- "spring-boot-loader":
  - "org/"
- "snapshot-dependencies":
- "custom-dependencies":
  - "io/myorg/"
- "application":
  - "BOOT-INF/classes/"
  - "BOOT-INF/classpath.idx"
  - "BOOT-INF/layers.idx"
  - "META-INF/"

Sa kini nga file layers.idxgidugang namo ang usa ka custom dependency nga ginganlan, io.myorgnga adunay mga dependency sa organisasyon nga nakuha gikan sa gipaambit nga repository.

konklusyon

Sa kini nga artikulo, among gitan-aw ang paggamit sa Cloud-Native Buildpacks aron makahimo usa ka imahe sa sulud nga direkta gikan sa gigikanan. Kini usa ka alternatibo sa paggamit sa Docker sa paghimo sa usa ka sudlanan nga imahe sa naandan nga paagi: una, usa ka baga nga executable JAR file ang gihimo ug dayon giputos sa usa ka sulud nga imahe pinaagi sa pagtino sa mga panudlo sa Dockerfile.

Gitan-aw usab namo ang pag-optimize sa among sudlanan pinaagi sa paglakip sa feature sa layering nga nagkuha sa mga dependency ngadto sa separado nga mga layer nga gi-cache sa host ug usa ka nipis nga layer sa aplikasyon ang gikarga sa oras sa pag-iskedyul sa mga makina sa pagpatuman sa container.

Makita nimo ang tanang source code nga gigamit sa artikulo sa Github .

Reperensya sa Sugo

Ania ang usa ka summary sa mga sugo nga among gigamit niini nga artikulo alang sa usa ka dali nga pakisayran.

Paglimpyo sa konteksto:

docker system prune -a

Paghimo usa ka imahen sa sulud nga adunay usa ka Dockerfile:

docker build -f <Docker file name> -t <tag> .

Paghimo usa ka sulud nga imahe gikan sa gigikanan (walay Dockerfile):

mvn spring-boot:build-image

Tan-awa ang dependency layer. Sa dili pa magtukod sa application jar file, siguroha nga ang layering feature gipalihok sa spring-boot-maven-plugin:

java -Djarmode=layertools -jar application.jar list

Kuhaa ang dependency layer. Sa dili pa magtukod sa application jar file, siguroha nga ang layering feature gipalihok sa spring-boot-maven-plugin:

 java -Djarmode=layertools -jar application.jar extract

Pagtan-aw sa Listahan sa mga Imahen sa Kontainer

docker images

Tan-awa sa wala sa sulod sa laragway sa sudlanan (siguroha nga na-install ang himan sa pag-dive):

dive <image ID or image tag>

Source: www.habr.com