Spring Boot ilovasi uchun optimallashtirilgan Docker tasvirlarini yaratish

Konteynerlar dasturni barcha dasturiy ta'minot va operatsion tizimga bog'liqliklari bilan qadoqlash va keyin ularni turli muhitlarga etkazib berishning afzal qilingan vositasiga aylandi.

Ushbu maqola Spring Boot ilovasini konteynerga joylashtirishning turli usullarini qamrab oladi:

  • docker fayli yordamida docker tasvirini yaratish,
  • Cloud-Native Buildpack yordamida manbadan OCI tasvirini yaratish,
  • qatlamli vositalar yordamida JAR qismlarini turli darajalarga ajratish orqali ish vaqtida tasvirni optimallashtirish.

 Kod misoli

Ushbu maqola ishchi kod misoli bilan birga keladi GitHub-da .

Konteyner terminologiyasi

Biz maqolada ishlatiladigan konteyner terminologiyasidan boshlaymiz:

  • Konteyner tasviri: ma'lum formatdagi fayl. Qurilish vositasini ishga tushirish orqali dasturimizni konteyner tasviriga aylantiramiz.
  • Konteyner: Konteyner tasvirining bajariladigan namunasi.
  • Konteyner dvigateli: Konteynerni ishga tushirish uchun mas'ul bo'lgan demon jarayoni.
  • Konteyner xosti: Konteyner dvigateli ishlayotgan asosiy mashina.
  • Konteynerlar reestri: Konteyner tasvirini nashr qilish va tarqatish uchun foydalaniladigan umumiy joy.
  • OCI standartiOchiq konteyner tashabbusi (OCI) Linux Foundation tomonidan yaratilgan engil, ochiq manbali boshqaruv tizimidir. OCI tasvir spetsifikatsiyasi konteyner tasvir formatlari uchun sanoat standartlarini va barcha konteyner dvigatellari har qanday qurish vositasi tomonidan yaratilgan konteyner tasvirlarini ishga tushirishini ta'minlash uchun ish vaqtini belgilaydi.

Ilovani konteynerga joylashtirish uchun biz ilovamizni konteyner tasviriga oβ€˜rab, ushbu tasvirni umumiy reestrga joylashtiramiz. Konteynerning ishlash vaqti ushbu tasvirni ro'yxatga olish kitobidan oladi, uni ochadi va uning ichida dasturni ishga tushiradi.

Spring Boot-ning 2.3-versiyasi OCI tasvirlarini yaratish uchun plaginlarni taqdim etadi.

Docker eng ko'p ishlatiladigan konteyner ilovasi va biz misollarimizda Docker-dan foydalanamiz, shuning uchun ushbu maqoladagi barcha keyingi konteyner havolalari Docker-ga murojaat qiladi.

An'anaviy usulda konteyner tasvirini yaratish

Spring Boot ilovalari uchun Docker tasvirlarini yaratish Dockerfile-ga bir nechta ko'rsatmalar qo'shish orqali juda oson.

Biz birinchi navbatda bajariladigan JAR ni yaratamiz va Dockerfile ko'rsatmalarining bir qismi sifatida kerakli moslashtirishlarni qo'llaganimizdan so'ng, bajariladigan JARni asosiy JRE tasvirining ustiga nusxalaymiz.

Keling, bahor ilovamizni yarataylik Bahor Initializr bog'liqliklar bilan weblombokΠΈ actuator. API bilan ta'minlash uchun biz dam olish boshqaruvchisini ham qo'shamiz GETusuli.

Docker faylini yaratish

Keyin ushbu ilovani qo'shish orqali konteynerga joylashtiramiz Dockerfile:

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

Bizning Dockerfaylimizda asosiy tasvir mavjud, dan adoptopenjdk, buning ustiga biz JAR faylimizni nusxalaymiz va keyin portni ochamiz, 8080so'rovlarni tinglaydi.

Ilova yig'ilishi

Avval Maven yoki Gradle yordamida dastur yaratishingiz kerak. Bu erda biz Maven dan foydalanamiz:

mvn clean package

Bu ilova uchun bajariladigan JAR faylini yaratadi. Docker dvigatelida ishlash uchun biz ushbu bajariladigan JARni Docker tasviriga aylantirishimiz kerak.

Konteyner tasvirini yarating

Keyin biz buyruqni ishga tushirish orqali ushbu JAR bajariladigan faylni Docker tasviriga joylashtiramiz docker buildavval yaratilgan Dockerfile-ni o'z ichiga olgan loyihaning asosiy katalogidan:

docker build  -t usersignup:v1 .

Ro'yxatdagi rasmimizni buyruq bilan ko'rishimiz mumkin:

docker images 

