Създаване на Docker изображения с Spring Boot

1. Въведение

Тъй като все повече организации се насочват към контейнери и виртуални сървъри, Docker се превръща в по-значителна част от работните процеси на разработката на софтуер. За тази цел една от страхотните нови функции в Spring Boot 2.3 е възможността за лесно създаване на образ на Docker за приложенията на Spring Boot.

В този урок ще разгледаме как да създадем Docker изображения за приложение Spring Spring.

2. Традиционни компилации на Docker

Традиционният начин за изграждане на Docker изображения с Spring Boot е използването на Dockerfile. По-долу е прост пример:

FROM openjdk:8-jdk-alpine EXPOSE 8080 ARG JAR_FILE=target/demo-app-1.0.0.jar ADD ${JAR_FILE} app.jar ENTRYPOINT ["java","-jar","/app.jar"]

След това можем да използваме командата за изграждане на docker, за да създадем образ на Docker. Това работи добре за повечето приложения, но има няколко недостатъка.

Първо, използваме дебелия буркан, създаден от Spring Boot. Това може да повлияе на времето за стартиране, особено в контейнеризирана среда . Можем да спестим време за стартиране, като вместо това добавим взривеното съдържание на файла на jar.

Второ, изображенията на Docker са изградени на слоеве. Характерът на Spring Boot дебели буркани кара всички приложения и библиотеки на трети страни да бъдат поставени в един слой. Това означава, че дори когато се променя само един ред код, целият слой трябва да бъде възстановен .

Чрез експлоадиране на буркана преди изграждане, кодът на приложението и библиотеките на трети страни получават свой собствен слой. Това ни позволява да се възползваме от кеширащия механизъм на Docker. Сега, когато се промени един ред код, трябва да се възстанови само съответният слой.

Имайки предвид това, нека разгледаме как Spring Boot е подобрил процеса на създаване на изображения на Docker.

3. Buildpacks

Buildpacks са инструмент, който осигурява рамка и зависимости на приложенията .

Например, като се получи Spring Boot дебел буркан, компилационният пакет би осигурил Java runtime за нас. Това ни позволява да пропуснем Dockerfile и да получим разумно изображение на Docker автоматично.

Spring Boot включва поддръжка на Maven и Gradle за компилационни пакети. Например, изграждайки с Maven, бихме изпълнили командата:

./mvnw spring-boot:build-image

Нека да разгледаме някои от съответните резултати, за да видим какво се случва:

[INFO] Building jar: target/demo-0.0.1-SNAPSHOT.jar ... [INFO] Building image 'docker.io/library/demo:0.0.1-SNAPSHOT' ... [INFO] > Pulling builder image 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 100% ... [INFO] [creator] ===> DETECTING [INFO] [creator] 5 of 15 buildpacks participating [INFO] [creator] paketo-buildpacks/bellsoft-liberica 2.8.1 [INFO] [creator] paketo-buildpacks/executable-jar 1.2.8 [INFO] [creator] paketo-buildpacks/apache-tomcat 1.3.1 [INFO] [creator] paketo-buildpacks/dist-zip 1.3.6 [INFO] [creator] paketo-buildpacks/spring-boot 1.9.1 ... [INFO] Successfully built image 'docker.io/library/demo:0.0.1-SNAPSHOT' [INFO] Total time: 44.796 s

Първият ред показва, че сме построили стандартния си буркан за мазнини, точно както всеки типичен пакет Maven.

Следващият ред започва изграждането на изображението на Docker. Веднага след това виждаме компилацията в Packeto builder.

Packeto е изпълнение на облачни компилации. Той извършва работата по анализ на нашия проект и определяне на необходимите рамки и библиотеки . В нашия случай той определя, че имаме проект Spring Boot и добавя в необходимите компилации.

Накрая виждаме генерираното изображение на Docker и общото време за изграждане. Забележете как първия път, когато изграждаме, прекарваме доста време в изтегляне на buildpacks и създаване на различни слоеве.

Една от чудесните характеристики на buildpacks е, че изображението на Docker е многослойно. Така че, ако променим само кода на приложението си, последващите компилации ще бъдат много по-бързи:

... [INFO] [creator] Reusing layer 'paketo-buildpacks/executable-jar:class-path' [INFO] [creator] Reusing layer 'paketo-buildpacks/spring-boot:web-application-type' ... [INFO] Successfully built image 'docker.io/library/demo:0.0.1-SNAPSHOT' ... [INFO] Total time: 10.591 s

4. Слоести бурканчета

В някои случаи може да предпочетем да не използваме buildpacks - може би нашата инфраструктура вече е обвързана с друг инструмент или вече имаме персонализирани Dockerfiles, които искаме да използваме повторно.

Поради тези причини Spring Boot също поддържа изграждането на изображения на Docker с помощта на слоести буркани . За да разберем как работи, нека разгледаме типично оформление на дебелия буркан Spring Boot:

org/ springframework/ boot/ loader/ ... BOOT-INF/ classes/ ... lib/ ...

Бурканът за мазнини се състои от 3 основни области:

  • Класове Bootstrap, необходими за стартиране на приложението Spring
  • Код на приложението
  • Библиотеки на трети страни

С многослойните буркани структурата изглежда подобно, но получаваме нов файл layer.idx, който преобразува всяка директория в дебелия буркан в слой:

- "dependencies": - "BOOT-INF/lib/" - "spring-boot-loader": - "org/" - "snapshot-dependencies": - "application": - "BOOT-INF/classes/" - "BOOT-INF/classpath.idx" - "BOOT-INF/layers.idx" - "META-INF/"

Извън кутията Spring Boot предлага четири слоя:

  • зависимости : типични зависимости от трети страни
  • snapshot-зависимости : snapshot зависимости от трети страни
  • ресурси : статични ресурси
  • приложение : код на приложение и ресурси

Целта е да поставите кода на приложението и библиотеките на трети страни в слоеве, които отразяват колко често се променят .

Например кодът на приложението вероятно се променя най-често, така че той получава свой собствен слой. Освен това, всеки слой може да се развива самостоятелно и само когато слой се промени, той ще бъде възстановен за изображението на Docker.

Сега, след като разбрахме новата структура на слоести буркани, нека разгледаме как можем да я използваме за създаване на изображения на Docker.

4.1. Създаване на слоести бурканчета

Първо, трябва да създадем нашия проект, за да създадем слоен буркан. С Maven това означава добавяне на нова конфигурация към раздела за приставки Spring Boot на нашия POM:

 org.springframework.boot spring-boot-maven-plugin   true   

С тази конфигурация командата на пакета Maven (заедно с която и да е от зависимите команди) ще генерира нов слоен буркан, използвайки четирите слоя по подразбиране, споменати по-рано.

4.2. Viewing and Extracting Layers

Next, we need to extract the layers from the jar so that the Docker image will have the proper layers.

To examine the layers of any layered jar, we can run the command:

java -Djarmode=layertools -jar demo-0.0.1.jar list

Then to extract them, we would run:

java -Djarmode=layertools -jar demo-0.0.1.jar extract

4.3. Creating the Docker Image

The easiest way to incorporate these layers into a Docker image is by using a Dockerfile:

FROM adoptopenjdk:11-jre-hotspot as builder ARG JAR_FILE=target/*.jar COPY ${JAR_FILE} application.jar RUN java -Djarmode=layertools -jar application.jar extract FROM adoptopenjdk:11-jre-hotspot COPY --from=builder dependencies/ ./ COPY --from=builder snapshot-dependencies/ ./ COPY --from=builder spring-boot-loader/ ./ COPY --from=builder application/ ./ ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]

This Dockerfile extracts the layers from our fat jar, then copies each layer into the Docker image. Each COPY directive results in a new layer in the final Docker image.

If we build this Dockerfile, we can see each layer from the layered jar get added to the Docker image as its own layer:

... Step 6/10 : COPY --from=builder dependencies/ ./ ---> 2c631b8f9993 Step 7/10 : COPY --from=builder snapshot-dependencies/ ./ ---> 26e8ceb86b7d Step 8/10 : COPY --from=builder spring-boot-loader/ ./ ---> 6dd9eaddad7f Step 9/10 : COPY --from=builder application/ ./ ---> dc80cc00a655 ...

5. Conclusion

В този урок видяхме различни начини за изграждане на изображения на Docker с Spring Boot. Използвайки buildpacks, можем да получим подходящи Docker изображения без шаблон или персонализирани конфигурации. Или с малко повече усилия можем да използваме слоести буркани, за да получим по-съобразено изображение на Docker.

Всички примери в този урок могат да бъдат намерени в GitHub.

За допълнителна информация относно използването на Java и Docker вижте урока по jib.