Существует множество руководств по «Docker для Java-разработчиков», но большинство из них не заботятся о небольших и эффективных образах Docker.
Я объединил много ресурсов о том, как создать простой и быстрый образ Docker, содержащий любое приложение, похожее на Spring Boot.
Мои цели:
- Создайте отдельный и портативный Dockerfile (как можно более общий).
- Заставьте Maven строить внутри Docker (нет необходимости иметь Maven локально).
- Не загружайте никакие зависимости Maven повторно, если в pom.xml нет изменений (перестраивайте изображение как можно быстрее).
- Окончательный образ Docker должен содержать только само приложение (без исходных кодов, без зависимостей Maven, требуемых сборкой Maven и т. Д.)
- Окончательное изображение должно быть как можно меньше (полный JDK не требуется).
- Приложение внутри Docker должно оставаться максимально настраиваемым (со всеми параметрами конфигурации Spring Boot).
- Возможность включить отладку (по запросу).
- Возможность просмотра файлов журнала.
Окончательное изображение предназначено для разработки, но оно не содержит никаких производственных деталей и полностью настраивается.
Чтобы увидеть рабочий пример, посмотрите
мой проект GitHub .
Чтобы выполнить одно требование переносимого Dockerfile, мне нужно использовать многоэтапные сборки Docker .
Он будет состоять из двух основных частей (этапов):
- Строительная часть.
- Часть времени выполнения.
Строительная часть Dockerfile
|
Я начал с официального имиджа Maven , так что вы можете изменить это, как пожелаете. Самая интересная часть это:
RUN mvn -B dependency:resolve dependency:resolve-plugins
Он загружает все зависимости, требуемые вашим приложением или плагинами, вызываемыми в процессе сборки. Тогда все зависимости являются частью одного слоя. Этот слой не изменяется до тех пор, пока в файле pom.xml не будут найдены какие-либо изменения.
Таким образом, восстановление происходит очень быстро и не включает загрузку всех зависимостей снова и снова.
Второй вариант, как загрузить необходимые зависимости, приходит с официального сайта Docker Maven (когда у вас есть проблемы с предыдущим вариантом):
RUN mvn -B -e -C -T 1C org.apache.maven.plugins:maven-dependency-plugin:3.0.2:go-offline
Как настроить параметры Maven
Есть много ситуаций, когда вам нужно изменить настройки Maven по умолчанию для вашей индивидуальной сборки. Для этого вам необходимо скопировать файл settings.xml в изображение, прежде чем предоставить определение образа компоновщика, например:
FROM maven:3-jdk-11 as builder
#Copy Custom Maven settings
COPY settings.xml /root/.m2/
Часть времени выполнения Dockerfile
FROM openjdk:11-slim as runtime
EXPOSE 8080
#Set app home folder
ENV APP_HOME /app
#Possibility to set JVM options (https://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html)
ENV JAVA_OPTS=""
#Create base app folder
RUN mkdir $APP_HOME
#Create folder to save configuration files
RUN mkdir $APP_HOME/config
#Create folder with application logs
RUN mkdir $APP_HOME/log
VOLUME $APP_HOME/log
VOLUME $APP_HOME/config
WORKDIR $APP_HOME
#Copy executable jar file from the builder image
COPY --from=builder /build/target/*.jar app.jar
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar app.jar" ]
#Second option using shell form:
#ENTRYPOINT exec java $JAVA_OPTS -jar app.jar $0 $@
Часть времени выполнения начинается с некоторых необходимых шагов, таких как предоставление портов, настройка окружения и создание некоторых полезных папок. Самая интересная часть связана с копированием ранее созданного файла JAR в наш новый образ:
#Copy executable jar file from the builder image
COPY --from=builder /build/target/*.jar app.jar
Я копирую из образа строителя, вижу парам –from
. Для получения дополнительной информации о копировании файлов из других изображений см. Страницу документации Docker.
Что касается приложения Spring Boot, созданный файл JAR является исполняемым, поэтому можно запустить наше приложение с помощью одной команды:
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar app.jar" ]
Чтобы сократить время запуска Tomcat, необходимо указать системное свойство /dev/urandom
.
Существуют и другие варианты запуска приложения Spring Boot в Docker. Для получения дополнительной информации посетите официальное руководство Spring .
Как за один шаг собрать и запустить Spring Boot Application в Docker
docker build -t <image_tag> . && docker run -p 8080:8080 <image_tag>
Приведенная выше команда создаст ваше приложение с Maven и запустит его без каких-либо задержек. Это самый простой способ без каких-либо настроек. Файл может содержать некоторые конкретные требования, поэтому вот пара из них.
Теперь вы можете посетить URL, чтобы получить ответ из моего примера GitHub :
http://localhost:8081/customer/10
Как отладить?
В моем примере используется Java 11, поэтому есть несколько параметров JVM для включения режима отладки:
docker build -t <image_tag> . && docker run -p 8080:8080 -p 5005:5005 --env JAVA_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 <image_tag>
Вам нужно добавить переменную окружения Docker, JAVA_OPTS
, с параметрами виртуальной машины Java и карту внутренний порт отладки на внешней стороне контейнера: -p 5005:5005
.
Для контейнеров Java 5-8 используйте этот JAVA_OPTS
параметр:
JAVA_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
Как настроить ведение журнала
Контейнер времени выполнения содержит папку под названием app /app/log
со всеми файлами журнала. Этот путь может быть легко смонтирован на вашем хосте:
docker build -t <image_tag> . && docker run -p 8080:8080 -v /opt/spring-boot/test/log:/app/log <image_tag>
Как изменить конфигурацию приложения
Файл jar содержит конфигурацию по умолчанию. Чтобы выборочно переопределить эти значения, у вас есть много вариантов . Я покажу вам некоторые из них.
Обратите внимание, что все конфигурации возможны при использовании формы exec ENTRYPOINT . При использовании формы оболочки ENTRYPOINT
вам необходимо передать все аргументы командной строки вручную:
ENTRYPOINT exec java $JAVA_OPTS -jar app.jar $0 $@
Аргументы командной строки
Spring Boot автоматически принимает все аргументы командной строки, и эти аргументы передаются в run
команду внутри Docker:
docker build -t <image_tag> . && docker run -p 8080:8080 <image_tag> --logging.level.org.springframework=debug
Свойства системы
Аналогичным образом используются обычные системные свойства:
docker build -t <image_tag> . && docker run -p 8080:8080 --env JAVA_OPTS=-Dlogging.level.org.springframework=DEBUG <image_tag>
Переменные среды
Вы можете использовать переменные среды вместо системных свойств. В большинстве операционных систем не допускаются имена ключей, разделенные точками, но вместо этого можно использовать подчеркивание (например, SPRING_CONFIG_NAME
вместо spring.config.name
). Проверьте страницу документации для получения дополнительной информации.
docker build -t <image_tag> . && docker run -p 8080:8080 --env LOGGING_LEVEL_ORG_SPRINGFRAMEWORK=DEBUG <image_tag>
Смонтируйте свой собственный файл конфигурации
Возможно, вы заметили, что есть VOLUME
команда для монтирования папки конфигурации:
docker build -t <image_tag> . && docker run -p 8080:8080 -v /opt/spring-boot/test/config:/app/config:ro <image_tag>
Таким образом, ваша локальная папка /opt/spring-boot/test/config
должна содержать файл application.properties
. Это имя файла конфигурации по умолчанию, и его можно легко изменить, установив свойство spring.config.name
.
Это все для этого поста, но ваши требования могут отличаться во многих отношениях. Я попытался решить некоторые из наиболее важных условий Java-разработчиков, используя Docker.
Как упоминалось выше, см. Пример проекта на
моем GitHub для всего кода.
Несколько интересных ссылок: