A konténerek a szoftver és az operációs rendszer összes függőségének csomagolására, majd ezt követően különböző környezetekbe való szállításra a preferált eszközökké váltak.
Ez a cikk különböző módszereket tárgyal a Spring Boot alkalmazás konténerizálására:
- Docker kép létrehozása Docker fájl segítségével,
- OCI kép létrehozása forráskód alapján Cloud-Native Buildpack segítségével,
- és a képek futás közbeni optimalizálása a JAR részek különböző szintjeire való felosztásával több szintű eszközökkel.
Példa kódra
Ez a cikk egy működő kódmintával van ellátva .
Konténer terminológia
Kezdjük a cikkben használt konténer terminológiával:
- Konténerkép (Container image): egy meghatározott formátumú fájl. Az alkalmazásunkat konténerképpé alakítjuk a build eszköz futtatásával.
- Konténer: a konténerkép végrehajtható példánya.
- Konténer motor (Container engine): egy démon folyamat, amely felelős a konténer futtatásáért.
- Konténer hoszt (Container host): az a számítógép, ahol a konténer motor működik.
- Konténer regiszter (Container registry): egy közös tárolóhely, amelyet a konténerkép közzétételére és terjesztésére használnak.
- OCI szabvány: – ez egy könnyű, nyílt irányítási struktúra, amely a Linux Foundation keretein belül jött létre. Az OCI képspecifikáció az iparági szabványokat határozza meg a konténerképek formátumaira és végrehajtási környezetére vonatkozóan, biztosítva, hogy minden konténer motor képes legyen az bármely build eszköz által létrehozott konténerképek futtatására.
Ahhoz, hogy az alkalmazást konténerbe helyezzük, konténerképbe zárjuk az alkalmazásunkat, és ezt a képet közzétesszük egy közös regiszterben. A konténer végrehajtási környezete ezt a képet a regiszterből letölti, kicsomagolja és az alkalmazást elindítja benne.
A 2.3-as Spring Boot verzió OCI képek létrehozásához pluginokat biztosít.
– a leggyakrabban használt konténer megvalósítás, és a példáinkban a Docker-t használjuk, ezért a cikk további részeiben a konténerre való hivatkozások a Docker-re vonatkoznak.
Konténerkép létrehozása hagyományos módon
Docker képeket létrehozni Spring Boot alkalmazásokhoz nagyon egyszerű, csak néhány utasítást kell hozzáadni a Docker fájlhoz.
Először létrehozzuk a JAR végrehajtható fájlt, és a Docker fájl utasításai részeként átmásoljuk a JAR végrehajtható fájlt a JRE alapképe fölé a szükséges beállítások alkalmazása után.
Létrehozzuk a Spring alkalmazásunkat a függőségekkel szolgáltatás szeretne hozzáférni egy, lombokés actuator. Ezenkívül hozzáadunk egy REST vezérlőt, hogy API-t nyújtsunk GETmódszerrel.
Docker fájl létrehozása
Ezután ezt az alkalmazást egy konténerbe helyezzük, hozzáadva Dockerfile:
FROM adoptopenjdk:11-jre-hotspot
ARG JAR_FILE=target\/.jar
COPY ${JAR_FILE} application.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","\/application.jar"]A Docker fájlunk tartalmazza az alapképet, amely adoptopenjdk, amelyre átmásoljuk a JAR fájlunkat, majd megnyitjuk a portot, 8080amely figyelni fogja a kéréseket.
Alkalmazás összeállítása
Először létre kell hozni az alkalmazást Maven vagy Gradle használatával. Itt a Mavent használjuk:
mvn clean packageEz létrehozza az alkalmazás végrehajtható JAR fájlját. Át kell alakítanunk ezt a végrehajtható JAR-t Docker képpé a Docker motorban való működéshez.
Konténerkép létrehozása
Ezután ezt a végrehajtható JAR fájlt Docker képbe helyezzük, végrehajtva a parancsot docker builda projekt gyökérkönyvtárából, amely tartalmazza a korábban létrehozott Docker fájlt:
docker build -t usersignup:v1 .A képet a következő paranccsal láthatjuk a listában:
docker images A fent említett parancs végrehajtásának eredménye tartalmazza a usersignupképet az alapképpel, adoptopenjdk, amely a Docker fájlunkban van megadva.
REPOSITORY TAG SIZE
usersignup v1 249MB
adoptopenjdk 11-jre-hotspot 229MBA konténerkép rétegeinek megtekintése
Nézzük meg a rétegek halmozását a képen belül. A hogy megnézzük ezeket a rétegeket:
dive usersignup:v1Íme a Dive parancs végrehajtásának egy része:

