Жазгы жүктөө колдонмосу үчүн оптималдаштырылган докер сүрөттөрүн куруу

Контейнерлер тиркемени анын бардык программалык камсыздоосу жана операциялык тутумунун көз карандылыгы менен таңгактоо жана андан кийин аларды ар кандай чөйрөлөргө жеткирүүнүн артыкчылыктуу каражаты болуп калды.

Бул макалада Spring Boot тиркемесин контейнерлештирүүнүн ар кандай жолдору каралат:

  • Docker файлын колдонуп Docker сүрөтүн түзүү,
  • Cloud-Native Buildpack аркылуу булактан OCI сүрөтүн түзүү,
  • жана көп баскычтуу куралдарды колдонуу менен JAR бөлүктөрүн ар кандай катмарларга бөлүү аркылуу иштөө убактысынын сүрөтүн оптималдаштыруу.

 Код мисалы

Бул макала жумушчу коддун мисалы менен коштолот GitHub боюнча .

Контейнер терминологиясы

Макалада колдонулган контейнер терминологиясынан баштайбыз:

  • Контейнер сүрөтү: белгилүү форматтагы файл. Биз куруу куралын иштетүү менен колдонмобузду контейнер сүрөтүнө айландырабыз.
  • контейнер: Контейнер сүрөтүнүн аткарылуучу мисалы.
  • Контейнер мотору: Контейнерди иштетүү үчүн жооптуу демон процесси.
  • Контейнер хосту: Контейнер кыймылдаткычы иштеген негизги компьютер.
  • Контейнер реестри: Контейнер сүрөтүн жарыялоо жана жайылтуу үчүн колдонулган жалпы жер.
  • OCI стандартыАчык контейнер демилгеси (OCI) Linux Фондунун ичинде түзүлгөн жеңил, ачык башкаруу структурасы. OCI Image Specification бардык контейнер кыймылдаткычтары ар кандай куруу куралы тарабынан түзүлгөн контейнер сүрөттөрүн иштете аларын камсыз кылуу үчүн контейнер сүрөтү жана иштөө убактысы форматтары үчүн тармактык стандарттарды аныктайт.

Тиркемени контейнерлештирүү үчүн биз колдонмобузду контейнер сүрөтүнө ороп, ал сүрөттү жалпы реестрге жарыялайбыз. Контейнердин иштөө убактысы реестрден бул сүрөттү алып чыгып, таңгактан чыгарат жана анын ичиндеги тиркемени иштетет.

Spring Boot 2.3 версиясы OCI сүрөттөрүн түзүү үчүн плагиндерди камсыз кылат.

ютуб эң көп колдонулган контейнерди ишке ашыруу болуп саналат жана биз мисалдарыбызда Докерди колдонобуз, андыктан бул макаладагы бардык кийинки контейнер шилтемелери Dockerге кайрылат.

Контейнердин сүрөтүн салттуу жол менен куруу

Spring Boot тиркемелери үчүн Docker сүрөттөрүн түзүү Docker файлына бир нече инструкцияларды кошуу менен абдан оңой.

Адегенде биз аткарылуучу JAR файлын түзөбүз жана Docker файлынын нускамаларынын бир бөлүгү катары, керектүү орнотууларды колдонгондон кийин аткарылуучу JAR файлын негизги JRE сүрөтүнүн үстүнө көчүрөбүз.

Жазгы колдонмобузду түзөлү Spring Initializr көз карандылыктар менен weblombokи actuator. Ошондой эле API менен камсыз кылуу үчүн эс алуу контроллерин кошуп жатабыз GETыкмасы.

Докер файлын түзүү

Андан кийин биз бул колдонмону кошуу менен контейнерлештиребиз Dockerfile:

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

Биздин Docker файлыбыздан негизги сүрөт бар adoptopenjdk, анын үстүнө биз JAR файлыбызды көчүрүп, анан портту ачабыз, 8080суроо-талаптарды угат.

Колдонмону түзүү

Адегенде сиз Maven же Gradle аркылуу колдонмо түзүшүңүз керек. Бул жерде биз Maven колдонобуз:

mvn clean package

Бул колдонмо үчүн аткарылуучу JAR файлын түзөт. Докер кыймылдаткычында иштөө үчүн бул аткарылуучу JARды Docker сүрөтүнө айландырышыбыз керек.

Контейнердин сүрөтүн түзүү

Андан кийин биз бул аткарылуучу JAR файлын буйрукту иштетүү менен Docker сүрөтүнө салабыз docker buildмурда түзүлгөн Dockerfile камтыган долбоордун түпкү каталогунан:

docker build  -t usersignup:v1 .

Биз төмөнкү буйрукту колдонуп тизмедеги сүрөтүбүздү көрө алабыз:

docker images 

Жогорудагы буйруктун жыйынтыгы биздин сүрөттү камтыйт usersignupнегизги сүрөт менен бирге, adoptopenjdkбиздин Docker файлыбызда көрсөтүлгөн.

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

Контейнер сүрөтүнүн ичиндеги катмарларды көрүү

Сүрөттүн ичиндеги катмарларды карап көрөлү. Биз колдонобуз курал  сууга түшүү бул катмарларды көрүү үчүн:

dive usersignup:v1

Бул жерде Dive буйругунун бир бөлүгү болуп саналат: 

Жазгы жүктөө колдонмосу үчүн оптималдаштырылган докер сүрөттөрүн куруу

Көрүнүп тургандай, колдонмо катмары сүрөт өлчөмүнүн олуттуу бөлүгүн түзөт. Биз оптималдаштыруунун бир бөлүгү катары кийинки бөлүмдөрдө бул катмардын өлчөмүн азайткыбыз келет.

Buildpack аркылуу контейнер сүрөтүн түзүү

Монтаж пакеттери (Buildpacks) бул баштапкы коддон контейнер сүрөтүн түзүү үчүн ар кандай Platform as a Service (PAAS) сунуштары тарабынан колдонулган жалпы термин. Бул Heroku тарабынан 2011-жылы ишке киргизилген жана андан бери Cloud Foundry, Google App Engine, Gitlab, Knative жана башка бир нече компаниялар тарабынан кабыл алынган.

Жазгы жүктөө колдонмосу үчүн оптималдаштырылган докер сүрөттөрүн куруу

Булут куруу пакеттеринин артыкчылыгы

Сүрөттөрдү түзүү үчүн Buildpack колдонуунун негизги артыкчылыктарынын бири болуп саналат Сүрөт конфигурациясынын өзгөрүүлөрүн борборлоштурулган (куруучу) башкарса болот жана куруучу аркылуу бардык колдонмолорго жайылтылат.

Курулуш топтомдору платформага тыгыз бириктирилген. Cloud-Native Buildpacks OCI сүрөт форматын колдоо менен платформалар боюнча стандартташтырууну камсыз кылат, бул сүрөттүн Docker кыймылдаткычы тарабынан иштетилишин камсыз кылат.

Spring Boot плагинин колдонуу

Spring Boot плагини Buildpack аркылуу булактан OCI сүрөттөрүн түзөт. Сүрөттөр колдонуу менен түзүлгөн bootBuildImageтапшырмалар (Gradle) же spring-boot:build-imageмаксаттары (Maven) жана жергиликтүү Docker орнотуу.

Докер реестрине түртүү үчүн керектүү сүрөттүн атын көрсөтүү менен ыңгайлаштыра алабыз 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>

Келгиле, бул үчүн Maven колдонолу build-imageтиркемени түзүү жана контейнер сүрөтүн түзүү максаттары. Биз азыр эч кандай Dockerfiles колдонбойбуз.

mvn spring-boot:build-image

Натыйжа мындай болот:

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

Чыгарылгандан биз муну көрөбүз paketo Cloud-Native buildpackжумушчу OCI сүрөтүн түзүү үчүн колдонулат. Мурдагыдай эле, биз буйрукту иштетүү менен Docker сүрөтү катары көрсөтүлгөн сүрөттү көрө алабыз:

docker images 

корутундусу:

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

Jib аркылуу контейнер сүрөтүн түзүү

Jib бул Google'дун сүрөт түзүү плагини, ал баштапкы коддон контейнер сүрөтүн түзүүнүн альтернативалуу ыкмасын камсыз кылат.

Конфигурациялоо jib-maven-pluginpom.xml ичинде:

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

Андан кийин, колдонмону түзүү жана контейнер сүрөтүн түзүү үчүн Maven буйругун колдонуп Jib плагинин иштетебиз. Мурдагыдай эле, биз бул жерде эч кандай Docker файлдарын колдонбойбуз:

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

Жогорудагы Maven буйругун аткаргандан кийин, биз төмөнкү натыйжаны алабыз:

[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

Чыгуу контейнер сүрөтү түзүлүп, реестрге жайгаштырылгандыгын көрсөтөт.

Мотивациялар жана оптималдаштырылган сүрөттөрдү түзүү ыкмалары

Бизде оптималдаштыруунун эки негизги себеби бар:

  • кирешелүүлүк: Контейнерди башкаруу системасында контейнердин сүрөтү сүрөт реестринен контейнер кыймылдаткычын иштеткен хостко чыгарылат. Бул процесс пландаштыруу деп аталат. Реестрден чоң сүрөттөрдү алып салуу контейнердик оркестрдик системаларда пландаштыруунун узакка созулушуна жана CI түтүктөрүндө узак курууга алып келет.
  • коопсуздук: Чоңураак сүрөттөрдө да алсыздыктар үчүн көбүрөөк аймак бар.

Докер сүрөтү катмарлардын стекинен турат, алардын ар бири биздин Dockerfileдеги нускаманы билдирет. Ар бир катмар астындагы катмардагы өзгөрүүлөрдүн дельтасын билдирет. Реестрден Docker сүрөтүн чыгарганда, ал катмарларга тартылып, хостто кэштелет.

Spring Boot колдонот "май JAR" in демейки таңгак форматы катары. Калың JARды караганыбызда, тиркеме бүт JARдын өтө аз бөлүгүн түзгөнүн көрөбүз. Бул көбүнчө өзгөрүп турган бөлүк. Калган жазгы алкактык көз карандылыктан турат.

Оптималдаштыруу формуласы тиркемени Spring Framework көз карандылыктарынан өзүнчө деңгээлде изоляциялоого багытталган.

Калың JAR файлынын негизги бөлүгүн түзгөн көз карандылык катмары бир гана жолу жүктөлүп алынат жана хост тутумунда кэште сакталат.

Колдонмонун жука катмары гана колдонмону жаңыртуу жана контейнерди пландаштыруу учурунда тартылат. бул диаграммада көрсөтүлгөндөй:

Жазгы жүктөө колдонмосу үчүн оптималдаштырылган докер сүрөттөрүн куруу

Кийинки бөлүмдөрдө биз Spring Boot тиркемеси үчүн бул оптималдаштырылган сүрөттөрдү кантип түзүүнү карап чыгабыз.

Buildpack аркылуу жазгы жүктөө колдонмосу үчүн оптималдаштырылган контейнер сүрөтүн түзүү

Spring Boot 2.3 коюу JAR файлынын бөлүктөрүн өзүнчө катмарларга чыгаруу менен катмарлоону колдойт. Катмарлоо функциясы демейки боюнча өчүрүлгөн жана Spring Boot Maven плагининин жардамы менен ачык иштетилиши керек:

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

Бул конфигурацияны контейнердин сүрөтүн түзүү үчүн адегенде Buildpack менен, андан кийин кийинки бөлүмдөрдө Docker менен колдонобуз.

ишке киргизели build-imageКонтейнер сүрөтүн түзүү үчүн Maven максаты:

mvn spring-boot:build-image

Натыйжадагы сүрөттөгү катмарларды көрүү үчүн Dive программасын иштетсек, анда биз калың JAR форматын колдонуп алганга салыштырмалуу колдонмо катмары (кызыл менен белгиленген) килобайт диапазонунда бир топ кичине экенин көрөбүз:

Жазгы жүктөө колдонмосу үчүн оптималдаштырылган докер сүрөттөрүн куруу

Docker аркылуу жазгы жүктөө колдонмосу үчүн оптималдаштырылган контейнер сүрөтүн түзүү

Maven же Gradle плагиндерин колдонуунун ордуна, биз Docker файлы менен катмарлуу Docker JAR сүрөтүн түзө алабыз.

Dockerди колдонгондо, катмарларды чыгарып, аларды акыркы сүрөткө көчүрүү үчүн эки кошумча кадамды жасашыбыз керек.

Катмарлоо иштетилген Mavenди колдонуп куруудан кийин пайда болгон JARдын мазмуну төмөнкүдөй болот:

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

Чыгуу аталган кошумча JAR көрсөтөт spring-boot-jarmode-layertoolsи layersfle.idxфайл. Бул кошумча JAR файлы кийинки бөлүмдө сүрөттөлгөндөй катмарлуу иштетүү мүмкүнчүлүктөрүн камсыз кылат.

Жеке катмарларга көз карандылыктарды алуу

Биздин катмарлуу JARдан катмарларды көрүү жана чыгаруу үчүн биз системанын касиетин колдонобуз -Djarmode=layertoolsбаштоо үчүн spring-boot-jarmode-layertoolsКолдонмонун ордуна JAR:

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

Бул буйрукту иштетүү колдо болгон буйрук параметрлерин камтыган жыйынтыкты чыгарат:

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

Чыгуу буйруктарды көрсөтөт listextractи helpс helpдемейки болуу. менен буйрукту иштетели listпараметр:

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

Биз катмар катары кошула турган көз карандылыктардын тизмесин көрөбүз.

Демейки катмарлар:

Кабат аты

ыраазы

dependencies

версиясында SNAPSHOT камтылбаган ар кандай көз карандылык

spring-boot-loader

JAR Loader класстары

snapshot-dependencies

версиясында SNAPSHOT камтылган ар кандай көз карандылык

application

колдонуу класстары жана ресурстар

катмарлар аныкталат layers.idxфайлды Docker сүрөтүнө кошуу керек. Бул катмарлар биринчи издөөдөн кийин хостто кэште сакталат, анткени алар өзгөрбөйт. Хостко жаңыртылган тиркеме катмары гана жүктөлөт, анын көлөмү азайгандыктан ылдамыраак .

Өзүнчө катмарларга бөлүнгөн көз карандылыктар менен сүрөттү түзүү

деген ыкманы колдонуп, эки этапта акыркы сүрөттү курабыз көп баскычтуу чогултуу . Биринчи кадамда биз көз карандылыктарды чыгарабыз, ал эми экинчи кадамда алынган көз карандылыкты акыркы сүрөткө көчүрөбүз.

Көп этаптуу куруу үчүн биздин Dockerfile өзгөртөлү:

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

Бул конфигурацияны өзүнчө файлга сактайбыз - Dockerfile2.

Биз буйрукту колдонуп Docker сүрөтүн курабыз:

docker build -f Dockerfile2 -t usersignup:v1 .

Бул буйрукту иштеткенден кийин биз төмөнкү жыйынтыкты алабыз:

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

Биз Docker сүрөтү сүрөт ID менен түзүлүп, анан тегтелгенин көрө алабыз.

Акырында, түзүлгөн Docker сүрөтүнүн ичиндеги катмарларды текшерүү үчүн Dive буйругун мурункудай аткарабыз. Биз Dive буйругуна киргизүү катары сүрөт ID же тэг бере алабыз:

dive userssignup:v1

Чыгуудан көрүнүп тургандай, тиркемени камтыган катмар азыр болгону 11 КБ жана көз карандылыктар өзүнчө катмарларда кэштелген. 

Жазгы жүктөө колдонмосу үчүн оптималдаштырылган докер сүрөттөрүн куруу

Жеке катмарлар боюнча ички көз карандылыкты алуу

Биз каалаган көз карандылыктарыбызды өзүнчө деңгээлге чыгарып, аларды тиркеме менен таңгактоо менен аларды жарыялоо менен тиркеменин деңгээлин андан ары азайта алабыз. ymlокшош файл аталган 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/"

Бул файлда layers.idxаттуу жеке көз карандылыкты коштук, io.myorgжалпы репозиторийден алынган уюмга көз карандылыктарды камтыйт.

жыйынтыктоо

Бул макалада биз түздөн-түз баштапкы коддон контейнердин сүрөтүн куруу үчүн Cloud-Native Buildpacks колдонууну карадык. Бул кадимки жол менен контейнердин сүрөтүн түзүү үчүн Dockerди колдонууга альтернатива: адегенде жоон аткарылуучу JAR файлын түзүп, андан кийин Docker файлында нускамаларды көрсөтүү менен аны контейнер сүрөтүнө таңгактоо.

Биз ошондой эле көз карандылыктарды хостто кэштелген өзүнчө катмарларга тартуучу катмарлоо функциясын иштетүү аркылуу контейнерибизди оптималдаштырууну карадык жана контейнердин аткаруу кыймылдаткычтарында пландаштыруу убагында колдонмонун жука катмары жүктөлөт.

Сиз макалада колдонулган бардык баштапкы кодду таба аласыз Github .

Буйрук шилтемеси

Бул макалада биз колдонгон буйруктардын кыскача кыскача баяндамасы.

Контекстти тазалоо:

docker system prune -a

Docker файлын колдонуу менен контейнер сүрөтүн түзүү:

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

Биз баштапкы коддон контейнер сүрөтүн курабыз (Dockerfile жок):

mvn spring-boot:build-image

Көз карандылык катмарларын көрүү. Колдонмонун JAR файлын куруудан мурун, Spring-boot-maven-plugin ичинде катмарлоо функциясы иштетилгенин текшериңиз:

java -Djarmode=layertools -jar application.jar list

Көз карандылык катмарларын чыгаруу. Колдонмонун JAR файлын куруудан мурун, Spring-boot-maven-plugin ичинде катмарлоо функциясы иштетилгенин текшериңиз:

 java -Djarmode=layertools -jar application.jar extract

Контейнер сүрөттөрүнүн тизмесин көрүү

docker images

Контейнердин ичиндеги сол жактагы көрүнүш (сууга түшүү куралы орнотулганын текшериңиз):

dive <image ID or image tag>

Source: www.habr.com