Альтернативная версия упаковки Java приложения в Docker

в 14:20, , рубрики: java, java docker maven, метки:

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

Java приложения, как мы их видим

Далее последует альтернативный способ сборки Java-приложений в Docker контейнер используя Maven.

Для сборки нам понадобится Java проект, Maven и немного терпения, чтоб все это завести.

Дисклеймер

Я предполагаю, что читатель уже знаком Java, Maven и Docker. Представляет, что написано в Docker-файле, зачем все ему это надо и вообще ниндзя

В это раз, мы будем использовать Maven-плагин от fabric8io.

Предположим, что у нас микро-сервис, который упаковывается в jar-файл, содержащий main метод, который и надо запустить для старта приложения. Добавляем плагин в build секцию:

<plugin>
    <groupId>io.fabric8</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>0.16.4</version>
    <executions>
        <execution>
            <id>Build docker container</id>
            <phase>package</phase>
            <goals>
                <goal>build</goal>
            </goals>
        </execution>
        <execution>
            <id>Push docker container</id>
            <phase>deploy</phase>
            <goals>
                <goal>push</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <images>
            <image>
                <name>${project.artifactId}</name>
                <registry>registry.io</registry>
                <build>
                    <from>java:8</from>
                    <tags>
                        <tag>${project.version}</tag>
                    </tags>
                    <ports>
                        <port>8080</port>
                    </ports>
                    <cmd>
                        <shell>java -cp 'jars/*' com.myapp.MainClass '/config.file'</shell>
                    </cmd>
                    <assembly>
                        <basedir>/</basedir>
                        <inline>
                            <dependencySet>
                                <outputDirectory>jars</outputDirectory>
                            </dependencySet>
                            <files>
                                <file>
                                    <source>${project.build.directory}/${project.build.finalName}.jar</source>
                                    <outputDirectory>jars</outputDirectory>
                                </file>
                                <file>
                                    <source>${project.basedir}/src/main/config/config.yml</source>
                                    <outputDirectory>/</outputDirectory>
                                </file>
                            </files>
                        </inline>
                    </assembly>
                </build>
            </image>
        </images>
    </configuration>
</plugin>

И, в общем то, все. Разберем поподробнее, что у нас там написано.

В начале идёт типичное определение плагина с версией. Далее идёт определение в какие фазы луны сборки мы хотим собирать и пушить наш контейнер. В моем случае сборка контейнера (build) будет происходить во время упаковки проекта (phase: package).

Пуш (push) контейнера в репозиторий будет происходить во время фазы деплой (deploy).

<executions>
    <execution>
        <id>Build docker container</id>
        <phase>package</phase>
        <goals>
            <goal>build</goal>
        </goals>
    </execution>
    <execution>
        <id>Push docker container</id>
        <phase>deploy</phase>
        <goals>
            <goal>push</goal>
        </goals>
    </execution>
</executions>

Внимание Maven!

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

Если это ваш случай, то секция исполнения схлопывается до следующей:

<executions>
    <execution>
        <id>Build & Push docker container</id>
        <phase>deploy</phase>
        <goals>
            <goal>build</goal>
            <goal>push</goal>
        </goals>
    </execution>
</executions>

Также можно перенести сбоку на фазу install. Может кто знает, как заставить Maven исполнять плагины в нужном порядке?

Определяем имя образа и репозиторий:

<name>${project.artifactId}</name>
<registry>registry.io</registry>

Если репозиторий не указан, то будет использоваться репозиторий Docker-а. Документация для дальнейшего чтения.

Описание сборки образа осуществляется в секции <build>. По сути это отражение Docker файла в Maven.

from — базовый образ
tags — теги с которыми будет собран образ
ports — открытые порты
cmd — строка запуска, так же можно указать entryPoint, о все доступных опциях можно почитать в документации.

В моем примере:

<shell>java -cp 'jars/*' com.myapp.MainClass '/config.file'</shell>

Это типичная строка запуска Java приложения, завернутая в shell форму Docker-а, в представлении Maven-а.

assembly — самая интересная часть плагина. Она определяет, что будет упаковано в образ контейнера и как. Есть несколько вариантов как можно описать упаковку, я выбрал inline, но есть и другие варианты.

В примере, я хочу взять все зависимости проекта и сложить в папку «jars»:

<dependencySet>
    <outputDirectory>jars</outputDirectory>
</dependencySet>

А так же, артефакт проекта, собственно наше приложение, туда же, а конфигурационный файл в корень контейнера.

<files>
    <file>
        <source>${project.build.directory}/${project.build.finalName}.jar</source>
        <outputDirectory>jars</outputDirectory>
    </file>
    <file>
        <source>${project.basedir}/src/main/config/config.file</source>
        <outputDirectory>/</outputDirectory>
    </file>
</files>

Подробнее о возможностях ассемблирования в документации, на этот раз Maven-а.

И все! В результате:

  • Вся конфигурация сборки Docker контейнера у нас сосредоточенна в файле проекта.
  • Мы можем использовать все прелести Maven-а, его переменные и плагины.
  • Сборка контейнера осуществляется прозрачно, в момент сборки проекта, результат доступен локально.
  • Версионирование контейнера идет нога в ногу с нашим проектом.
  • Мы можем продолжать использовать все тот же CI/CD инструмент, что и раньше (надо установить Docker на сервере).

Несколько слов о плагине: разработка идет активно, мейнтейнер оперативно отвечает и охотно мерджит пул-реквесты.

» Сам плагин может ещё много чего: возможности
» Пример проекта выложен на github-е

Автор: osigida

Источник

Поделиться новостью

* - обязательные к заполнению поля