我已经按照这些教程为Spring Boot应用程序构建Docker映像,该应用程序使用Maven作为构建工具。 我在Windows 10计算机上使用boot2docker VM,将我的项目从Bitbucker存储库克隆到VM。
https://spring.io/guides/gs/spring-boot-docker/
https://www.callicoder.com/spring-boot-docker-example/
我了解其中的说明,但是,我无法构建正确的Docker映像。这是我尝试过的事情。
使用适用于Dockerfile的Spotify maven插件。尝试运行./mvnw来构建JAR和Docker映像。但是,我没有在boot2docker中安装Java。因此Maven包装器./mvnw无法运行。
我试图通过Dockerfile构建JAR,该文件基于openjdk:8-jdk-alpine映像。我在Dockerfile中添加了RUN ./mvnw package
指令。然后运行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,我需要在Docker引擎所在的操作系统中安装Java。但是我认为这不是一个好习惯,因为这会降低可移植性。
对于2,首先,我不知道如何在Dockerfile中成功运行./mvnw。其次,我不确定通过Dockerfile来构建Spring Boot JAR是否是一个好习惯,因为我看不到任何“ Docker for Spring Boot”教程可以告诉您这样做。
那么,解决我的情况的最佳实践是什么?我是Docker的新手。评论和答案表示赞赏!
答案 0 :(得分:1)
您可以安装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并在内部版本中运行它。
答案 1 :(得分:0)
从您的第二个示例中,我认为您误解了 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