Как стать автором
Обновить

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

Время на прочтение22 мин
Количество просмотров11K
Автор оригинала: Ashish Choudhary

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

Вступление

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

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

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

  1. Docker простой

  1. Docker многоступенчатый

  1. Jib

  1. Buildpack

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

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

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

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

Однако Jib предоставляет (по умолчанию) базовые образы без дистрибутивов, которые легче и безопаснее, поскольку не содержат менеджеров пакетов, которые поставляются с типичными дистрибутивами Linux.

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

Как вы можете видеть в таблице сравнения данных, 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, используя его структуру расширений..

Теги:
Хабы:
+1
Комментарии2

Публикации

Изменить настройки темы

Истории

Работа

Java разработчик
352 вакансии

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн