Сравнение современных построителей образов контейнеров: Jib, Buildpacks и Docker

Kate

Administrator
Команда форума
В этой статье будут рассмотрены и сравнены различные методы контейнеризации Java-приложений.

700244248009a8266f449de225f35fde.png

Вступление​

Docker приобрел огромную популярность с момента своего дебюта в 2013 году. Многие предприятия полагаются на Docker для контейнеризации своих приложений. Многие вещи благоприятствуют популярности Docker, например, то, что он обеспечивает изоляцию, согласованную среду и идеально подходят для сценариев использования микросервисов, что делает его незаменимым для создания контейнеров. Однако в мире технологий нет ничего постоянного, и всегда есть альтернатива. Часто возникает необходимость исправить недостатки инструмента. Так в чем же недостатки Docker? Я бы, во-первых, включил необходимость root-доступа и, во-вторых, зависимость от процесса-демона.

Нет никакого неприятия Docker. Но у каждой технологии есть свои сценарии использования. Предположим, ваш сценарий использования относительно прост, и вы не заинтересованы в изучении новой технологии для контейнеризации вашего Java-приложения. В этом случае есть альтернативы получше, чем Docker. Эти инструменты появились за последние несколько лет из-за трудностей разработчиков при контейнеризации своих приложений. Создание контейнеров для Java-приложений - нетривиальная задача. Это требует обучения, так как вы должны познакомиться с командами для конкретных инструментов и т. д. Не следует ожидать, что Java разработчики также будут экспертами по контейнерам.

В этом сообщении мы обсудим с нуля Docker и его альтернативы, достойные рассмотрения для контейнеризации ваших Java-приложений. Эти инструменты позволят вам получить контейнерное приложение с минимальными установками и настройками. Вероятно, вам даже не потребуется устанавливать Docker или работать с Dockerfile. К концу этой статьи вы сможете решить, какой построитель образов контейнера является самым быстрым, потребляет наименьшее количество ресурсов, проще в настройке и лучше всего подходит для вашего сценария использования.

Сравниваемые инструменты​

В этой статье мы рассмотрим основные концепции и приведем краткое пошаговое руководство для следующих инструментов построения образов контейнеров:

  1. Jib
  2. Buildpacks
  3. Docker

Структура сравнения​

Мы будем использовать следующие критерии и характеристики для анализа инструментов построения образов контейнеров.

  1. Легкость использования
  2. Потребление ресурсов (память, дисковое пространство и т. д.)
  3. Время, затраченное на создание образа (первая сборка или последующая сборка)
  4. Оптимизация слоев образов

Пререквизиты​

Если вы хотите продолжить, убедитесь, что у вас есть следующее:

  1. Rancher для разработчиков, если вы планируете развертывать и запускать созданные образы
  2. Учетная запись DockerHub
  3. Docker для Desktop
  4. OpenJDK11
  5. IDE по вашему выбору
  6. Проект Spring Boot с версией 2.3 или выше

Анатомия приложения Spring Boot​

Приложение Spring Boot, которое мы используем для этого сравнения, представляет собой простое приложение Hello World. Мы предоставили конечную точку REST /hello на локальном хосте через curl или клиент REST, например, Postman вернет строковое сообщение «Hello World !!!». Исходный код приложения Spring Boot доступен здесь. В этой статье мы намеренно урезали вывод, чтобы уменьшить многословность журналов.

Альтернативный вариант: Jib​

Jib - это контейнерный Java-контейнер от Google, который позволяет Java-разработчикам создавать контейнеры с помощью таких инструментов сборки, как Maven и Gradle.
Главное в Jib заключается в том, что вам не нужно ничего знать об установке Docker или поддержке Dockerfile. Jib не имеет демона. Более того, как разработчик, вы заботитесь только об артефакте (jar, war и т. д.), Который вы создадите, и вам не нужно иметь дело с какой-либо ерундой Docker (сборка / push и т. д.). Разработчику Java просто нужно добавить плагин к инструменту сборки по своему выбору (Maven / Gradle), и все. Вам не нужно проходить множество руководств, чтобы изучить такие технологии, как Docker, для контейнеризации вашего Java-приложения.

Создание образа с помощью Jib​

Перед созданием образа вам необходимо добавить поддержку Jib в ваше Spring Boot приложение. Мы можем включить эту поддержку, просто добавив плагин Maven или Gradle в ваш файл pom.xml или build.gradle. Начать работу с Jib несложно.

Для Maven Spring Boot Project добавьте в файл pom.xml следующее:

<project>
...
<build>
<plugins>
...
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>2.7.1</version>
<configuration>
<to>
<image>docker.io/my-docker-id/my-app</image>
</to>
</configuration>
</plugin>
...
</plugins>
</build>
...
</project>
Для Gradle Spring Boot Project добавьте в файл build.gradle следующее:

