Как создать образ Docker для приложения Spring Boot без JAR под рукой

Я следовал этим урокам, чтобы создать образ Docker для моего приложения Spring Boot, которое использует Maven в качестве инструмента для сборки. Я использую ВМ boot2docker поверх машины с Windows 10, клонируя свой проект на ВМ из моего хранилища Bitbucker.

https://spring.io/guides/gs/spring-boot-docker/

https://www.callicoder.com/spring-boot-docker-example/

Я понимаю инструкции, но мне не удалось создать правильный образ Docker. Вот что я попробовал.

  1. Используйте плагин Spotify maven для Dockerfile. Попробуйте запустить./mvnw, чтобы собрать JAR и образ Docker. Но у меня не установлена ​​Java в boot2docker. Таким образом, оболочка Maven./mvnw не может быть запущена.

  2. Я пытался собрать JAR через Dockerfile, который основан на образе openjdk:8-jdk-alpine. я добавил RUN ./mvnw package инструкция в Dockerfile. Тогда беги docker build -t <my_project> . построить образ Docker. Это терпит неудачу в инструкции RUN, требуя /bin/sh: mvnw: not found The command '/bin/sh -c mvnw package' returned a non-zero code: 127

Мой Dockerfile, расположенный в каталоге, где находится mvnw:

MAINTAINER myname

VOLUME /tmp

RUN ./mvnw package

ARG JAR_FILE=target/myproject-0.0.1-SNAPSHOT.jar

COPY ${JAR_FILE} app.jar

ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

Для 1 мне нужно установить Java в ОС, где находится механизм Docker. Но я думаю, что это не очень хорошая практика, потому что это снижает мобильность.

Во-первых, во-первых, я не знаю, как успешно запустить./mvnw в Dockerfile. Во-вторых, я не уверен, является ли хорошей практикой создание JAR-файла Spring Boot с помощью Dockerfile, поскольку я не вижу учебника "Docker for Spring Boot", в котором можно было бы это сделать.

Итак, как лучше всего решить мою ситуацию? Я новичок в Докере. Комментарии и ответы приветствуются!

3 ответа

Вы можете установить maven и запустить компиляцию прямо в сборке. Как правило, это будет многоэтапная сборка, чтобы избежать включения всего jdk в ваш отправленный образ:

FROM openjdk:8-jdk-alpine as build
RUN apk add --no-cache maven
WORKDIR /java
COPY . /java
RUN mvn package -Dmaven.test.skip=true
EXPOSE 8080
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/java/target/myproject-0.0.1-SNAPSHOT.jar"]

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

Судя по вашему второму примеру, я думаю, вы неправильно понимаете, как Docker создает образы. Когда Docker выполняет RUN ./mvnw package, файл mvnw должен существовать в файловой системе создаваемого образа, что означает, что у вас должна быть такая инструкция, как COPY mvnw . на предыдущем шаге - это скопирует файл из вашей локальной файловой системы в образ.

Вам, вероятно, потребуется скопировать всю структуру проекта внутри изображения перед вызовом ./mvnw, как следует из ответа @BMitch.

Кроме того, как сказал @BMitch, для создания образа небольшого размера обычно рекомендуется использовать многоступенчатую сборку, где на первом этапе устанавливаются все зависимости, но в конечном образе есть только ваш JAR.

Вы можете попробовать что-то вроде ниже:

      # First stage: build fat JAR

# Select base image.
# (The "AS builder" gives a name to the stage that we will need later)
# (I think it's better to use a slim image with Maven already installed instead
#  than ./mvnw. Otherwise you could need to give execution rights to your file
#  with instructions like "RUN chmod +x mvnw".)
FROM maven:3.6.3-openjdk-8-slim AS builder

# Set your preferred working directory
# (This tells the image what the "current" directory is for the rest of the build)
WORKDIR /opt/app

# Copy everything from you current local directory into the working directory of the image
COPY . .

# Compile, test and package
# (-e gives more information in case of errors)
# (I prefer to also run unit tests at this point. This may not be possible if your tests
#  depend on other technologies that you don't whish to install at this point.)
RUN mvn -e clean verify

###

# Second stage: final image containing only WAR files

# The base image for the final result can be as small as Alpine with a JRE
FROM openjdk:8-jre-alpine

# Once again, the current directory as seen by your image
WORKDIR /opt/app

# Get artifacts from the previous stage and copy them to the new image.
# (If you are confident the only JAR in "target/" is your package, you could NOT
#  use the full name of the JAR and instead something like "*.jar", to avoid updating
#  the Dockerfile when the version of your project changes.)
COPY --from=builder /opt/app/target/*.jar ./

# Expose whichever port you use in the Spring application
EXPOSE 8080

# Define the application to run when the Docker container is created.
# Either ENTRYPOINT or CMD.
# (Optionally, you could define a file "entrypoint.sh" that can have a more complex
#  startup logic.)
# (Setting "java.security.egd" when running Spring applications is good for security
#  reasons.)
ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -jar /opt/app/*.war

Мое решение основано на Gradle. Я использую GradleWrapper.

Итак, команда ниже создаст проект и сгенерирует исполняемый файл jar Springboot в папке build/libs.

      ./gradlew clean build

И ниже приведен код Dockerfile.

      FROM bellsoft/liberica-openjdk-alpine:17
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

В основном это начинается сjava17образ, копирует jar из каталога сборки в app.jar, а затем регистрируетENTRYPOINTчтобы запустить командуjava -jar /app.jar

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

      jar {
    enabled = false
}
Другие вопросы по тегам