Подтвердить что ты не робот

Как построить Docker-контейнер для Java-приложения

Что я хочу сделать, это создать образ докеров для моего Java-приложения, но для большинства скомпилированных языков должны быть верны следующие соображения.

Проблема

На моем сервере сборки я хочу создать образ докеры для моего приложения в качестве поставляемого. Для этого мне нужно скомпилировать приложение с помощью некоторого инструмента сборки (обычно Gradle, Maven или Ant), а затем добавить созданный файл JAR в образ докеры. Поскольку я хочу, чтобы изображение докера просто выполняло JAR файл, я, конечно же, начну с базового образа с уже установленной Java.

Существует три способа сделать это:

Пусть инструмент сборки управляет процессом

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

Но мой Dockerfile больше не является автономным. Это зависит от шагов, которые могут произойти за пределами Docker. В моем Dockerfile у меня будет оператор COPY или ADD, который должен скопировать JAR файл на изображение. Это утверждение не будет выполнено, если баннер не будет создан заранее. Так что просто выполнение Dockerfile может не работать. Это становится проблемой, если вы хотите интегрироваться с сервисами, которые только что создаются с использованием текущего файла Docker, например, функции автоматической сборки на DockerHub.

пусть Docker управляет сборкой

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

Основная проблема с этим подходом заключается в том, что нельзя добавлять команды Dockerfile, которые должны выполняться за пределами создаваемого образа докера. Это означает, что я должен добавить свой исходный код и свои инструменты сборки к образцу докеров и создать свой JAR файл внутри изображения. Это приведет к тому, что мое изображение будет больше, чем должно быть из-за всех добавленных файлов, которые будут лишними во время выполнения. Это также добавит дополнительные слои к моему изображению.

Edit:

Как заметил @adrian-mouat, если бы я добавил источники, создав приложение и удалив исходные файлы в одном заявлении RUN, я мог бы избежать добавления ненужных файлов и слоев в образ Docker. Это означало бы создание какой-то безумной цепной команды.

две отдельные сборки

В этом случае мы разделим нашу сборку на две части: сначала мы создаем файл JAR с помощью нашего инструмента сборки и загружаем его в репозиторий (репозиторий Maven или Ivy). Затем мы запускаем отдельную сборку Docker, которая просто добавляет JAR файл из репозитория.

Заключение

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

Но это не позволит мне интегрироваться с DockerHub.

Вопрос

Есть ли другой способ, который мне не хватает?

4b9b3361

Ответ 1

Концентратор реестра Docker содержит образ Maven, который можно использовать для создания контейнеров Java.

При таком подходе на машине сборки не требуется предварительно устанавливать Java или Maven, Docker контролирует весь процесс сборки.

Пример

├── Dockerfile
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── org
    │   │       └── demo
    │   │           └── App.java
    │   └── resources
    │       └── log4j.properties
    └── test
        └── java
            └── org
                └── demo
                    └── AppTest.java

Изображение построено следующим образом:

docker build -t my-maven .

И выполните следующее:

$ docker run -it --rm my-maven
0    [main] INFO  org.demo.App  - hello world

Dockerfile

FROM maven:3.3-jdk-8-onbuild
CMD ["java","-jar","/usr/src/app/target/demo-1.0-SNAPSHOT-jar-with-dependencies.jar"]

Обновление

Если вы хотите оптимизировать изображение, чтобы исключить источник, вы можете создать Dockerfile, который включает только встроенный файл jar:

FROM java:8
ADD target/demo-1.0-SNAPSHOT-jar-with-dependencies.jar /opt/demo/demo-1.0-SNAPSHOT-jar-with-dependencies.jar
CMD ["java","-jar","/opt/demo/demo-1.0-SNAPSHOT-jar-with-dependencies.jar"]

И создайте изображение в два этапа:

docker run -it --rm -w /opt/maven \
   -v $PWD:/opt/maven \
   -v $HOME/.m2:/root/.m2 \
   maven:3.3-jdk-8 \
   mvn clean install

docker build -t my-app .

__

Обновление (2017-07-27)

Docker теперь имеет возможность многоэтапной сборки. Это позволяет Docker создавать образ, содержащий инструменты сборки, но только зависимости времени выполнения.

В следующем примере демонстрируется эта концепция, обратите внимание, как jar копируется из целевого каталога первого этапа сборки

FROM maven:3.3-jdk-8-onbuild 

FROM java:8
COPY --from=0 /usr/src/app/target/demo-1.0-SNAPSHOT.jar /opt/demo.jar
CMD ["java","-jar","/opt/demo.jar"]

Ответ 2

Структура java-приложения

Demo
└── src
|    ├── main
|    │   ├── java
|    │   │   └── org
|    │   │       └── demo
|    │   │           └── App.java
|    │   └── resources
|    │       └── application.properties
|    └── test
|         └── java
|               └── org
|                   └── demo
|                         └── App.java  
├──── Dockerfile
├──── pom.xml

Содержимое файла Docker

FROM java:8
EXPOSE 8080
ADD /target/demo.jar demo.jar
ENTRYPOINT ["java","-jar","demo.jar"]

Команды для создания и запуска образа

  • Перейдите в каталог проекта. Скажем, D:/Demo
$ cd D/demo
$ mvn clean install
$ docker build demo .
$ docker run -p 8080:8080 -t demo