Yuqoridagi buyruqning chiqishi bizning rasmimizni o'z ichiga oladi usersignupasosiy rasm bilan birga, adoptopenjdkbizning Docker faylimizda ko'rsatilgan.

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

Konteyner tasviridagi qatlamlarni ko'rish

Keling, rasm ichidagi qatlamlar to'plamini ko'rib chiqaylik. foydalanamiz asbob  sho'ng'in, Ushbu qatlamlarni ko'rish uchun:

dive usersignup:v1

Bu erda "Dive" buyrug'ining chiqishining bir qismi: 

Spring Boot ilovasi uchun optimallashtirilgan Docker tasvirlarini yaratish

Ko'rib turganimizdek, amaliy qatlam tasvir hajmining muhim qismini tashkil qiladi. Biz optimallashtirishning bir qismi sifatida quyidagi bo'limlarda ushbu qatlam hajmini qisqartirishni xohlaymiz.

Buildpack yordamida konteyner tasvirini yaratish

Yig'ish paketlari (Qurilish paketlari) - bu turli xil Platforma As a Service (PAAS) takliflari tomonidan manba kodidan konteyner tasvirini yaratish uchun ishlatiladigan umumiy atama. U Heroku tomonidan 2011 yilda ishga tushirilgan va shundan beri Cloud Foundry, Google App Engine, Gitlab, Knative va boshqalar tomonidan qabul qilingan.

Spring Boot ilovasi uchun optimallashtirilgan Docker tasvirlarini yaratish

Cloud Build paketlarining afzalliklari

Tasvirlarni yaratish uchun Buildpack-dan foydalanishning asosiy afzalliklaridan biri shundaki tasvir konfiguratsiyasi o'zgarishlari markaziy (quruvchi) tomonidan boshqarilishi va quruvchi yordamida barcha ilovalarga tarqalishi mumkin.

Qurilish paketlari platformaga chambarchas bog'langan edi. Cloud-Native Buildpacks OCI tasvir formatini qo'llab-quvvatlash orqali platformalar bo'ylab standartlashtirishni ta'minlaydi, bu esa tasvirni Docker dvigateli tomonidan ishlashini ta'minlaydi.

Spring Boot plaginidan foydalanish

Spring Boot plagini Buildpack yordamida manbadan OCI tasvirlarini yaratadi. Tasvirlar yordamida yaratiladi bootBuildImagevazifalar (Gradle) yoki spring-boot:build-imagemaqsadlar (Maven) va mahalliy Docker o'rnatilishi.

Biz Docker registriga o'tkazishimiz kerak bo'lgan rasm nomini nomni ko'rsatish orqali sozlashimiz mumkin. 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>

Bajarish uchun Maven dan foydalanamiz build-imageilova yaratish va konteyner tasvirini yaratish maqsadlari. Biz hozirda hech qanday Dockerfilldan foydalanmayapmiz.

mvn spring-boot:build-image

Natija shunday bo'ladi:

[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'

Chiqishdan biz buni ko'ramiz paketo Cloud-Native buildpackishlaydigan OCI tasvirini yaratish uchun foydalaniladi. Avvalgidek, biz buyruqni bajarish orqali Docker tasviri sifatida ro'yxatga olingan tasvirni ko'rishimiz mumkin:

docker images 

xulosa:

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

Jib yordamida konteyner tasvirini yaratish

Jib - bu Google tomonidan taqdim etilgan rasm mualliflik plaginidir, u manbadan konteyner tasvirini yaratishning muqobil usulini taqdim etadi.

Konfiguratsiya jib-maven-pluginpom.xml ichida:

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

Keyinchalik, dasturni yaratish va konteyner tasvirini yaratish uchun Maven buyrug'i yordamida Jib plaginini ishga tushiramiz. Avvalgidek, biz bu erda hech qanday Docker faylidan foydalanmayapmiz:

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

Yuqoridagi Maven buyrug'ini bajarganimizdan so'ng biz quyidagi natijani olamiz:

[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

Chiqish konteyner tasviri yaratilganligini va registrga joylashtirilganligini ko'rsatadi.

Optimallashtirilgan tasvirlarni yaratish uchun motivlar va usullar

Optimallashtirishning ikkita asosiy sababi bor:

  • unumdorlik: Konteynerni orkestrlash tizimida konteyner tasviri tasvirlar registridan konteyner dvigatelida ishlaydigan xostga olinadi. Bu jarayon rejalashtirish deb ataladi. Ro'yxatga olish kitobidan katta hajmdagi rasmlarni olib tashlash, konteyner orkestrlash tizimlarida uzoq rejalashtirish vaqtlariga va CI quvurlarida uzoq vaqt qurishga olib keladi.
  • Xavfsizlik: katta tasvirlarda zaifliklar uchun ham katta maydon mavjud.

Docker tasviri qatlamlar to'plamidan iborat bo'lib, ularning har biri bizning Docker faylimizdagi bayonotni ifodalaydi. Har bir qatlam pastki qatlamdagi o'zgarishlar deltasini ifodalaydi. Docker tasvirini ro'yxatga olish kitobidan olganimizda, u qatlamlarga tortiladi va xostda keshlanadi.

Spring Boot foydalanadi "yog 'JAR" ichida standart qadoqlash formati sifatida. Yog 'JARni ko'rib chiqsak, dastur butun JARning juda kichik qismi ekanligini ko'ramiz. Bu eng ko'p o'zgarib turadigan qismdir. Qolganlari Spring Framework bog'liqliklaridan iborat.

Optimallashtirish formulasi dasturni Spring Framework bog'liqliklaridan alohida darajada ajratishga qaratilgan.

Qalin JAR faylining asosiy qismini tashkil etuvchi qaramlik qatlami faqat bir marta yuklab olinadi va xost tizimida keshlanadi.

Ilovani yangilash va konteynerni rejalashtirish vaqtida ilovaning faqat yupqa qatlami tortiladi, ushbu diagrammada ko'rsatilganidek:

Spring Boot ilovasi uchun optimallashtirilgan Docker tasvirlarini yaratish

Keyingi bo'limlarda biz Spring Boot ilovasi uchun optimallashtirilgan tasvirlarni qanday yaratishni ko'rib chiqamiz.

Buildpack bilan Spring Boot ilovasi uchun optimallashtirilgan konteyner tasvirini yaratish

Spring Boot 2.3 qalin JAR fayl qismlarini alohida qatlamlarga ajratib olish orqali qatlamlarni qo'llab-quvvatlaydi. Qatlamlash xususiyati sukut bo'yicha o'chirib qo'yilgan va Spring Boot Maven plagini yordamida aniq yoqilgan bo'lishi kerak:

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

Biz ushbu konfiguratsiyadan konteyner tasvirimizni avval Buildpack bilan, keyin esa keyingi bo'limlarda Docker yordamida yaratish uchun foydalanamiz.

Yuguraylik build-imageMavenning maqsadi konteyner tasvirini yaratish:

mvn spring-boot:build-image

Olingan rasmdagi qatlamlarni ko'rish uchun Dive-ni ishga tushirsak, biz qalin JAR formatidan foydalanganimiz bilan solishtirganda, ilova qatlami (qizil rangda aylana) kilobayt oralig'ida ancha kichikroq ekanligini ko'ramiz:

Spring Boot ilovasi uchun optimallashtirilgan Docker tasvirlarini yaratish

Docker yordamida Spring Boot ilovasi uchun optimallashtirilgan konteyner tasvirini yaratish

Maven yoki Gradle plaginlaridan foydalanish o'rniga biz Docker fayli bilan qatlamli Docker JAR tasvirini ham yaratishimiz mumkin.

Docker-dan foydalanganda biz qatlamlarni ajratib olish va ularni yakuniy tasvirga nusxalash uchun ikkita qo'shimcha qadamni bajarishimiz kerak.

Qatlamlash yoqilgan Maven bilan qurilgandan so'ng olingan JAR tarkibi quyidagicha ko'rinadi:

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

Chiqish nomli qo'shimcha JARni ko'rsatadi spring-boot-jarmode-layertoolsΠΈ layersfle.idxfayl. Ushbu qo'shimcha JAR fayli keyingi bo'limda ta'riflanganidek, qatlamlash imkoniyatlarini taqdim etadi.

Alohida qatlamlarga bog'liqliklarni ajratib oling

Bizning qatlamli JAR-dan qatlamlarni ko'rish va chiqarish uchun biz tizim xususiyatidan foydalanamiz -Djarmode=layertoolsboshlash uchun spring-boot-jarmode-layertoolsIlova o'rniga JAR:

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

Ushbu buyruqni ishga tushirish mavjud buyruq variantlarini o'z ichiga olgan chiqishni ishlab chiqaradi:

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

Chiqish buyruqlarni ko'rsatadi listextractΠΈ helpс helpstandart bo'ling. bilan buyruqni ishga tushiramiz listvariant:

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

Biz qatlamlar sifatida qo'shilishi mumkin bo'lgan bog'liqliklar ro'yxatini ko'ramiz.

Sukut bo'yicha qatlamlar:

Qatlam nomi

Mundarija

dependencies

versiyasida SNAPSHOT bo'lmagan har qanday qaramlik

spring-boot-loader

JAR Loader sinflari

snapshot-dependencies

versiyasida SNAPSHOT bo'lgan har qanday bog'liqlik

application

dastur sinflari va resurslari

Qatlamlar ichida aniqlanadi layers.idxfaylni Docker tasviriga qo'shish kerak bo'lgan tartibda joylashtiring. Bu qatlamlar oΚ»zgarmasligi sababli birinchi yuklashdan keyin xostda keshlanadi. Xostga faqat yangilangan dastur qatlami yuklab olinadi, bu esa kichraytirilgan hajm tufayli tezroq .

Alohida qatlamlarga ajratilgan bog'liqliklar bilan tasvirni yaratish

deb nomlangan usul yordamida ikki bosqichda yakuniy tasvirni yaratamiz ko'p bosqichli yig'ish . Birinchi bosqichda biz bog'liqliklarni chiqaramiz va ikkinchi bosqichda chiqarilgan bog'liqliklarni finalga nusxalaymiz.

Keling, ko'p bosqichli qurilish uchun Docker faylimizni o'zgartiraylik:

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

Biz ushbu konfiguratsiyani alohida faylda saqlaymiz - Dockerfile2.

Biz Docker tasvirini quyidagi buyruq yordamida yaratamiz:

docker build -f Dockerfile2 -t usersignup:v1 .

Ushbu buyruqni ishga tushirgandan so'ng biz quyidagi natijani olamiz:

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

Biz Docker tasviri tasvir identifikatori bilan yaratilganligini va keyin teglanganligini ko'rishimiz mumkin.

Va nihoyat, yaratilgan Docker tasviridagi qatlamlarni tekshirish uchun avvalgidek Dive buyrug'ini bajaramiz. Biz Dive buyrug'iga kirish sifatida rasm identifikatorini yoki tegni taqdim etishimiz mumkin:

dive userssignup:v1

Natijadan ko'rinib turibdiki, ilovani o'z ichiga olgan qatlam endi atigi 11 KB va bog'liqliklar alohida qatlamlarda keshlangan. 

Spring Boot ilovasi uchun optimallashtirilgan Docker tasvirlarini yaratish

Alohida qatlamlardagi ichki bog'liqliklarni ajratib oling

Biz har qanday maxsus bog'liqliklarni ilova bilan o'rash o'rniga ularni alohida qatlamga chiqarib, ilova qatlami hajmini yanada kamaytirishimiz mumkin. ymlnomli o'xshash fayl 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/"

Ushbu faylda layers.idxnomli maxsus bog'liqlikni qo'shdik, io.myorgumumiy ombordan olingan tashkilotga bog'liqliklarni o'z ichiga oladi.

xulosa

Ushbu maqolada biz to'g'ridan-to'g'ri manbadan konteyner tasvirini yaratish uchun Cloud-Native Buildpacks-dan foydalanishni ko'rib chiqdik. Bu odatiy tarzda konteyner tasvirini yaratish uchun Docker-dan foydalanishning muqobil variantidir: birinchi navbatda, qalin bajariladigan JAR fayli yaratiladi va keyin Dockerfile-dagi ko'rsatmalarni ko'rsatib, konteyner tasviriga paketlanadi.

Biz, shuningdek, xostda keshlangan alohida qatlamlarga bog'liqliklarni chiqaradigan qatlam xususiyatini qo'shish orqali konteynerimizni optimallashtirishni ko'rib chiqdik va konteynerning ishlash dvigatellarida rejalashtirish vaqtida nozik dastur qatlami yuklanadi.

Maqolada foydalanilgan barcha manba kodlarini topishingiz mumkin Github .

Buyruq havolasi

Tezkor ma'lumot olish uchun biz ushbu maqolada foydalangan buyruqlarning qisqacha mazmuni.

Kontekstni tozalash:

docker system prune -a

Dockerfile yordamida konteyner tasvirini yaratish:

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

Manbadan konteyner tasvirini yarating (Dockerfilesiz):

mvn spring-boot:build-image

Bog'liq qatlamlarini ko'rish. Ilova jar faylini yaratishdan oldin, spring-boot-maven-plaginida qatlam xususiyati yoqilganligiga ishonch hosil qiling:

java -Djarmode=layertools -jar application.jar list

Bog'liq qatlamlarini ajratib oling. Ilova jar faylini yaratishdan oldin, spring-boot-maven-plaginida qatlam xususiyati yoqilganligiga ishonch hosil qiling:

 java -Djarmode=layertools -jar application.jar extract

Konteyner rasmlari ro'yxatini ko'rish

docker images

Konteyner tasvirining chap tomonida ko'ring (sho'ng'in vositasi o'rnatilganligiga ishonch hosil qiling):

dive <image ID or image tag>

Manba: www.habr.com