Kontejnerët janë bërë mjeti i preferuar për paketimin e aplikacioneve me të gjitha varësitë e softuerit dhe sistemin operativ, dhe pastaj dorëzimin e tyre në mjedise të ndryshme.
Në këtë artikull shqyrtohen mënyrat e ndryshme për konteinerizimin e aplikacioneve Spring Boot:
- krijimi i një imazhi Docker me anë të skedarit Docker,
- krijimi i një imazhi OCI nga kodi burimor me anë të Cloud-Native Buildpack,
- dhe optimizimi i imazhit gjatë ekzekutimit duke ndarë pjesët JAR në nivele të ndryshme me anë të mjeteve shumë-nivelëshe.
 Shembulli i kodit
Ky artikull shoqërohet me një shembull kodi në punë  .
Terminologjia e kontejnerëve
Do të fillojmë me terminologjinë e kontejnerëve që përdoret në artikull:
- Imazhi i kontejnerit (Container image): një skedar me format të caktuar. Ne e konvertojmë aplikacionin tonë në një imazh kontejneri duke ekzekutuar një mjet ndërtimi.
- Konteineri: një ekzemplar ekzekutiv i imazhit të kontejnerit.
- Motori i kontejnerit (Container engine): proces demoni që është përgjegjës për ekzekutimin e kontejnerit.
- Hosti i kontejnerit (Container host): kompjuteri host në të cilin funksionon mekanizmi i kontejnerit.
- Regjistri i kontejnerëve (Container registry): një vend i zakonshëm i përdorur për publikimin dhe shpërndarjen e imazheve të kontejnerëve.
- Standardi OCI: â Ă«shtĂ« njĂ« strukturĂ« e lehtĂ« e hapur e administratĂ«s, e formuar nĂ«n Linux Foundation. Specifikimi i imazheve OCI pĂ«rcakton standardet e industrisĂ« pĂ«r format e imazheve tĂ« kontejnerĂ«ve dhe mjediseve tĂ« ekzekutimit, pĂ«r tĂ« garantuar se tĂ« gjithĂ« mekanizmat e kontejnerĂ«ve mund tĂ« ekzekutojnĂ« imazhet e kontejnerĂ«ve tĂ« krijuar nga çdo mjet ndĂ«rtimi.
Për të vendosur aplikacionin në kontejner, ne e mbështjellim aplikacionin tonë në një imazh kontejneri dhe e publikojmë këtë imazh në një regjistër të zakonshëm. Mjedisi i ekzekutimit të kontejnerit e nxjerr këtë imazh nga regjistri, e shpërndan atë dhe ekzekuton aplikacionin brenda tij.
Versioni 2.3 i Spring Boot ofron plugina për krijimin e imazheve OCI.
â implementimi mĂ« i pĂ«rdorur i kontejnerĂ«ve, dhe ne pĂ«rdorim Docker nĂ« shembujt tanĂ«, prandaj tĂ« gjitha referencat e mĂ«tejshme pĂ«r kontejner nĂ« kĂ«tĂ« artikull do tĂ« nĂ«nkuptojnĂ« Docker.
Krijimi i imazhit të kontejnerit në mënyrë tradicionale
Të krijosh imazhe Docker për aplikacionet Spring Boot është shumë e lehtë, duke shtuar disa udhëzime në skedarin Docker.
Së pari, ne krijojmë një skedar executiv JAR dhe, si pjesë e instrukcioneve të skedarit Docker, kopjojmë skedarin executiv JAR mbi imazhin bazë JRE pas aplikimit të cilësimeve të nevojshme.
Le të krijojmë aplikacionin tonë Spring në  me varësi web, lombokdhe actuator. Ne gjithashtu shtojmë një kontrollues rest për të ofruar API me GETmetodën.
Krijimi i skedarit Docker
Pastaj ne vendosim këtë aplikacion në kontejner, duke shtuar Dockerfile:
FROM adoptopenjdk:11-jre-hotspot
ARG JAR_FILE=target
/*.jar
COPY ${JAR_FILE} application.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/application.jar"]Skedari ynë Docker përmban një imazh bazë, nga adoptopenjdk, mbi të cilin kopjojmë skedarin tonë JAR, dhe pastaj hapim portin, 8080i cili do të dëgjojë për kërkesa.
Ndërtime aplikacionesh
E para që duhet bërë është krijimi i aplikacionit me Maven ose Gradle. Këtu ne përdorim Maven:
mvn clean packageKjo krijon skedarin executiv JAR të aplikacionit. Na nevojitet ta konvertojmë këtë JAR në një imazh Docker për ta funksionuar në motorin Docker.
Krijimi i imazhit të kontejnerit
Pastaj ne vendosim këtë skedar executiv JAR në imazhin Docker, duke ekzekutuar komandën docker buildnga katalogu rrënjor i projektit që përmban skedarin Docker, të krijuar më parë:
docker build -t usersignup:v1 .Ne mund ta shohim imazhin tonë në listë me komandën:
docker images Rezultati i ekzekutimit të komandës së mësipërme përfshin imazhin tonë usersignupbashkë me imazhin bazë, adoptopenjdk, të specifikuar në skedarin tonë Docker.
REPOSITORY TAG SIZE
usersignup v1 249MB
adoptopenjdk 11-jre-hotspot 229MBShikimi i shtresave brenda imazhit të kontejnerit
Le të shohim në grumbullin e shtresave brenda imazhit. Ne do të përdorim   për të parë këto shtresa:
dive usersignup:v1Ja njĂ« pjesĂ« e rezultateve tĂ« ekzekutimit tĂ« komandĂ«s Dive:Â

Siç e shohim, niveli aplikativ përbën një pjesë të konsiderueshme të madhësisë së imazhit. Ne duam ta zvogëlojmë madhësinë e këtij niveli në seksionet e ardhshme si pjesë e optimizimit tonë.
Krijimi i imazhit të kontejnerit me Buildpack
() është një term i zakonshëm i përdorur nga oferta të ndryshme të "Platformës si Shërbim" (PAAS) për të ndërtuar një imazh kontejneri nga kodi burimor. Ai u lançua nga Heroku në vitin 2011 dhe që atëherë është pranuar nga Cloud Foundry, Google App Engine, Gitlab, Knative dhe disa të tjera.

Përfitimi i paketave të ndërtimit në re
Një nga përfitimet kryesore të përdorimit të Buildpack për të krijuar imazhe është se me ndryshimet e konfigurimit të imazhit mund të menaxhohen në mënyrë qendrore (builder) dhe të shpërndahen në të gjitha aplikacionet që përdorin builder.
Paketat ndërtuese ishin të lidhura ngushtë me platformën. Cloud-Native Buildpacks ofrojnë standardizim mes platformave, duke mbështetur formatin e imazhit OCI, i cili garanton se imazhi mund të ekzekutohet nga motori Docker.
Përdorimi i plugin-it Spring Boot
Plugin-i Spring Boot krijon imazhe OCI nga kodin burimor duke përdorur Buildpack. Imazhet krijohen duke përdorur bootBuildImagedetyrat (Gradle) ose spring-boot:build-imageqëllimet (Maven) dhe instalimin lokal të Docker.
Mund të konfigurojmë emrin e imazhit që nevojitet për t'u dërguar në regjistrin Docker, duke treguar emrin në image tag:
org.springframework.boot
spring-boot-maven-plugin
docker.io/pratikdas/${project.artifactId}:v1Të përdorim Maven për të kryer build-imageqëllimin për ndërtimin e aplikacionit dhe krijimin e imazhit të kontejnerit. Tani nuk po përdorim asnjë skedar Docker.
mvn spring-boot:build-imageRezultati do të jetë diçka e tillë:
[INFO] --- spring-boot-maven-plugin:2.3.3.RELEASE:build-image (default-cli) @ usersignup ---
[INFO] Ndërtimi i imazhit 'docker.io/pratikdas/usersignup:v1'
[INFO]
[INFO] > Duke tërhequr imazhin ndërtues 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 0%
.
.
.. [krijuesi] Shtimi i etiketës 'org.springframework.boot.version'
.. [krijuesi] *** Imazhet (c311fe74ec73):
.. [krijuesi] docker.io/pratikdas/usersignup:v1
[INFO]
[INFO] Imazhi 'docker.io/pratikdas/usersignup:v1' u ndërtua me suksesNga të dhënat e daljes, shohim se paketo Cloud-Native buildpackpërdoret për të krijuar një imazh OCI të funksionshëm. Ashtu si më parë, mund të shohim imazhin e specifikuar si imazh Docker duke ekzekutuar komandën:
docker images Përfundimi:
REPOSITORY SIZE
paketobuildpacks/run 84.3MB
gcr.io/paketo-buildpacks/builder 652MB
pratikdas/usersignup 257MBKrijimi i imazhit të kontejnerit me Jib
Jib është një plugin për ndërtimin e imazheve nga Google që ofron një metodë alternative për ndërtimin e imazhit të kontejnerit nga kodin burimor.
Konfigurojmë jib-maven-pluginnë pom.xml:
com.google.cloud.tools
jib-maven-plugin
2.5.2Pastaj, ne ekzekutojmë plugin-in Jib duke përdorur komandën Maven për të ndërtuar aplikacionin dhe krijuar imazhin e kontejnerit. Ashtu si më parë, këtu nuk po përdorim asnjë skedar Docker:
mvn compile jib:build -Dimage=/usersignup:v1Pas ekzekutimit të komandës Maven të specifikuar më lart, ne marrim daljen e mëposhtme:
[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% completeTë dhënat tregojnë se imazhi i kontejnerit është ndërtuar dhe vendosur në registrin.
Motivimet dhe metodat për krijimin e imazheve të optimizuara
Kemi dy arsye kryesore për optimizim:
- Performanca: në sistemin e orkestrimit të kontejnerëve, imazhi i kontejnerit tërhiqet nga registri i imazheve në hostin ku është aktivizuar mekanizmi i kontejnerit. Ky proces quhet planifikim. Tërheqja e imazheve me madhësi të madhe nga registra çon në një kohë të gjatë planifikimi në sistemet e orkestrimit të kontejnerëve dhe një kohë të gjatë ndërtimi në kanalet CI.
- Siguria: imazhet e mëdha gjithashtu kanë një hapësirë më të madhe për dobësi.
Imazhi Docker pĂ«rbĂ«het nga njĂ« shtresĂ« e grumbullit, secila pĂ«rfaqĂ«son njĂ« udhĂ«zim nĂ« Dockerfile tonĂ«. Ădo shtresĂ« pĂ«rfaqĂ«son njĂ« dytĂ« ndryshimesh nga shtresa poshtĂ«. Kur tĂ«rheqim imazhin Docker nga registri, ai tĂ«rhiqet nĂ« shtresa dhe ruhet nĂ« host.
Spring Boot përdor  Formula e optimizimit është përqendruar rreth izolimit të aplikacionit në një nivel të veçantë nga varësitë e Spring Framework.
Shtresa e varësive që formon shumicën e JAR-it të trashë ngarkohet vetëm një herë dhe ruhet në sistemin host.
Vetëm shtresa e hollë e aplikacionit tërheq gjatë përditësimeve të aplikacionit dhe planifikimit të kontejnerëve,
siç është ilustruar në këtë diagram: Në seksionet në vazhdim, ne do të shqyrtojmë se si të krijojmë këto imazhe të optimizuara për aplikacionin Spring Boot.

Krijimi i një imazhi të optimizuar të kontejnerit për aplikacionin Spring Boot me ndihmën e Buildpack
Spring Boot 2.3 mbështet shumë-shtresimin duke tërhequr pjesët e JAR-it të trashë në shtresa të veçanta. Funksionaliteti i shtresës është çaktivizuar përcaktimisht dhe duhet të aktivizohet qartë me ndihmën e plugin-it Spring Boot Maven:
Spring Boot 2.3 mbĂ«shtet shumĂ«-niveloĆshmĂ«rinĂ« duke nxjerrĂ« pjesĂ«t e njĂ« skedari tĂ« trashĂ« JAR nĂ« shtresa tĂ« veçanta. Funksioni i mbivendosjes Ă«shtĂ« i çaktivizuar nga e drejta dhe duhet tĂ« aktivizohet qartĂ« pĂ«rmes plugin-it Spring Boot Maven:
org.springframework.boot
spring-boot-maven-plugin
trueNe do ta përdorim këtë konfigurim për të krijuar imazhin tonë të kontejnerit së pari me ndihmën e Buildpack, pastaj me Docker në seksionet në vazhdim.
Le të ekzekutojmë build-imageqëllimin Maven për të krijuar imazhin e kontejnerit:
mvn spring-boot:build-imageNëse ekzekutojmë Dive për të parë shtresat në imazhin rezultues, do të shohim se shtresa e aplikacionit (e rrethuar me të kuqe) është shumë më e vogël në rangun e kilobajtëve në krahasim me atë që kemi marrë duke përdorur formatin e trashë JAR:

Krijimi i një imazhi të optimizuar të kontejnerit për aplikacionin Spring Boot me ndihmën e Docker
Në vend që të përdorim pluginin Maven ose Gradle, ne gjithashtu mund të krijojmë një imazh Docker me shumë shtresa JAR me skedarin Docker.
Kur përdorim Docker, na nevojiten dy hapa shtesë për të nxjerrë dhe kopjuar shtresat në imazhin përfundimtar.
Përmbajtja e JAR-it të marrë pas ndërtimit me ndihmën e Maven me funksionin e aktivizuar për shtresa do të duket si më poshtë:
META-INF/
.
BOOT-INF/lib/
.
BOOT-INF/lib/spring-boot-jarmode-layertools-2.3.3.RELEASE.jar
BOOT-INF/classpath.idx
BOOT-INF/layers.idxNë daljet shfaqet një JAR shtesë i quajtur spring-boot-jarmode-layertoolsdhe layersfle.idxskedari. Ky JAR shtesë ofron mundësinë e përpunimit me shumë shtresa, siç është përshkruar në seksionin e ardhshëm.
Nxjerrja e varësive në shtresa të veçanta
Për të parë dhe nxjerrë shtresat nga JAR-i ynë me shumë shtresa, ne përdorim pronë sistemike -Djarmode=layertoolspër të ekzekutuar spring-boot-jarmode-layertoolsJAR-in përveç aplikacionit:
java -Djarmode=layertools -jar target/usersignup-0.0.1-SNAPSHOT.jarEkzekutimi i kësaj komande jep një dalje që përmban opsionet e disponueshme të komandës:
Përdorimi:
java -Djarmode=layertools -jar usersignup-0.0.1-SNAPSHOT.jar
Komandat e disponueshme:
list Listo shtresat nga jar-i që mund të nxirren
extract Nxjerr shtresat nga jar-i për krijimin e imazhit
help Ndihmë për çdo komandëDalja tregon komandat list, extractdhe helpme helptë jetë në default. Le të ekzekutojmë komandën me listopsionin:
java -Djarmode=layertools -jar target/usersignup-0.0.1-SNAPSHOT.jar listdependencies
spring-boot-loader
snapshot-dependencies
applicationNe shohim një listë varësish që mund të shtohen si shtresa.
Shtresat për default:
Emri i shtresës
Përmbajtja
dependencies
çdo varësi, përfshirë versionin që nuk ka SNAPSHOT
spring-boot-loader
Klasa e ngarkuesit të JAR-it
snapshot-dependencies
çdo varësi, përfshirë versionin që ka SNAPSHOT
application
klasat e aplikacioneve dhe burimet
Shtresat janë përcaktuar në layers.idxskedën në rendin në të cilin duhet të shtohen në imazhin Docker. Këto shtresa ruhen në host pas ekstraktimit të parë, pasi ato nuk ndryshojnë. Vetëm niveli i azhurnuar i aplikacionit ngarkohet në host, që ndodh më shpejt për shkak të madhësisë më të vogël. .
Ndërtimi i imazhit me varësitë e nxjerra në shtresa të ndara.
Ne do të ndërtojmë imazhin përfundimtar në dy faza, duke përdorur një metodë të quajtur  . Në fazën e parë do të nxjerrim varësitë, dhe në fazën e dytë do t'i kopjojmë varësitë e nxjerra në imazhin përfundimtar.
Le të modifikojmë skedën tonë Docker për ndërtim shumëfazor:
# 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"]Ta ruajmĂ« kĂ«tĂ« konfigurim nĂ« njĂ« skedĂ« tĂ« veçantĂ« â Dockerfile2.
Të ndërtojmë imazhin Docker duke përdorur komandën:
docker build -f Dockerfile2 -t usersignup:v1 .Pas ekzekutimit të kësaj komande, ne marrim këtë rezultat:
Dërgimi i kontekstit të ndërtimit në daemon-in Docker 20.41MB
Hapi 1/12 : NGA adoptopenjdk:14-jre-hotspot si ndërtues
14-jre-hotspot: Po tërheq nga library/adoptopenjdk
.
.
Të ndërtuar me sukses a9ebf6970841
Etiketuar me sukses userssignup:v1Ne shohim se imazhi Docker krijohet me një identifikues imazhi dhe më pas etiketohët.
Më në fund, ne ekzekutojmë komandën Dive, ashtu si më parë, për të kontrolluar shtresat brenda imazhit të gjeneruar Docker. Ne mund të specifikojmë identifikuesin e imazhit ose etiketën si input për komandën Dive:
dive userssignup:v1Siç shihet nga rezultati, niveli qĂ« pĂ«rmban aplikacionin tani zĂ« vetĂ«m 11 KB, ndĂ«rsa varĂ«sitĂ« ruhen nĂ« shtresa tĂ« ndara.Â

Ekstraktimi i varësive të brendshme në shtresa të ndara.
Ne mund ta zvogëlojmë më tej madhësinë e nivelit të aplikacionit duke nxjerrë çdo një nga varësitë tona të personalizuara në një nivel të veçantë në vend që t'i paketojmë ato së bashku me aplikacionin, duke i shpallur ato në ymlnjë skedë të tillë të quajtur 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/"Në këtë skedë layers.idxne kemi shtuar një varësi të personalizuar me emrin, io.myorgqë përmban varësi të organizatës, të marrë nga një depo të përbashkët.
Përfundimi
Në këtë artikull ne shqyrtuam përdorimin e Buildpacks Cloud-Native për krijimin e një imazhi konteineri direkt nga kodi burimor. Kjo është një alternativë ndaj përdorimit të Docker për krijimin e imazhit të konteinerit në mënyrë të zakonshme: fillimisht krijohet një skedë e trashë ekzekutimi JAR, dhe pastaj ajo paketizohet në një imazh konteneri duke përshkruar udhëzimet në skedarin Docker.
Ne gjithashtu shqyrtuam optimizimin e konteinerit tonë, duke përfshirë funksionin e mbivendosjes, i cili nxjerr varësitë në nivele të veçanta, të cilat ruhen në host, ndërsa niveli i hollë i aplikacionit ngarkohet gjatë planifikimit në mekanizmat e ekzekutimit të konteinerit.
Mund të gjeni të gjitha kodet burimore të përdorura në artikull në  .
DHTMLP Komandat
Ja një përmbledhje e shkurtër e komandave që ne përdorëm në këtë artikull për një njohuri të shpejtë.
Pastrimi i kontekstit:
docker system prune -aKrijimi i imazhit të konteinerit me skedarin Docker:
docker build -f -t .Krijimi i imazhit të konteinerit nga kodi burimor (pa Dockerfile):
mvn spring-boot:build-imageShikoni nivelet e varësive. Para se të krijoni një skedë JAR të aplikacionit, sigurohuni që funksioni i mbivendosjes të jetë aktivizuar në spring-boot-maven-plugin:
java -Djarmode=layertools -jar application.jar listNxjerrja e niveleve të varësive. Para se të krijoni një skedë JAR të aplikacionit, sigurohuni që funksioni i mbivendosjes të jetë aktivizuar në spring-boot-maven-plugin:
java -Djarmode=layertools -jar application.jar extractShikoni listën e imazheve të konteinerëve
docker imagesShikoni nivelin brenda imazhit të konteinerit (sigurohuni që mjeti për depërtim është i instaluar):
diveBurimi: habr.com
