Spring Boot Tətbiqi üçün Optimallaşdırılmış Docker Şəkillərinin qurulması

Konteynerlər proqramın bütün proqram təminatı və əməliyyat sistemindən asılılıqları ilə qablaşdırma və sonra onları müxtəlif mühitlərə çatdırmaq üçün üstünlük verilən vasitəyə çevrilmişdir.

Bu məqalə Spring Boot tətbiqini konteynerləşdirməyin müxtəlif yollarını əhatə edir:

  • docker faylından istifadə edərək docker təsvirinin yaradılması,
  • Cloud-Native Buildpack istifadə edərək mənbədən OCI təsvirinin yaradılması,
  • və laylı alətlərdən istifadə etməklə JAR hissələrini müxtəlif səviyyələrə ayırmaqla iş vaxtında təsvirin optimallaşdırılması.

 Kod nümunəsi

Bu məqalə iş kodu nümunəsi ilə müşayiət olunur GitHub-da .

Konteyner terminologiyası

Məqalədə istifadə olunan konteyner terminologiyası ilə başlayacağıq:

  • Konteyner şəkli: xüsusi formatlı fayl. Quraşdırma alətini işlətməklə tətbiqimizi konteyner şəklinə çeviririk.
  • Konteyner: Konteyner şəklinin icra edilə bilən nümunəsi.
  • Konteyner mühərriki: Konteyneri işə salmaqdan məsul olan demon prosesi.
  • Konteyner sahibi: Konteyner mühərrikinin işlədiyi əsas maşın.
  • Konteyner reyestri: Konteyner şəklini dərc etmək və yaymaq üçün istifadə olunan ümumi yer.
  • OCI standartıAçıq Konteyner Təşəbbüsü (OCI) Linux Fondu tərəfindən yaradılmış yüngül, açıq mənbəli idarəetmə çərçivəsidir. OCI Şəkil Spesifikasiyası konteyner təsvir formatları üçün sənaye standartlarını və bütün konteyner mühərriklərinin hər hansı bir qurma aləti tərəfindən yaradılmış konteyner şəkillərini işlədə bilməsini təmin etmək üçün iş vaxtını müəyyən edir.

Tətbiqi konteynerləşdirmək üçün tətbiqimizi konteyner şəklinə bükürük və həmin şəkli ictimai reyestrdə dərc edirik. Konteynerin işləmə vaxtı bu təsviri reyestrdən alır, paketdən çıxarır və onun daxilindəki proqramı işə salır.

Spring Boot-un 2.3 versiyası OCI şəkillərinin yaradılması üçün plaginləri təmin edir.

yükvuran ən çox istifadə edilən konteyner tətbiqidir və biz nümunələrimizdə Docker-dən istifadə edirik, buna görə də bu məqalədəki bütün sonrakı konteyner istinadları Docker-ə istinad edəcək.

Ənənəvi şəkildə konteyner təsvirinin qurulması

Spring Boot proqramları üçün Docker şəkillərini yaratmaq, Dockerfile-ə bir neçə təlimat əlavə etməklə çox asandır.

Biz əvvəlcə icra edilə bilən JAR yaradırıq və Dockerfile təlimatlarının bir hissəsi kimi, lazımi fərdiləşdirmələri tətbiq etdikdən sonra icra edilə bilən JAR-ı əsas JRE şəklinin üstünə kopyalayırıq.

Gəlin Bahar tətbiqimizi yaradaq Bahar başlanğıcı asılılıqlarla weblombokи actuator. API təmin etmək üçün istirahət nəzarətçisi də əlavə edirik GETüsul.

Dockerfile yaradılması

Sonra bu proqramı əlavə edərək konteynerə yerləşdiririk Dockerfile:

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

Bizim Dockerfaylımız əsas təsvirdən ibarətdir adoptopenjdk, bunun üzərinə JAR faylımızı kopyalayırıq və sonra portu açırıq, 8080istəkləri dinləyəcək.

Tətbiq montajı

Əvvəlcə Maven və ya Gradle istifadə edərək proqram yaratmalısınız. Burada Maven istifadə edirik:

mvn clean package

Bu proqram üçün icra edilə bilən JAR faylı yaradır. Docker mühərrikində işləmək üçün bu icra edilə bilən JAR-ı Docker təsvirinə çevirməliyik.

Konteyner şəkli yaradın

Daha sonra əmri işlətməklə bu JAR icra olunanı Docker təsvirinə yerləşdirdik docker builddaha əvvəl yaradılmış Dockerfile olan layihənin kök kataloqundan:

docker build  -t usersignup:v1 .

Biz öz şəklimizi komanda ilə siyahıda görə bilərik:

docker images 

Yuxarıdakı əmrin çıxışı bizim şəklimizi ehtiva edir usersignupəsas şəkil ilə birlikdə, adoptopenjdkDockerfile-də müəyyən edilmişdir.

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

Konteyner şəklinin içərisindəki təbəqələrə baxın

Şəklin içərisində olan təbəqə yığınına baxaq. istifadə edəcəyik alət  dalış, Bu təbəqələrə baxmaq üçün:

dive usersignup:v1

Budur Dive əmrinin çıxışının bir hissəsi: 

Spring Boot Tətbiqi üçün Optimallaşdırılmış Docker Şəkillərinin qurulması

Gördüyümüz kimi, tətbiq təbəqəsi təsvir ölçüsünün əhəmiyyətli bir hissəsini təşkil edir. Biz optimallaşdırmamızın bir hissəsi olaraq aşağıdakı bölmələrdə bu təbəqənin ölçüsünü azaltmaq istəyirik.

Buildpack ilə konteyner şəklinin qurulması

Montaj paketləri (Quraşdırma paketləri) mənbə kodundan konteyner şəkli yaratmaq üçün müxtəlif Platforma Xidmət kimi (PAAS) təklifləri tərəfindən istifadə olunan ümumi termindir. 2011-ci ildə Heroku tərəfindən istifadəyə verilmiş və o vaxtdan Cloud Foundry, Google App Engine, Gitlab, Knative və bir neçə başqa şirkət tərəfindən qəbul edilmişdir.

Spring Boot Tətbiqi üçün Optimallaşdırılmış Docker Şəkillərinin qurulması

Bulud Quraşdırma Paketlərinin Üstünlüyü

Şəkillər yaratmaq üçün Buildpack istifadə etməyin əsas üstünlüklərindən biri budur image konfiqurasiya dəyişiklikləri mərkəzləşdirilmiş şəkildə idarə oluna bilər (yaradıcı) və qurucudan istifadə edərək bütün tətbiqlərə yayıla bilər.

Quraşdırma paketləri platforma ilə sıx bağlı idi. Cloud-Native Buildpacks OCI təsvir formatını dəstəkləməklə platformalar arasında standartlaşdırma təmin edir ki, bu da təsvirin Docker mühərriki tərəfindən idarə olunmasını təmin edir.

Spring Boot Plugin istifadə edərək

Spring Boot plagini Buildpack istifadə edərək mənbədən OCI şəkillərini qurur. Şəkillər istifadə edərək yaradılır bootBuildImagetapşırıqlar (Gradle) və ya spring-boot:build-imagehədəf (Maven) və yerli Docker quraşdırılması.

Adı qeyd etməklə Docker reyestrinə köçürməli olduğumuz şəklin adını fərdiləşdirə bilərik. 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>

İcra etmək üçün Maven-dən istifadə edək build-imageproqram yaratmaq və konteyner şəkli yaratmaq məqsədləri. Hazırda heç bir Dockerfiles istifadə etmirik.

mvn spring-boot:build-image

Nəticə belə bir şey olacaq:

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

Çıxışdan bunu görürük paketo Cloud-Native buildpackişləyən OCI təsviri yaratmaq üçün istifadə olunur. Əvvəlki kimi, biz əmri işlətməklə Docker təsviri kimi qeyd olunan şəkli görə bilərik:

docker images 

Nəticə:

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

Jib ilə konteyner şəklinin yaradılması

Jib, mənbədən konteyner şəkli yaratmağın alternativ üsulunu təmin edən Google-dan şəkil yaratma plaginidir.

Özelleştirin jib-maven-pluginpom.xml-də:

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

Sonra, tətbiqi qurmaq və konteyner şəklini yaratmaq üçün Maven əmrindən istifadə edərək Jib plaginini işə salırıq. Əvvəlki kimi, biz burada heç bir Dockerfiles istifadə etmirik:

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

Yuxarıdakı Maven əmrini yerinə yetirdikdən sonra aşağıdakı nəticəni alırıq:

[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

Çıxış, konteyner şəklinin yaradıldığını və reyestrdə yerləşdirildiyini göstərir.

Optimallaşdırılmış şəkillər yaratmaq üçün motivlər və üsullar

Optimallaşdırmağın iki əsas səbəbi var:

  • Məhsuldarlıq: Konteynerin orkestrasiya sistemində konteyner təsviri təsvir reyestrindən konteyner mühərriki ilə işləyən hosta çəkilir. Bu proses planlaşdırma adlanır. Reyestrdən böyük şəkillərin çıxarılması konteyner orkestrləşdirmə sistemlərində uzun planlaşdırma vaxtlarına və CI boru kəmərlərində uzun qurma vaxtlarına səbəb olur.
  • təhlükəsizlik: böyük şəkillərdə zəifliklər üçün də geniş sahə var.

Docker təsviri hər biri Dockerfile-də ifadəni təmsil edən təbəqələr yığınından ibarətdir. Hər bir təbəqə alt qatdakı dəyişikliklərin deltasını təmsil edir. Reyestrdən Docker şəklini çəkdiyimiz zaman o, təbəqələrə çəkilir və hostda keşlənir.

Spring Boot istifadə edir "yağlı jar" içində standart qablaşdırma formatı kimi. Yağlı bir JAR-a baxdıqda, tətbiqin bütün JAR-ın çox kiçik bir hissəsi olduğunu görürük. Bu, ən çox dəyişən hissədir. Qalanları Spring Framework asılılıqlarından ibarətdir.

Optimallaşdırma düsturu tətbiqi Spring Framework asılılıqlarından ayrı səviyyədə təcrid etmək ətrafında cəmlənmişdir.

Qalın JAR faylının əsas hissəsini təşkil edən asılılıq təbəqəsi yalnız bir dəfə endirilir və host sistemində keşlənir.

Proqram yeniləmələri və konteyner planlaşdırması zamanı tətbiqin yalnız nazik təbəqəsi çəkilir, bu diaqramda göstərildiyi kimi:

Spring Boot Tətbiqi üçün Optimallaşdırılmış Docker Şəkillərinin qurulması

Növbəti bölmələrdə Spring Boot tətbiqi üçün bu optimallaşdırılmış şəkillərin necə yaradılacağına baxacağıq.

Buildpack ilə Spring Boot Tətbiqi üçün Optimallaşdırılmış Konteyner Şəkilinin qurulması

Spring Boot 2.3 qalın JAR faylının hissələrini ayrı-ayrı təbəqələrə çıxararaq təbəqələşdirməni dəstəkləyir. Qatlama xüsusiyyəti defolt olaraq qeyri-aktivdir və Spring Boot Maven plaginindən istifadə edərək açıq şəkildə aktivləşdirilməlidir:

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

Bu konfiqurasiyadan konteyner təsvirimizi əvvəlcə Buildpack, sonra isə Docker ilə aşağıdakı bölmələrdə qurmaq üçün istifadə edəcəyik.

Gəl qaçaq build-imageMaven konteyner şəklini yaratmağı hədəfləyir:

mvn spring-boot:build-image

Yaranan şəkildəki təbəqələri görmək üçün Dive-i işə salsaq, görərik ki, tətbiq təbəqəsi (qırmızı ilə dairəvi) qalın JAR formatından istifadə etdiyimizlə müqayisədə kilobayt diapazonunda çox kiçikdir:

Spring Boot Tətbiqi üçün Optimallaşdırılmış Docker Şəkillərinin qurulması

Docker ilə Spring Boot Tətbiqi üçün Optimallaşdırılmış Konteyner Şəkilinin qurulması

Maven və ya Gradle plaginindən istifadə etmək əvəzinə, Docker faylı ilə qatlı Docker JAR şəkli də yarada bilərik.

Docker-dən istifadə etdikdə, təbəqələri çıxarmaq və onları son görüntüyə köçürmək üçün əlavə iki addım atmalıyıq.

Qatlaşdırma aktivləşdirilmiş Maven ilə tikildikdən sonra yaranan JAR-ın məzmunu belə görünəcək:

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

Çıxış adlı əlavə JAR göstərilir spring-boot-jarmode-layertoolsи layersfle.idxfayl. Bu əlavə JAR faylı növbəti hissədə təsvir olunduğu kimi təbəqələşdirmə imkanlarını təmin edir.

Ayrı-ayrı təbəqələrdən asılılıqları çıxarın

Laylı JAR-dan təbəqələrə baxmaq və çıxarmaq üçün biz sistem xassəsindən istifadə edirik -Djarmode=layertoolsbaşlanğıc üçün spring-boot-jarmode-layertoolsƏrizə əvəzinə JAR:

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

Bu əmri yerinə yetirmək mövcud əmr seçimlərini ehtiva edən bir nəticə çıxarır:

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

Çıxış əmrləri göstərir listextractи helpс helpstandart olun. ilə əmri icra edək listseçim:

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

Biz təbəqələr kimi əlavə edilə bilən asılılıqların siyahısını görürük.

Defolt olaraq qatlar:

Qat adı

Məzmun

dependencies

versiyasında SNAPSHOT olmayan istənilən asılılıq

spring-boot-loader

JAR yükləyici sinifləri

snapshot-dependencies

versiyasında SNAPSHOT olan istənilən asılılıq

application

tətbiq sinifləri və resursları

Qatlar müəyyən edilir layers.idxfaylı Docker şəklinə əlavə edilməli olan ardıcıllıqla. Dəyişmədiyi üçün bu təbəqələr ilk gətirmədən sonra hostda keşlənir. Yalnız yenilənmiş tətbiq təbəqəsi hosta endirilir ki, bu da azaldılmış ölçüyə görə daha sürətli olur .

Ayrı-ayrı təbəqələrə çıxarılan asılılıqlarla təsvirin qurulması

adlı metoddan istifadə edərək son şəkli iki addımda quracağıq çoxmərhələli montaj . Birinci mərhələdə biz asılılıqları çıxaracağıq, ikinci mərhələdə isə çıxarılan asılılıqları finala köçürəcəyik.

Çoxmərhələli quruluş üçün Dockerfaylımızı dəyişdirək:

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

Bu konfiqurasiyanı ayrı bir faylda saxlayırıq - Dockerfile2.

Komandadan istifadə edərək Docker şəklini qururuq:

docker build -f Dockerfile2 -t usersignup:v1 .

Bu əmri yerinə yetirdikdən sonra aşağıdakı nəticəni alırıq:

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 şəklinin şəkil identifikatoru ilə yaradıldığını və sonra etiketləndiyini görə bilərik.

Nəhayət, yaradılan Docker təsvirinin içindəki təbəqələri yoxlamaq üçün Dive əmrini əvvəlki kimi icra edirik. Dive əmrinə giriş olaraq şəkil identifikatoru və ya etiket təqdim edə bilərik:

dive userssignup:v1

Çıxışdan göründüyü kimi, tətbiqi ehtiva edən təbəqə indi cəmi 11 KB-dır və asılılıqlar ayrı-ayrı təbəqələrdə yaddaşda saxlanılır. 

Spring Boot Tətbiqi üçün Optimallaşdırılmış Docker Şəkillərinin qurulması

Ayrı-ayrı təbəqələrdə daxili asılılıqları çıxarın

İstənilən fərdi asılılığımızı tətbiqdə bəyan etməklə onları proqramla qablaşdırmaq əvəzinə ayrı bir təbəqəyə çıxararaq tətbiq təbəqəsinin ölçüsünü daha da azalda bilərik. ymladlı oxşar 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/"

Bu faylda layers.idxadlı xüsusi asılılıq əlavə etdik, io.myorgpaylaşılan depodan əldə edilən təşkilat asılılıqlarını ehtiva edir.

Buraxılış

Bu yazıda biz birbaşa mənbədən konteyner şəkli yaratmaq üçün Cloud-Native Buildpacks-dən istifadə etməyə baxdıq. Bu, adi şəkildə konteyner təsviri yaratmaq üçün Docker-dən istifadəyə alternativdir: əvvəlcə qalın icra edilə bilən JAR faylı yaradılır və sonra Dockerfile-də təlimatları təyin etməklə konteyner şəklinə qablaşdırılır.

Asılılıqları hostda keşlənmiş ayrı-ayrı təbəqələrə çıxaran və konteynerin icra mühərriklərində planlaşdırma zamanı nazik tətbiq təbəqəsi yüklənən təbəqə xüsusiyyətini daxil etməklə konteynerimizi optimallaşdırmağa da baxdıq.

Məqalədə istifadə olunan bütün mənbə kodunu burada tapa bilərsiniz Github .

Komanda Referansı

Tez istinad üçün bu məqalədə istifadə etdiyimiz əmrlərin xülasəsi budur.

Kontekst təmizlənməsi:

docker system prune -a

Dockerfile ilə konteyner şəklinin qurulması:

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

Mənbədən konteyner şəklini yaradın (Dockerfile olmadan):

mvn spring-boot:build-image

Asılılıq qatlarına baxın. Tətbiq jar faylını yaratmazdan əvvəl, spring-boot-maven-plugin-də təbəqələşdirmə funksiyasının aktiv olduğundan əmin olun:

java -Djarmode=layertools -jar application.jar list

Asılılıq təbəqələrini çıxarın. Tətbiq jar faylını yaratmazdan əvvəl, spring-boot-maven-plugin-də təbəqələşdirmə funksiyasının aktiv olduğundan əmin olun:

 java -Djarmode=layertools -jar application.jar extract

Konteyner Şəkillərinin Siyahısına Baxın

docker images

Konteyner şəklinin içərisində solda baxın (dalış alətinin quraşdırıldığından əmin olun):

dive <image ID or image tag>

Mənbə: www.habr.com