Ahogy látjuk, az alkalmazásszint jelentős részesedést képvisel a kép méretében. E réteg méretének csökkentésére törekszünk a következő szakaszokban az optimalizálás keretein belül.
Konténer kép létrehozása Buildpack segítségével
() – egy általános kifejezés, amelyet a PaaS (Platform as a Service) különböző ajánlatai használnak a konténerkép létrehozásához a forráskódból. 2011-ben indította el a Heroku, és azóta elfogadta a Cloud Foundry, a Google App Engine, a Gitlab, a Knative és mások.

A felhő alapú buildpackek előnye
Az egyik fő előny, hogy Buildpack-et használunk a képek létrehozásához, az az, hogy A konfigurációs képek módosításait központosítva (builder) kezelhetjük és terjeszthetjük minden alkalmazásra, amely a builder-t használja.
A build csomagok szoros kapcsolatban álltak a platformmal. A Cloud-Native Buildpack-ek szabványosítást biztosítanak a platformok között az OCI képformátum támogatásával, amely garantálja, hogy a kép Docker motorral futtatható.
Spring Boot plugin használata
A Spring Boot plugin OCI képeket készít a forráskódból a Buildpack segítségével. A képek létrehozása a következők felhasználásával történik: bootBuildImagefeladatok (Gradle) vagy spring-boot:build-imagecélok (Maven) és a Docker helyi telepítése.
A Docker registry-be feltöltéshez szükséges kép nevét a következő módon állíthatjuk be: image tag:
org.springframework.boot
spring-boot-maven-plugin
docker.io/pratikdas/${project.artifactId}:v1Használjuk a Mavent az alkalmazás létrehozásának és a konténerkép elkészítésének végrehajtására. Jelenleg nem használunk Docker fájlokat. build-imagefeladat a konténerkép létrehozásához. Jelenleg nem használunk Docker fájlokat.
mvn spring-boot:build-imageA kimenet körülbelül a következő lesz:
[INFO] --- spring-boot-maven-plugin:2.3.3.RELEASE:build-image (default-cli) @ usersignup ---
[INFO] Kép építése 'docker.io/pratikdas/usersignup:v1'
[INFO]
[INFO] > Builder kép betöltése 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 0%
.
.
.. [creator] Címke hozzáadása: 'org.springframework.boot.version'
.. [creator] *** Képek (c311fe74ec73):
.. [creator] docker.io/pratikdas/usersignup:v1
[INFO]
[INFO] Sikeresen készült a 'docker.io/pratikdas/usersignup:v1' képA kimenetből láthatjuk, hogy paketo Cloud-Native buildpackhasználatos egy működő OCI kép létrehozásához. Mint korábban, itt is láthatjuk a képet, amely Docker képként van megadva a következő parancs végrehajtásával:
docker images Következtetés:
REPOSITORY SIZE
paketobuildpacks/run 84.3MB
gcr.io/paketo-buildpacks/builder 652MB
pratikdas/usersignup 257MBKonténerkép létrehozása Jib segítségével
A Jib egy Google által készített képkészítő plugin, amely alternatív módszert kínál a konténerkép elkészítésére a forráskódból.
Beállítjuk jib-maven-plugina pom.xml-ben:
com.google.cloud.tools
jib-maven-plugin
2.5.2Ezután a Jib pluginnal indítjuk a Maven parancsot az alkalmazás építésére és a konténerkép létrehozására. Mint korábban, itt sem használunk Docker fájlokat:
mvn compile jib:build -Dimage=/usersignup:v1A fenti Maven parancs végrehajtása után a következő kimenetet kapjuk:
[INFO] Alkalmazás konténerbe helyezése pratikdas/usersignup:v1...
.
.
[INFO] Konténer belépési pont beállítva [java, -cp, /app/resources:/app/classes:/app/libs/*, io.pratik.users.UsersignupApplication]
[INFO]
[INFO] Kép felépítve és feltöltve pratikdas/usersignup:v1 néven
[INFO] Feladatok végrehajtása:
[INFO] [==============================] 100.0% készA kimeneti adatok azt mutatják, hogy a konténer képe létrejött és a tárhelyre került.
Az optimalizált képek létrehozásának motivációi és módszerei
Két fő okunk van az optimalizálásra:
- Teljesítmény: a konténerek orchestration rendszerében a konténer képét a tárhelyről húzzák le, ahol a konténer mechanizmusa fut. Ez a folyamat a tervezés. Nagy méretű képek letöltése a tárhelyről hosszú tervezési időt és hosszú CI folyamatidőt eredményez a konténerek orchestration rendszereiben.
- Biztonság: a nagy méretű képeknek nagyobb a sebezhetősége is.
A Docker kép egy rétegek halmazából áll, melyek mindegyike egy utasítást képvisel a Dockerfile-ban. Minden réteg a következő réteg eltérését jelenti. Amikor a Docker képet letöltjük a tárhelyről, az rétegekként kerül letöltésre és gyorsítótárazásra kerül a gépen.
A Spring Boot használja alapértelmezett csomagolási formátumként. Amikor a vastag JAR-t nézzük, azt látjuk, hogy az alkalmazás nagyon kis része a teljes JAR-nak. Ez a része, amely a leggyakrabban változik. A fennmaradó rész a Spring Framework függőségeiből áll.
Az optimalizálás formulája az alkalmazás izolálására összpontosít egy külön szinten a Spring Framework függőségeitől.
A függőségi réteg, amely a vastag JAR fájl fő részét képezi, csak egyszer kerül betöltésre és cache-eli a helyi rendszeren.
Csak a vékony alkalmazásréteg kerül letöltésre az alkalmazásfrissítések és konténerütemezés során, ahogy az ezen a diagramon látható:

A következő fejezetekben megvizsgáljuk, hogyan készíthetünk optimalizált képeket a Spring Boot alkalmazás számára.
Optimalizált konténerkép létrehozása a Spring Boot alkalmazáshoz Buildpack segítségével
A Spring Boot 2.3 támogatja a többrétegűséget azáltal, hogy a vastag JAR fájl részeit külön rétegekbe vonja ki. Az alapértelmezett rétegezési funkció ki van kapcsolva, és kifejezetten engedélyezni kell a Spring Boot Maven plugin segítségével:
org.springframework.boot
spring-boot-maven-plugin
trueEzt a konfigurációt fogjuk használni a konténerkép létrehozásához először Buildpack segítségével, majd Dockerrel a következő szakaszokban.
Futtassuk build-imagea Maven célt a konténerkép létrehozásához:
mvn spring-boot:build-imageHa elindítjuk a Dive-ot, hogy megnézzük a rétegeket a kapott képen, láthatjuk, hogy az alkalmazás réteg (pirossal körvonalazva) sokkal kisebb sávnyi kilobájtokban van, mint amit a vastag JAR formátum használatával kaptunk:

Optimalizált konténerkép létrehozása a Spring Boot alkalmazáshoz Docker segítségével
A Maven vagy a Gradle plugin használata helyett létrehozhatunk egy többszörös Docker JAR képet egy Docker fájl segítségével is.
Amikor Docker-t használunk, két további lépést kell végrehajtanunk a rétegek kinyeréséhez és ezek végső képbe másolásához.
A Maven által létrehozott JAR tartalma, a rétegezési funkció engedélyezésével, a következőképpen fog kinézni:
META-INF/
.
BOOT-INF/lib/
.
BOOT-INF/lib/spring-boot-jarmode-layertools-2.3.3.RELEASE.jar
BOOT-INF/classpath.idx
BOOT-INF/layers.idxA kimenetben megjelenik egy extra JAR névvel spring-boot-jarmode-layertoolsés layersfle.idxfájl. Ez a kiegészítő JAR fájl lehetővé teszi a réteges feldolgozást, ahogyan az a következő szakaszban lesz leírva.
A függőségek kinyerése külön rétegekben
A rétegek megtekintéséhez és kinyeréséhez a többszörös JAR-ból a következő rendszerpropért használjuk -Djarmode=layertoolsa JAR futtatása helyett az alkalmazás: spring-boot-jarmode-layertoolsjava -Djarmode=layertools -jar target/usersignup-0.0.1-SNAPSHOT.jar
Ennek a parancsnak a végrehajtása egy olyan kimenetet ad, amely a rendelkezésre álló parancsparamétereket tartalmazza:Usage: java -Djarmode=layertools -jar usersignup-0.0.1-SNAPSHOT.jarAvailable 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
A kimenet megmutatja a parancsokatextract list, legyen alapértelmezett. Futtassuk a parancsot aés helpa helpopcióval: listjava -Djarmode=layertools -jar target/usersignup-0.0.1-SNAPSHOT.jar list
dependencies
spring-boot-loader
snapshot-dependencies
applicationLátjuk a függőségek listáját, amelyeket rétegekként lehet hozzáadni.Alapértelmezett rétegek:
Réteg neve
bármely függőség, amelynek verziója nem tartalmaz SNAPSHOT-ot
Tartalom
függőségeket
spring-boot-loader
JAR betöltő osztályai
snapshot-dependencies
bármely függőség, amelynek verziója tartalmaz SNAPSHOT-ot
alkalmazás osztályai és erőforrásai
application
alkalmazások osztályai és erőforrásai
Rétegek definiáltak a layers.idxfájlban, abban a sorrendben, ahogy hozzá kell adni őket a Docker képből. Ezek a rétegek a hoszton kerülnek cache-elésre az első letöltés után, mivel nem változnak. Csak a frissített alkalmazásréteg kerül a hosztra, ami gyorsabb, mivel csökkentett méretű. .
A képet a függőségek külön rétegekként való letöltésével építjük fel.
Két lépésben állítjuk elő a végső képet, az úgynevezett Az első lépésben letöltjük a függőségeket, a második lépésben pedig átmásoljuk a letöltött függőségeket a végső képbe.
Módosítsuk a Docker fájlunkat a többlépéses buildhez:
# 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"]Mentsük el ezt a konfigurációt külön fájlba — Dockerfile2.
A Docker képet a következő parancs segítségével építjük fel:
docker build -f Dockerfile2 -t usersignup:v1 .E parancs végrehajtása után a következő kimenetet kapjuk:
Build context sending to Docker daemon 20.41MB
Step 1/12: FROM adoptopenjdk:14-jre-hotspot as builder
14-jre-hotspot: Pulling from library/adoptopenjdk
.
.
Sikeresen építve: a9ebf6970841
Sikeresen címkézve: userssignup:v1Látjuk, hogy a Docker kép létrejön egy képid azonosítóval, majd címkézve.
Végül futtatjuk a Dive parancsot, ahogyan korábban, hogy ellenőrizzük a generált Docker kép rétegeit. Megadhatjuk a képid azonosítóját vagy címkéjét a Dive parancs bemeneteként:
dive userssignup:v1A kimenetből látható, hogy az alkalmazást tartalmazó réteg most mindössze 11 KB, míg a függőségek külön rétegekben cache-elődnek.

A belső függőségek letöltése külön rétegekben.
Továbbiakban csökkenthetjük az alkalmazás rétegének méretét, ha a felhasználói függőségeinket külön rétegként töltjük le, ahelyett, hogy azokat az alkalmazással együtt csomagolnánk, nyilvánítva azokat a ymlhasonló nevű fájlban, 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/"Ebben a fájlban layers.idxmegtettük a testreszabható függőséget, io.myorgamely az organizációs függőségeket tartalmazza, a közös tárolóból származóan.
Következtetés
Ebben a cikkben a Cloud-Native Buildpackok használatát tekintettük át, amely lehetővé teszi, hogy közvetlenül a forráskódból hozzunk létre konténerképet. Ez egy alternatíva a Docker használatával történő konténerkép-gyártáshoz, amely során először egy vastag JAR végrehajtható fájlt hozunk létre, majd ezt csomagoljuk egy konténerképre Docker fájl utasításainak megadásával.
Ezen kívül áttekintettük konténerünk optimalizálását is, beleértve a rétegzés funkcióját, amely a függőségeket külön szintekre bontja, amelyeket a gazdagépen gyorsítótárban tárolunk, míg a vékony alkalmazásréteg a konténervégrehajtási mechanizmusok során töltődik be.
A cikkben használt összes forráskódot itt találhatja: .
Parancsok útmutatója
Itt van egy rövid összefoglaló a cikkben használt parancsokról, hogy gyorsan át tudja tekinteni őket.
A kontextus tisztítása:
docker system prune -aKonténerkép létrehozása Docker fájl segítségével:
docker build -f -t .Konténerkép létrehozása forráskódból (Dockerfile nélkül):
mvn spring-boot:build-imageA függőségek rétegeinek megtekintése. Az alkalmazás JAR fájl összegyűjtése előtt győződjön meg róla, hogy a rétegző funkció engedélyezve van a spring-boot-maven-pluginben:
java -Djarmode=layertools -jar application.jar listA függőségek rétegeinek kinyerése. Az alkalmazás JAR fájl összegyűjtése előtt győződjön meg róla, hogy a rétegző funkció engedélyezve van a spring-boot-maven-pluginben:
java -Djarmode=layertools -jar application.jar extractA konténerképek listájának megtekintése
docker imagesA konténerkép belsejében található rétegek megtekintése (győződjön meg róla, hogy a merülő eszköz telepítve van):
diveForrás: habr.com
