10

I have the following docker file that runs a spring boot application:

# For Java 11, try this
FROM adoptopenjdk/openjdk11:alpine-jre

#
ARG JAR_FILE=/build/libs/pokerstats-0.0.1-SNAPSHOT.jar

#
WORKDIR /opt/app

#
COPY ${JAR_FILE} app.jar

#
ENTRYPOINT ["java","-jar","app.jar"]

The issue is that currently I have to run gradle clean build on my host machine first to create the jar file on my local machine at path:

/build/libs/pokerstats-0.0.1-SNAPSHOT.jar

How can I put this gradle clean build into my docker file so that the build step is done inside the container?

edit:

I want the steps for a user to be:

  1. Clone my project from github
  2. run docker build -t pokerstats . - which will do the gradle build
  3. run docker container run -d -p 8080:8080 pokerstats

The user will clone my project from github - I then want them to be able to run the docker container without having to build the project with gradle first - I.e. I want the docker file to do the build and copy the jar into the container.

Brian Burns
  • 17,878
  • 8
  • 77
  • 67
java12399900
  • 1,449
  • 6
  • 17
  • 39
  • `The issue is that currently I have to run gradle clean build on my host machine first to create the jar file on my local machine at path` - why is this an issue? – jannis Apr 08 '20 at 19:12
  • Note that you can use a Gradle plugin to build docker images. There are a few out there, for example [com.liferay.app.docker](https://plugins.gradle.org/plugin/com.liferay.app.docker). – jannis Apr 08 '20 at 19:14
  • Because Ideally I would like this step in the docker container as it is one less command for a user to carry out before running my application. Is this possible? – java12399900 Apr 08 '20 at 19:14
  • It's is not clear what you want to do. If the users will only have the docker image there is no point to have them build the project instead of running the jar file. If the users can change the project it mean they will have it installed in their machine. In this case use a ```docker volumes``` – aiqency Apr 08 '20 at 19:32
  • `Is this possible?` - look above - there are plugins that will make this a one-step operation. – jannis Apr 08 '20 at 19:34
  • @aiqency - The user will clone my project from github - I then want them to be able to run the docker container without having to build the project with gradle first - I.e. I want the docker file to do the build and copy the jar into the container. I have edited my question to highlight this. – java12399900 Apr 08 '20 at 19:37
  • But then they have to build the image first, don't they? So what's the difference - they'll have to do SOMETHING this way or another. – jannis Apr 08 '20 at 19:41
  • Indeed, building the project directly in the `docker build` step yields a bit more reproducibility (and does not require having a complete toolchain on the host). To implement this, you could try for instance to rely on a standard maven-based `Dockerfile` such as that of this answer [How to convert a Spring-Boot web service into a Docker image](https://stackoverflow.com/a/54299199), and replace `mvn` commands with gradle ones? – ErikMD Apr 08 '20 at 19:41
  • Docker image is just another artifact produced by your project. Why build it differently than other artifacts (jar package for example)? – jannis Apr 08 '20 at 19:45
  • I agree with jannis If the users are devs and you want them to run the project in a container just let them use volumes – aiqency Apr 08 '20 at 19:53
  • @jannis two possible reasons: (1) to have a comprehensive build system within a container, e.g. for CI purposes ; (2) for reproducibility, see e.g. [this paragraph of a docker.com article](https://www.docker.com/blog/intro-guide-to-dockerfile-best-practices/#h.hsy4wrgavnlq) – ErikMD Apr 08 '20 at 19:53
  • @ErikMD thanks,How can I reproduce your maven answer in gradle? this is what I am looking for I think – java12399900 Apr 08 '20 at 22:20
  • 1
    https://codefresh.io/docs/docs/learn-by-example/java/gradle/ – jannis Apr 09 '20 at 21:38
  • 1
    https://medium.com/@sairamkrish/docker-for-spring-boot-gradle-java-micro-service-done-the-right-way-2f46231dbc06 – jannis Apr 09 '20 at 21:41
  • "build gradle within docker multistage spring-boot" is the phrase I used to find these links – jannis Apr 09 '20 at 21:42
  • @jannis thanks - feel free to answer the question or else I can add my answer as I have found a solution using that medium article you linked – java12399900 Apr 09 '20 at 22:32
  • `or else I can add my answer` please do. – jannis Apr 09 '20 at 22:33
  • I have added my answer now - feel free to add any feedback on my docker file as I not sure it is 100% optimal. – java12399900 Apr 09 '20 at 22:36

1 Answers1

14

After reading this article I have been able to solve this using a Multi Stage Docker Build. Please see the Docker file below:

# using multistage docker build
# ref: https://docs.docker.com/develop/develop-images/multistage-build/
    
# temp container to build using gradle
FROM gradle:5.3.0-jdk-alpine AS TEMP_BUILD_IMAGE
ENV APP_HOME=/usr/app/
WORKDIR $APP_HOME
COPY build.gradle settings.gradle $APP_HOME
  
COPY gradle $APP_HOME/gradle
COPY --chown=gradle:gradle . /home/gradle/src
USER root
RUN chown -R gradle /home/gradle/src
    
RUN gradle build || return 0
COPY . .
RUN gradle clean build
    
# actual container
FROM adoptopenjdk/openjdk11:alpine-jre
ENV ARTIFACT_NAME=pokerstats-0.0.1-SNAPSHOT.jar
ENV APP_HOME=/usr/app/
    
WORKDIR $APP_HOME
COPY --from=TEMP_BUILD_IMAGE $APP_HOME/build/libs/$ARTIFACT_NAME .
    
EXPOSE 8080
ENTRYPOINT exec java -jar ${ARTIFACT_NAME}
joshmcode
  • 3,247
  • 1
  • 34
  • 46
java12399900
  • 1,449
  • 6
  • 17
  • 39
  • 1
    What's the use of running gradle build twice ? – Nicolas Feb 16 '21 at 14:15
  • 2
    I suspect there isn't one - there are some other lines in this Dockerfile that don't look quite right either: "COPY . .", copying the project source with the chown option and then chowning it again, copying gradle from the original location in the image - these things make me suspect that running gradle twice is an oversight. – ultrafez Mar 05 '21 at 09:48
  • I agree some of this isn't needed, but I _think_ the `COPY . .` following the build is caching the dependencies. Copy the gradle files and build -- which will fail because the src is missing. Then copy over everything else and build again, but now the deps are in a previous step so changes to src won't mean redownloading/buidling dependencies. – Ian Pringle Nov 30 '21 at 17:21