Убедитесь, что контейнер запущен или нет

$ docker ps

Выход будет

CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                    NAMES
55c11a464f5a        demo1               "java -jar demo.jar"   21 seconds ago      Up About a minute   0.0.0.0:8080->8080/tcp   cranky_mayer

Ответ 3

Самый простой способ - позволить инструменту сборки контролировать процесс. В противном случае вам потребуется сохранить файл сборки инструмента сборки (например, pom.xml для Maven или build.gradle для Gradle), а также Dockerfile.

Простой способ создать Docker-контейнер для вашего Java-приложения - это использовать Jib, который доступен в виде плагинов Maven и Gradle.

Например, если вы используете Maven и хотите собрать свой контейнер для работающего демона Docker, вы можете просто запустить эту команду:

mvn compile com.google.cloud.tools:jib-maven-plugin:0.9.2:dockerBuild

Кроме того, можно построить непосредственно в реестр Докер с стакселя без необходимости установки docker, запустите демон Docker (который требует привилегий суперпользователя), или написать Dockerfile. Это также быстрее и воспроизводит изображения.

Подробнее о Jib можно узнать в репозитории Github: https://github.com/GoogleContainerTools/jib

Ответ 4

Мы использовали Spotify Docker Maven Plugin некоторое время. Плагин позволяет вам привязать Docker к его фазе жизненного цикла Maven.

Пример: Запустите сборку Docker после упаковки (фаза: пакет) вашего приложения, настроив плагин, чтобы добавить ваше встроенное приложение в качестве ресурса в контекст сборки Docker. На этапе развертывания нажмите кнопку Docker push to push to Docker в реестре. Это может работать рядом с обычным плагином развертывания, который публикует артефакт в хранилище, например Nexus.

Позже мы разделили сборку на два отдельных задания на сервере CI. Поскольку Docker - это всего лишь один способ запуска вашего приложения (иногда нам нужно, чтобы выпущенное приложение использовалось в разных средах не только Docker), сборка Maven не должна полагаться на Docker.

Итак, первое задание освобождает приложение в Nexus (через развертывание Maven). Второе задание (которое может быть нисходящей зависимостью первого задания) загружает последний артефакт выпуска, выполняет сборку Docker и помещает изображение в реестр. Для загрузки последней версии мы используем Версии Maven Plugin (версии: use-latest-релизы), а также Maven Dependency Plugin (зависимость: get и зависимость: копирование).

Второе задание также может быть запущено для конкретной версии приложения для (re) создания образа Docker для более старой версии. Кроме того, вы можете использовать конвейер сборки (на Jenkins), который выполняет оба задания и передает версию выпуска или артефакт выпуска в сборку Docker.

Ответ 5

Несколько вещей:

  • Если вы удаляете файлы в той же инструкции, которую вы добавляете, они не будут использовать пространство на изображении. Если вы посмотрите на некоторые файлы Dockerfiles для официальных изображений, вы увидите, что они загружают источник, строят его и удаляют все на одном и том же этапе (например, https://github.com/docker-library/python/blob/0fa3202789648132971160f686f5a37595108f44/3.5/slim/Dockerfile). Это означает, что вам нужно сделать какую-то раздражающую гимнастику, но это вполне выполнимо.

  • Я не вижу проблемы с двумя отдельными Dockerfiles. Самое приятное в том, что вы можете использовать JRE, а не JDK, чтобы разместить свою банку.

Ответ 6

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

  • добавить jar в изображение.
  • установить heapsize для java
  • выполнить команду jar через точку входа

образец файла dockerfile

FROM base
ADD sample.jar renamed.jar
ENV HEAP_SIZE 256m
ENTRYPOINT exec java -Xms$HEAP_SIZE -Xmx$HEAP_SIZE -jar renamed.jar

пример развертывания пакета на tomcat

FROM tomcat7
ADD sample.war ${CATALINA_HOME}/webapps/ROOT.war
CMD ${CATALINA_HOME}/bin/catalina.sh run

Создание докеров в качестве изображения

cp tomcat.dockerfile /workingdir/Dockerfile
docker build -t name /workingdir/Dockerfile .

Список изображений

docker images

Использовать изображение для создания контейнера

docker run --name cont_name --extra-vars var1=val1 var2=val2 imagename

Ответ 7

Здесь Я описываю, как я это делаю в своей среде разработки.

  • Создайте войну/банку локально с помощью Maven
  • Скопируйте его в локальную папку Docker
  • Запустите Плагин Intellij Docker, который создает изображение докера, содержащее войну/банку, запускает сервер приложений и разворачивает его на удаленном докере сервер

Надеюсь, что это поможет.

Ответ 8

Контейнерное Java-приложение с использованием инструмента Jib без написания dockerfile

Jib - это инструмент Java с открытым исходным кодом, поддерживаемый Google для создания образов Docker приложений Java. Это упрощает контейнеризацию, так как с ней нам не нужно писать dockerfile. И на самом деле нам даже не нужно устанавливать докер, чтобы самим создавать и публиковать образы докеров.

Google публикует Jib как плагин Maven и Gradle. https://github.com/GoogleContainerTools/jib

Контейнерное Java-приложение с использованием проекта Maven

https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin#quickstart

Контейнерное Java-приложение с использованием проекта Gradle

https://github.com/GoogleContainerTools/jib/tree/master/jib-gradle-plugin#quickstart