plugins {
id 'com.google.cloud.tools.jib' version '2.7.1'
}
jib.to.image = 'my-docker-id/my-app'
Кроме того, слои, создаваемые Jib, строятся поверх базового образа без дистрибутива. По умолчанию Jib использует образ Java 8 без дистрибутива, но вы можете выбрать образ по своему усмотрению. В этой демонстрации мы сосредоточимся на контейнеризации приложения с помощью плагина Maven Jib. Чтобы отправить образ в выбранный вами реестр контейнеров, вам необходимо добавить учетные данные реестра в maven settings.xml. Вы также должны просмотреть этот пост о том, как выполнить настройку для разных реестров контейнеров. Например, можно использовать следующую конфигурацию для отправки образа в реестр контейнеров DockerHub.

<server>
<id>registry.hub.docker.com</id>
<username>username</username>
<password>password</password>
</server>
Мы можем начать создание образа с помощью следующей команды:

mvn compile jib:build
Он скомпилирует, построит и затем отправит образ вашего приложения в настроенный реестр контейнеров. Ниже приводится результат.

time mvn compile jib:build
..........
[INFO] Containerizing application to registry.hub.docker.com/hiashish/spring-boot-jib...
[WARNING] Base image 'gcr.io/distroless/java:11' does not use a specific image digest - build may not be reproducible
[INFO] Using credentials from Maven settings file for registry.hub.docker.com/hiashish/spring-boot-jib
[INFO] Using base image with digest: sha256:449c1c57fac9560ee06cd50f8a3beeb9b8cc22f1ed128f068457f7607bcfcac6
[INFO]
[INFO] Container entrypoint set to [java, -cp, /app/resources:/app/classes:/app/libs/*, com.compare.imagebuilder.Application]
[INFO]
[INFO] Built and pushed image as registry.hub.docker.com/hiashish/spring-boot-jib
[INFO] Executing tasks:
[INFO] [==============================] 100.0% complete
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 31.183 s
[INFO] Finished at: 2021-02-19T16:51:35+05:30
[INFO] ------------------------------------------------------------------------
mvn compile jib:build -DskipTests 20.81s user 1.78s system 68% cpu 33.032 total
Jib также может создавать и сохранять образ с помощью локального демона Docker, используя следующую команду. Однако нам придется отправить образ вручную с помощью команды docker push.

mvn compile jib:dockerBuild
Ниже приводится результат:

.......
[INFO] Containerizing application to Docker daemon as hiashish/spring-boot-jib...
[WARNING] Base image 'gcr.io/distroless/java:11' does not use a specific image digest - build may not be reproducible
[INFO] Using base image with digest: sha256:449c1c57fac9560ee06cd50f8a3beeb9b8cc22f1ed128f068457f7607bcfcac6
[INFO]
[INFO] Container entrypoint set to [java, -cp, /app/resources:/app/classes:/app/libs/*, com.compare.imagebuilder.Application]
[INFO]
[INFO] Built image to Docker daemon as hiashish/spring-boot-jib
[INFO] Executing tasks:
[INFO] [==============================] 100.0% complete
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 21.340 s
[INFO] Finished at: 2021-02-19T18:48:41+05:30
[INFO] ------------------------------------------------------------------------
mvn compile jib:dockerBuild 15.90s user 2.57s system 78% cpu 23.568 total
Размер образа:

REPOSITORY TAG IMAGE ID CREATED SIZE
hiashish/spring-boot-jib latest eacedad2d476 51 years ago 214MB
Ниже показано использование памяти docker statsпосле запуска нашего приложения Spring Boot Hello-World в качестве контейнера Docker.

CONTAINER ID NAME CPU % MEM USAGE / LIMIT
de0358ed9920 epic_varahamihira 1.04% 116.8MiB / 1.944GiB

Вторая альтернатива: Buildpacks​

Cloud Native Buildpacks преобразует исходный код вашего приложения в образы, которые можно запускать в любом облаке.
Buildpacks был впервые разработан Heroku в 2011 году, но теперь он является частью фонда CNCF. Как и Jib, пакеты сборки могут работать и без Dockerfile, но вам понадобится процесс демона Docker, чтобы реализовать его магию. В Buildpack входом является исходный код вашего приложения, а выходом - образ контейнера. В этой части он очень похож на Jib, но Jib может делать это без демона docker. В фоновом режиме Buildpack выполняет много работы, такой как получение зависимостей, обработка ресурсов, обработка кеширования и компиляция кода для любого языка, на котором построено ваше приложение.

Создание образа с помощью Buildpacks​

Начиная с версии 2.3, Spring Boot включает прямую поддержку Buildpack как для Maven, так и для Gradle. Одна команда может дать вам разумный образ вашего локально запущенного демона Docker. Buildpack требует, чтобы демон docker был запущен и работал. Если у вас не запущен демон docker, вы получите следующую ошибку при выполнении команды Maven.

Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.4.2:build-image (default-cli) on project imagebuilder: Execution default-cli of goal org.springframework.boot:spring-boot-maven-plugin:2.4.2:build-image failed: Connection to the Docker daemon at 'localhost' failed with error "[61] Connection refused"; ensure the Docker daemon is running and accessible
Для Maven Spring Boot Project запустите сборку с помощью следующей команды:

mvn spring-boot:build-image
Для Gradle Spring Boot проекта запустите сборку с помощью следующей команды:

gradle bootBuildImage
Поведение сборки пакетов по умолчанию с помощью Spring Boot заключается в том, чтобы сохранить образ локально для демона Docker. Однако вы также можете отправить свои образы в удаленный реестр контейнеров. Чтобы это сработало, нам необходимо внести следующие изменения в файл Maven pom.xml.

<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<name>docker.example.com/library/${project.artifactId}</name>
<publish>true</publish>
</image>
<docker>
<publishRegistry>
<username>user</username>
<password>secret</password>
<url>https://docker.example.com/v1/</url>
<email>user@example.com</email>
</publishRegistry>
</docker>
</configuration>
</plugin>
</plugins>
</build>
</project>
Сначала мы попытаемся создать и опубликовать образ для локального демона Docker. Начнем сборку с команды mvn spring-boot:build-imageMaven Build. Ниже приводится результат.

[INFO] [creator] Adding layer 'paketo-buildpacks/ca-certificates:helper'
[INFO] [creator] Adding layer 'paketo-buildpacks/bellsoft-liberica:helper'
[INFO] [creator] Adding layer 'paketo-buildpacks/bellsoft-liberica:java-security-properties'
[INFO] [creator] Adding layer 'paketo-buildpacks/bellsoft-liberica:jre'
[INFO] [creator] Adding layer 'paketo-buildpacks/bellsoft-liberica:jvmkill'
[INFO] [creator] Adding layer 'paketo-buildpacks/executable-jar:class-path'
[INFO] [creator] Adding layer 'paketo-buildpacks/spring-boot:helper'
[INFO] [creator] Adding layer 'paketo-buildpacks/spring-boot:spring-cloud-bindings'
[INFO] [creator] Adding layer 'paketo-buildpacks/spring-boot:web-application-type'
[INFO] [creator] Adding 5/5 app layer(s)
[INFO] [creator] Adding layer 'launcher'
[INFO] [creator] Adding layer 'config'
[INFO] [creator] Adding layer 'process-types'
[INFO] [creator] Adding label 'io.buildpacks.lifecycle.metadata'
[INFO] [creator] Adding label 'io.buildpacks.build.metadata'
[INFO] [creator] Adding label 'io.buildpacks.project.metadata'
[INFO] [creator] Adding label 'org.opencontainers.image.title'
[INFO] [creator] Adding label 'org.opencontainers.image.version'
[INFO] [creator] Adding label 'org.springframework.boot.spring-configuration-metadata.json'
[INFO] [creator] Adding label 'org.springframework.boot.version'
[INFO] [creator] Setting default process type 'web'
[INFO] [creator] *** Images (20569cdcf777):
[INFO] [creator] docker.io/library/buildpack:0.0.1-SNAPSHOT
[INFO]
[INFO] Successfully built image 'docker.io/library/buildpack:0.0.1-SNAPSHOT'
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:49 min
[INFO] Finished at: 2021-02-20T01:07:08+05:30
[INFO] ------------------------------------------------------------------------
mvn compile spring-boot:build-image -DskipTests 19.33s user 1.40s system 18% cpu 1:51.21 total
Теперь мы создадим и разместим образ в удаленном реестре контейнеров.

Выполним команду mvn spring-boot:build-image.

[INFO] [creator] Adding label 'io.buildpacks.build.metadata'
[INFO] [creator] Adding label 'io.buildpacks.project.metadata'
[INFO] [creator] Adding label 'org.opencontainers.image.title'
[INFO] [creator] Adding label 'org.opencontainers.image.version'
[INFO] [creator] Adding label 'org.springframework.boot.spring-configuration-metadata.json'
[INFO] [creator] Adding label 'org.springframework.boot.version'
[INFO] [creator] Setting default process type 'web'
[INFO] [creator] *** Images (dc8e2a8dc2e2):
[INFO] [creator] registry.hub.docker.com/hiashish/buildpack:latest
[INFO]
[INFO] Successfully built image 'registry.hub.docker.com/hiashish/buildpack:latest'
[INFO]
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 0%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 9%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 15%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 18%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 18%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 18%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 32%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 38%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 40%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 45%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 45%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 55%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 60%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 61%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 62%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 67%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 77%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 79%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 89%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 90%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 91%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 92%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 94%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 95%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 95%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 95%
[INFO] > Pushing image 'registry.hub.docker.com/hiashish/buildpack:latest' 100%
[INFO] > Pushed image 'registry.hub.docker.com/hiashish/buildpack:latest'
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 02:58 min
[INFO] Finished at: 2021-02-20T01:19:26+05:30
[INFO] ------------------------------------------------------------------------
mvn compile spring-boot:build-image -DskipTests 19.33s user 1.38s system 11% cpu 3:00.29 total
Размер образа:

REPOSITORY TAG IMAGE ID CREATED SIZE
hiashish/buildpack 0.0.1-SNAPSHOT 20569cdcf777 41 years ago 258MB
Ниже показано использование памяти docker statsпосле запуска нашего приложения Spring Boot Hello World в качестве контейнера Docker.

CONTAINER ID NAME CPU % MEM USAGE / LIMIT
a05ee6e6a07b strange_goodall 0.54% 121.8MiB / 1.944GiB

Альтернатива третья: Docker​

Docker - это де-факто стандарт для создания контейнерных приложений. Docker зависит от процесса-демона, который должен работать для обслуживания всех ваших команд Docker. Docker CLI запускает команду для демона docker и выполняет необходимые операции (например, отправка / извлечение образов, запуск контейнеров и т. д.). Docker использует файл с именем Dockerfile, написанный вами с шагами и инструкциями, понятными Docker. Затем этот Dockerfile используется для создания образа контейнера вашего приложения с помощью такой команды, как docker build. Преимущество здесь в том, что он позволяет использовать различные уровни настройки при создании образа контейнера вашего приложения в соответствии с вашими потребностями.

Наивный способ создания образа с помощью Docker​

Чтобы создать образ с помощью Docker, нам нужно добавить несколько инструкций в наш Dockerfile. Эти инструкции действуют как ввод, а затем процесс демона Docker создает образ с этими инструкциями. Обратной стороной этого подхода является то, что нам нужно создать артефакт с помощью команды mvn clean package, чтобы Docker мог скопировать последнюю версию jar. Это добавит времени процессу создания образа. В этом подходе мы не рассматривали оптимизацию наложения образов с помощью таких методов, как многоэтапное построение. Нам просто нужна контейнерная версия нашего приложения, но это неэффективно, поскольку мы использовали большой базовый образ нашего приложения. Ниже указано время, необходимое для создания артефакта с помощью команды пакета maven.

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 8.734 s
[INFO] Finished at: 2021-02-18T22:07:40+05:30
[INFO] ------------------------------------------------------------------------
Вот Dockerfile для нашего приложения Spring Boot Hello-World.

# Rookie way of writing Dockerfile
FROM openjdk:11

COPY target/*.jar app.jar

ENTRYPOINT ["java","-jar","/app.jar"]
  1. Инструкция FROM указывает базовый образ для нашего приложения
  2. Инструкция COPY, как следует из названия, скопирует локальный jar-файл, созданный Maven, в наш образ.
  3. Инструкция точки входа действует как исполняемый файл для нашего контейнера при запуске
Хорошо, тогда приступим. Ниже приведены результаты выполнения этого файла Dockerfile с помощью команды docker build.

time docker build -t hiashish/imagebuilder:latest .
[+] Building 50.8s (8/8) FINISHED
=> [internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 121B 0.1s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/openjdk:11 3.3s
=> [auth] library/openjdk:pull token for registry-1.docker.io 0.0s
=> [internal] load build context 2.3s
=> => transferring context: 17.04MB 2.3s
=> [1/2] FROM docker.io/library/openjdk:11@sha256:3805f5303af58ebfee1d2f5cd5a897e97409e48398144afc2233f7b778337017 46.7s
=> => resolve docker.io/library/openjdk:11@sha256:3805f5303af58ebfee1d2f5cd5a897e97409e48398144afc2233f7b778337017 0.0s
=> => sha256:0ecb575e629cd60aa802266a3bc6847dcf4073aa2a6d7d43f717dd61e7b90e0b 50.40MB / 50.40MB 0.0s
=> => sha256:feab2c490a3cea21cc051ff29c33cc9857418edfa1be9966124b18abe1d5ae16 10.00MB / 10.00MB 0.0s
=> => sha256:f15a0f46f8c38f4ca7daecf160ba9cdb3ddeafda769e2741e179851cfaa14eec 51.83MB / 51.83MB 0.0s
=> => sha256:26cb1dfcbebb21160622ee663cb64f65e625a9f3d98c55b9555e21e2cb15e400 5.29MB / 5.29MB 0.0s
=> => sha256:242c5446d23fd9e18b2a08efc86e19bcf271b95038f7a2a58f4819fb362dee36 208B / 208B 0.0s
=> => sha256:3805f5303af58ebfee1d2f5cd5a897e97409e48398144afc2233f7b778337017 1.04kB / 1.04kB 0.0s
=> => sha256:2d17e02b6902d28c8546b2a1feff7e4a1fd74c703339bca6ae1c45584b9a0b67 1.79kB / 1.79kB 0.0s
=> => sha256:82e02728b3fd3958c5ca23fb86b9f06ba2e4bb834c0e456fe2d278a932923d53 6.27kB / 6.27kB 0.0s
=> => sha256:7467d1831b6947c294d92ee957902c3cd448b17c5ac2103ca5e79d15afb317c3 7.83MB / 7.83MB 0.0s
=> => sha256:f22708c7c9c1856c05e56ae8f5812a24b7304cb80ebfc9a34dd4f4cbaf3dd6d2 202.80MB / 202.80MB 0.0s
=> => extracting sha256:0ecb575e629cd60aa802266a3bc6847dcf4073aa2a6d7d43f717dd61e7b90e0b 9.3s
=> => extracting sha256:7467d1831b6947c294d92ee957902c3cd448b17c5ac2103ca5e79d15afb317c3 1.1s
=> => extracting sha256:feab2c490a3cea21cc051ff29c33cc9857418edfa1be9966124b18abe1d5ae16 1.2s
=> => extracting sha256:f15a0f46f8c38f4ca7daecf160ba9cdb3ddeafda769e2741e179851cfaa14eec 9.5s
=> => extracting sha256:26cb1dfcbebb21160622ee663cb64f65e625a9f3d98c55b9555e21e2cb15e400 0.7s
=> => extracting sha256:242c5446d23fd9e18b2a08efc86e19bcf271b95038f7a2a58f4819fb362dee36 0.0s
=> => extracting sha256:f22708c7c9c1856c05e56ae8f5812a24b7304cb80ebfc9a34dd4f4cbaf3dd6d2 20.6s
=> [2/2] COPY target/*.jar app.jar 0.2s
=> exporting to image 0.3s
=> => exporting layers 0.2s
=> => writing image sha256:6704ddf7df3398be458722ea1c4d8c17393dc656a1a8ae89152f99c5462b0306 0.0s
=> => naming to docker.io/hiashish/imagebuilder:latest 0.0s
docker build -t hiashish/imagebuilder:latest . 0.82s user 0.64s system 2% cpu 51.572 total
Затем мы опубликовали образ с помощью команды docker push.

time docker push hiashish/imagebuilder
Using default tag: latest
The push refers to repository [docker.io/hiashish/imagebuilder]
baebe8d2c101: Pushed
ebab439b6c1b: Mounted from hiashish/helloworld
c44cd007351c: Mounted from hiashish/helloworld
02f0a7f763a3: Mounted from hiashish/helloworld
da654bc8bc80: Mounted from hiashish/helloworld
4ef81dc52d99: Mounted from hiashish/helloworld
909e93c71745: Mounted from hiashish/helloworld
7f03bfe4d6dc: Mounted from hiashish/helloworld
latest: digest: sha256:166c00c1ba605a360e4555405f57d2f5b93ec7abc979ecb4a43de7c9366639d0 size: 2006
docker push hiashish/imagebuilder 0.26s user 0.38s system 1% cpu 32.655 total
Размер образа

REPOSITORY TAG IMAGE ID CREATED SIZE
hiashish/dockersimple latest 3cdf4936ec77 20 hours ago 664MB
Чтобы проверить использование памяти, воспользуемся командой docker stats. Ниже приведен результат после запуска контейнера Docker для нашего приложения Spring Boot Hello-Wolrd.

CONTAINER ID NAME CPU % MEM USAGE / LIMIT
f8f34e0ffaa4 magical_lamport 0.89% 138.7MiB / 1.944GiB

Профессиональный способ создания образа с помощью Docker Multistage Build​

В предыдущем разделе наш процесс был немного утомительным, а размер выходного образа был большим. Мы можем улучшить этот процесс и создавать тонкие образы с помощью многоступенчатых сборок Docker. Еще одна проблема с предыдущим методом заключалась в том, что нужно сначала упаковать наше приложение с помощью команды mvn package до создания фактического образа. В этом разделе мы постараемся избежать этого.

Вот Dockerfile для нашего приложения Spring Boot Hello-World, которое использует многоступенчатую сборку. Позвольте мне объяснить Dockerfile. Я использовал образ maven-openjdk11 для сборки и создания jar-файла для моего проекта на первом этапе, но это не будет окончательный результат. На втором этапе я скопировал jar, который мы создали на предыдущем этапе сборки, и создал новый окончательный образ на основе значительно меньшего базового образа Java 11 JRE. Окончательный образ Docker не включает JDK или maven, а только JRE. Если вы заметили, время сборки здесь больше, потому что все необходимые зависимости должны быть загружены на первом этапе сборки. Думаю, это единственный недостаток такого подхода.

# Pro way of writing Dockerfile
FROM maven:3-openjdk-11 as build
RUN mkdir /app
COPY . /app
WORKDIR /app
RUN mvn clean package -DskipTests

FROM openjdk:11-jre-slim
RUN mkdir /project
COPY --from=build /app/target/imagebuilder-0.0.1-SNAPSHOT.jar /project
WORKDIR /project
ENTRYPOINT ["java","-jar","imagebuilder-0.0.1-SNAPSHOT.jar"]
Ниже приведены результаты выполнения этого файла Dockerfile с помощью команды docker build.

time docker build -t hiashish/multistagebuild:latest .
[+] Building 213.4s (17/17) FINISHED
=> [internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 503B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/openjdk:11-jre-slim 2.7s
=> [internal] load metadata for docker.io/library/maven:3-openjdk-11 3.0s
=> [auth] library/maven:pull token for registry-1.docker.io 0.0s
=> [auth] library/openjdk:pull token for registry-1.docker.io 0.0s
=> [build 1/5] FROM docker.io/library/maven:3-openjdk-11@sha256:7376ab3120aeb575cd6cd336a423c6c8f62f26d9fb1ddc2659a299c3433a2fa2 35.8s
=> => resolve docker.io/library/maven:3-openjdk-11@sha256:7376ab3120aeb575cd6cd336a423c6c8f62f26d9fb1ddc2659a299c3433a2fa2 0.0s
=> => sha256:1539a43fb9fbebf79ac9e96adfae8dada3b6caa0ab0e6586e837dae4b8eabc3c 355B / 355B 0.0s
=> => sha256:7376ab3120aeb575cd6cd336a423c6c8f62f26d9fb1ddc2659a299c3433a2fa2 549B / 549B 0.0s
=> => sha256:12b1cd95e6bf321d358f4a8484584acc1354728c4c6f82f0568a2a3fdfbb0f34 2.42kB / 2.42kB 0.0s
=> => sha256:feab2c490a3cea21cc051ff29c33cc9857418edfa1be9966124b18abe1d5ae16 10.00MB / 10.00MB 0.0s
=> => sha256:f15a0f46f8c38f4ca7daecf160ba9cdb3ddeafda769e2741e179851cfaa14eec 51.83MB / 51.83MB 0.0s
=> => sha256:26cb1dfcbebb21160622ee663cb64f65e625a9f3d98c55b9555e21e2cb15e400 5.29MB / 5.29MB 0.0s
=> => sha256:f22708c7c9c1856c05e56ae8f5812a24b7304cb80ebfc9a34dd4f4cbaf3dd6d2 202.80MB / 202.80MB 0.0s
=> => sha256:8749bb0dc5132a22fbd2b2b23d4179568f3a758dd0c53dc2b87048656d19b8d7 852B / 852B 0.0s
=> => sha256:8de5407a7bebd1d5f75cc154bf8c74535dde31e10b8baa60347d04a7b3f338c5 8.92kB / 8.92kB 0.0s
=> => sha256:0ecb575e629cd60aa802266a3bc6847dcf4073aa2a6d7d43f717dd61e7b90e0b 50.40MB / 50.40MB 0.0s
=> => sha256:7467d1831b6947c294d92ee957902c3cd448b17c5ac2103ca5e79d15afb317c3 7.83MB / 7.83MB 0.0s
=> => sha256:242c5446d23fd9e18b2a08efc86e19bcf271b95038f7a2a58f4819fb362dee36 208B / 208B 0.0s
=> => sha256:b6129cf0dd9130eddbcd914da7d0808d038216f3ea3e599da8e3d3b80d7ce427 9.58MB / 9.58MB 0.0s
=> => extracting sha256:0ecb575e629cd60aa802266a3bc6847dcf4073aa2a6d7d43f717dd61e7b90e0b 10.0s
=> => extracting sha256:7467d1831b6947c294d92ee957902c3cd448b17c5ac2103ca5e79d15afb317c3 1.0s
=> => extracting sha256:feab2c490a3cea21cc051ff29c33cc9857418edfa1be9966124b18abe1d5ae16 1.0s
=> => extracting sha256:f15a0f46f8c38f4ca7daecf160ba9cdb3ddeafda769e2741e179851cfaa14eec 7.7s
=> => extracting sha256:26cb1dfcbebb21160622ee663cb64f65e625a9f3d98c55b9555e21e2cb15e400 0.5s
=> => extracting sha256:242c5446d23fd9e18b2a08efc86e19bcf271b95038f7a2a58f4819fb362dee36 0.0s
=> => extracting sha256:f22708c7c9c1856c05e56ae8f5812a24b7304cb80ebfc9a34dd4f4cbaf3dd6d2 11.4s
=> => extracting sha256:b6129cf0dd9130eddbcd914da7d0808d038216f3ea3e599da8e3d3b80d7ce427 0.5s
=> => extracting sha256:8749bb0dc5132a22fbd2b2b23d4179568f3a758dd0c53dc2b87048656d19b8d7 0.0s
=> => extracting sha256:1539a43fb9fbebf79ac9e96adfae8dada3b6caa0ab0e6586e837dae4b8eabc3c 0.0s
=> [stage-1 1/4] FROM docker.io/library/openjdk:11-jre-slim@sha256:34744515bdde22d92a627555165e72b4e3e7aca2094cc025cb0f4000058a3c1c 16.0s
=> => resolve docker.io/library/openjdk:11-jre-slim@sha256:34744515bdde22d92a627555165e72b4e3e7aca2094cc025cb0f4000058a3c1c 0.0s
=> => sha256:33964aae81418d20eee9035f0a64d71bded866a765423048f456d6835b1e2a3d 7.58kB / 7.58kB 0.0s
=> => sha256:45b42c59be334ecda0daaa139b2f7d310e45c564c5f12263b1b8e68ec9e810ed 27.10MB / 27.10MB 0.0s
=> => sha256:a91c0c19c84860aaa974864243509770a5b009f3a88b4a228010a9ade71ac968 3.27MB / 3.27MB 0.0s
=> => sha256:dbe61a45ef1807a5db8d1f61021955a6ee0c370a88bb9c568a2ae31417afbda6 209B / 209B 0.0s
=> => sha256:6eeb16e47bf12a88503349a2056e84ea8b6e1329850c1ad859e2d01401f45a1f 47.04MB / 47.04MB 0.0s
=> => sha256:34744515bdde22d92a627555165e72b4e3e7aca2094cc025cb0f4000058a3c1c 549B / 549B 0.0s
=> => sha256:1317197ccd52971d38949536ba5a27ad61de3bf78ef792033622a4694eb0c373 1.16kB / 1.16kB 0.0s
=> => extracting sha256:45b42c59be334ecda0daaa139b2f7d310e45c564c5f12263b1b8e68ec9e810ed 6.8s
=> => extracting sha256:a91c0c19c84860aaa974864243509770a5b009f3a88b4a228010a9ade71ac968 0.8s
=> => extracting sha256:dbe61a45ef1807a5db8d1f61021955a6ee0c370a88bb9c568a2ae31417afbda6 0.0s
=> => extracting sha256:6eeb16e47bf12a88503349a2056e84ea8b6e1329850c1ad859e2d01401f45a1f 5.9s
=> [internal] load build context 2.4s
=> => transferring context: 17.20MB 2.3s
=> [stage-1 2/4] RUN mkdir /project 1.2s
=> [build 2/5] RUN mkdir /app 0.6s
=> [build 3/5] COPY . /app 0.2s
=> [build 4/5] WORKDIR /app 0.1s
=> [build 5/5] RUN mvn clean package -DskipTests 172.8s
=> [stage-1 3/4] COPY --from=build /app/target/imagebuilder-0.0.1-SNAPSHOT.jar /project 0.1s
=> [stage-1 4/4] WORKDIR /project 0.1s
=> exporting to image 0.2s
=> => exporting layers 0.2s
=> => writing image sha256:079ca9681f614fe441730f4baaf3494841fd672fa814cfd7baeb52097e7c83d5 0.0s
=> => naming to docker.io/hiashish/multistagebuild:latest
docker build -t hiashish/multistagebuild:latest . 4.26s user 3.04s system 3% cpu 3:33.89 total
Затем мы опубликовали образ с помощью команды docker push.

time docker push hiashish/multistagebuild
Using default tag: latest
The push refers to repository [docker.io/hiashish/multistagebuild]
5f70bf18a086: Mounted from paketobuildpacks/builder
df8f2c4d6677: Pushed
657f5a5c28df: Pushed
027810cd859b: Mounted from library/openjdk
513adf10febc: Mounted from library/openjdk
08664b16f94c: Mounted from library/openjdk
9eb82f04c782: Mounted from library/openjdk
latest: digest: sha256:91dca4aebfda20cd93b7fb29d946ab694bdcc2b9351a44de6d2a16822b689f18 size: 1784
docker push hiashish/multistagebuild 0.20s user 0.28s system 1% cpu 30.667 total
Размер образа при многоступенчатой сборке Docker.

REPOSITORY TAG IMAGE ID CREATED SIZE
hiashish/multistagebuild latest 079ca9681f61 13 seconds ago 237MB
Ниже показано использование памяти после запуска контейнера Docker нашего приложения Spring Boot Hello-World.

CONTAINER ID NAME CPU % MEM USAGE / LIMIT
7b64ea0aabf2 keen_bohr 0.80% 139.8MiB / 1.944GiB

Сравнение данных​

8fbadb7dcd263698a2db0a6a6e23ea4b.png
9b3529e7092ebcba6df0ba414e29e9c5.png
844d7a603027fc29326a15131332d2fd.png

В этом разделе Dive будет использоваться для проверки слоев образов, созданных с использованием методов контейнеризации, которые мы рассмотрели в этой статье. Dive достаточно умен, чтобы понять, тратите ли вы какое-либо пространство, и если да, то вы можете найти способы уменьшить размер образа Docker / OCI.

  1. Docker простой
    3c1b91f5e751ccea60923f146b0e8725.png
  2. Docker многоступенчатый
    e1e4420b476251f2a624353d6b8c1b6d.png
  3. Jib
    363ea2e19ff58425ced2fc3929069861.png
  4. Buildpack
    62fd9fd2536a77659c885fb1c4365c4a.png
Мы оценили предложения на основе того, насколько они соответствуют каждому из критериев, указанных в следующем разделе.

Критерий первый: простота использования​

Как Jib, так и Spring Boot Buildpack методы просты. С ними легко начать, просто добавив плагин. Они встроены в экосистему Spring Boot. Они действительно предоставляют некоторые разумные настройки по умолчанию для работы, и вам решать, какой уровень настройки вы ожидаете. Однако эти два параметра могут не поддерживать все функции, которые выполняет Dockerfile, например, использование чего-то вроде RUN-эквивалента инструкции Dockerfile с Jib или Buildpack. Docker требует отдельной установки, и вам необходимо ознакомиться с командами, которые он поддерживает. Как мы видели ранее, мы также должны следовать некоторым рекомендациям Docker, чтобы создать более тонкий образ для нашего приложения. Однако Jib предоставляет (по умолчанию) базовые образы без дистрибутива, которые легче и безопаснее, поскольку они не

Критерий второй: время создания образа​

Как вы можете видеть в таблице сравнения данных, Jib - наиболее эффективный вариант при сравнении времени создания образов. Когда мы использовали Jib без демона Docker, он создал образ и поместил его в реестр удаленных контейнеров всего за ~ 33 секунды при первом запуске сборки, а последующие сборки были еще быстрее. Ни один из других вариантов, которые мы исследовали, не подходит.

Критерий третий: использование ресурсов​

Поддержка Spring Boot Jib обеспечивает некоторые разумные настройки по умолчанию, а его базовый образ без дистрибутива намного меньше, чем другие варианты, что приводит к окончательному меньшему образу. Docker не такой уж тонкий по сравнению с Jib, даже при многоступенчатой сборке с тонким базовым образом. Образ, созданный с помощью поддержки Buildpack для Spring Boot, велик по сравнению с многоступенчатой сборкой Jib и Docker. Наконец, Jib потребляет меньше всего памяти.

Обзор критериев: слои образа​

В приведенном выше разделе сравнения слоев образов вы можете увидеть, что простые и многоступенчатые образы сборки Docker объединяют зависимости, ресурсы и классы в один неэффективный слой. Кроме того, есть пустая трата времени, которую можно улучшить. С помощью Jib мы расширили структуру каталогов для классов, ресурсов и зависимостей, и их размер минимален. Преимущество этого подхода в том, что при любых изменениях кода перестраиваются только ваши изменения, а не все приложение. Это означает, что Jib толкает только слой, который изменяется, а остальные слои остаются прежними. С Buildpack у нас более или менее такое же распределение слоев по сравнению с Jib, но есть и некоторая потеря места, так как оценка эффективности образа составляет 99%. Еще одна проблема с Buildpack заключается в том, что он объединяет ресурсы вместе, что делает разбиение на уровни неэффективным.

Заключение​

В этой статье мы рассмотрели различные методы создания образов контейнеров для разработчиков Java, включая Jib, Buildpacks и Docker. Мы сравнили метод создания образа по нескольким параметрам, таким как время создания образа (сборка и отправка), использование ресурсов (дисковое пространство и память) и насколько легко начать работу с каждым инструментом. С данными, которые мы представили, вы можете видеть, что Jib является эффективным методом создания образов контейнеров для вашего приложения. Buildpacks - хороший вариант. Однако иногда они медленнее, чем Jib, и не позволяют изменять родительский образ. Наконец, если вы ищете лучший контроль или настройку, тогда Docker может быть вашим лучшим вариантом. Тем не менее, Jib настолько изменился с момента своего создания, что вы можете делать практически все, что можете, с Docker, используя его структуру расширений..



Источник статьи: https://habr.com/ru/post/552494/
 
Сверху