Dockerfile to create image of spring boot - spring-boot

I want to create Docker image for a spring boot application.It uses gardle as build tool.
In bitbucket repository i could see below files are placed
--> src
--> build.gradle
--> Dockerfile
--> gradlew
--> gradlew.bat
Now Dockerfile has below content
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG DEPENDENCY=target/dependency
COPY ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY ${DEPENDENCY}/META-INF /app/META-INF
COPY ${DEPENDENCY}/BOOT-INF/classes /app
EXPOSE 8080
ENTRYPOINT ["java","-cp","app:app/lib/*","eds.billnq"]
When i try to create image using Dockerfile i get error
target/dependency/BOOT-INF library not found
target/dependency/META-INF library not found
My query is why here there is no gradle build steps in docker file ?
Also where target/dependency/ will be created ?

why here there is no gradle build steps in docker file ?
It looks like the Dockerfile is expecting the application to have already been built (by Gradle) before the Docker image is built, and for the resulting class files and jars to be available in various directories under target/dependency.
The Spring Boot Docker guide referred to by #WonChul Heo in the comments goes into how to build a Docker image using Gradle and specifically with the plugin gradle.plugin.com.palantir.gradle.docker:gradle-docker.
Also where target/dependency/ will be created ?
I'm guessing they should be created when you run your Gradle build, but without knowing more about how the build is configured, it's hard to say for sure.
I suggest you read through the guide again and compare what it recommends to what you have in your codebase, especially the Gradle build definitions.
At the end of the day, if you've pulled code from a private code repo and can't figure out how to make it build, it's probably best to seek out advice from the people who've committed to the codebase than from SO.

When working With Gradle ur jar file is going to be generated inside build/libs/{Your jar}
Can you please change ARG DEPENDENCY=target/dependency to ARG DEPENDENCY=build/libs and try? It will work.

Related

My spring boot application was running fine but when I dockerized it I got File not Found error

I don't know what I'm getting this error when I dockerized my spring-boot application
this is my Dockerfile
enter image description here
First, I wonder is your application working on your IDE?
Second, I think you make sure to build and package.
It is not sure to exists a jar file in your target folder.
You always have to build and check by yourself.
Make the build process automatic.
How about using this Dockerfile?
FROM maven:3.8.6-openjdk-18-slim as MAVEN_BUILD
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -Dmaven.test.skip=true
FROM openjdk:18-alpine
WORKDIR /app
ARG JAR_FILE=*.jar
COPY --from=MAVEN_BUILD /build/target/${JAR_FILE} ./app.jar
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]
If maven or openjdk version not matched, check this site.
https://hub.docker.com/_/maven
https://hub.docker.com/_/openjdk
In your Spring Boot application, from what I can see your BookingController is missing. Make sure you have the file present and build your image accordingly.
For your Dockerfile, try to change add to ADD, as it seems your target files are not been copied into the image built.

Should I build my gradle project using the Dockerfile

I'm reading about dockerization of Spring Boot applications and all (or almost all) tutorials are based on some simple Dockerfile like
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
It usually work (however you may need to change some build target paths) but as far as I understand it requires us to build the application jar before the docker build command will be run.
I'm actually working with Gradle but for the Maven, I guess, it looks the same.
My question is: is it good convention?
If I'll download some repostitory and run docker build, regardless having proper Dockerfile, it will fail because there is no target/*.jar file (at least if someone did not commit the /build directory :P).
Should we then include some ./gradlew build commands in the Dockerfile?
https://github.com/palantir/gradle-docker
you should use this project
or
jar_path=$(find . |grep $APP_NAME|grep jar|grep -v original|grep -v repository|grep -v templates)
mv $jar_path ./app.jar

Dockerfile for Spring boot

Spring docs tell me how to write a Dockerfile for my Spring Boot app. I adapted it to my gradle build with "build/libs" directory
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
But in my build/libs directory there are multiple versions of my jar:
app-22.9.0.jar
app-22.9.0-SNAPSHOT.jar
app-22.10.0.jar
app-22.10.0-SNAPSHOT.jar
...
Of course I can call 'gradle clean assemble' to do the job. But I need the Dockerfile in a test too. It is annoying to run clean assemble all the time.
How can I specify in my Dockerfile COPY command to use only the latest jar.
Docker uses normal shell glob rules when expanding patterns like this; there's no way to tell it to use the single most recent matching file, or the file with the largest embedded semantic version, or other things.
When you build the image, you can pass a more specific value for that ARG like
docker build --build-arg JAR_FILE=app-22.10.0.jar -t myapp:22.10.0 .
You may also want that build version to be in the image tag and it may be helpful to script this.
(You probably don't need to ./gradlew clean in between rebuilds, and that might make running ./gradlew assemble go faster.)

Using Maven artifact in Google Cloud Docker build

I have a google cloud container build with the following steps
gcr.io/cloud-builders/mvn to run a mvn clean package cmd
gcr.io/cloud-builders/docker to create a docker image
My docker image includes and will run tomcat.
Both these steps work fine independently.
How can I copy the artifacts built by step 1 into the correct folder of my docker container? I need to move either the built wars or specific lib files from step 1 to the tomcat dir in my docker container.
Echoing out the /workspace and /root dir in my Dockerfile doesn't show the artifacts. I think I'm misunderstanding this relationship.
Thanks!
Edit:
I ended up changing the Dockerfile to set the WORKDIR to /workspace
and
COPY /{files built by maven} {target}
The working directory is a persistent volume mounted in the builder containers, by default under /workdir. You can find more details in the documentation here https://cloud.google.com/container-builder/docs/build-config#dir
I am not sure what is happening in your case. But there is an example with a Maven step and a Docker build step in the documentation of the gcr.io/cloud-builders/mvn builder. https://github.com/GoogleCloudPlatform/cloud-builders/tree/master/mvn/examples/spring_boot. I suggest you compare with your files.
If it does not help, could you share your Dockerfile and cloudbuild.yaml. Please make sure you remove any sensitive information.
Also, you can inspect the working directory by running the build locally https://cloud.google.com/container-builder/docs/build-debug-locally#preserve_intermediary_artifacts

Caching Jar dependencies for Maven-based Docker builds

I'm building a Docker image from this Dockerfile:
FROM maven:3.3.3-jdk-8
MAINTAINER Mickael BARON
ADD pom.xml /work/pom.xml
WORKDIR /work
RUN mvn dependency:go-offline --fail-never
ADD ["src", "/work/src"]
RUN ["mvn", "package"]
With this Dockerfile, I force to download the dependencies before packaging my Java project. Thus, I don't have to redownload the dependencies every time I changed a file from my src directory.
But, there is a problem and this problem is depending on the version of Maven (base image). In fact, the dependencies are downloaded but they are not persisted into the ~/.m2 directory of the container. It's empty. Thus, when I change some source file all the dependencies are redownloaded.
However, I noticed that if I change the version of Maven from the base image (for example FROM maven:3.2.5-jdk-8), it works.
Very strange, isn't it?
There is a new instruction regarding this topic:
https://github.com/carlossg/docker-maven#packaging-a-local-repository-with-the-image
The $MAVEN_CONFIG dir (default to /root/.m2) is configured as a volume so anything copied there in a Dockerfile at build time is lost. For that the dir /usr/share/maven/ref/ is created, and anything in there will be copied on container startup to $MAVEN_CONFIG.
To create a pre-packaged repository, create a pom.xml with the dependencies you need and use this in your Dockerfile. /usr/share/maven/ref/settings-docker.xml is a settings file that changes the local repository to /usr/share/maven/ref/repository, but you can use your own settings file as long as it uses /usr/share/maven/ref/repository as local repo.
I'm afraid it's because of this VOLUME instruction they've added:
https://github.com/carlossg/docker-maven/blame/8ab542b907e69c5269942bcc0915d8dffcc7e9fa/jdk-8/Dockerfile#L11
It makes /root/.m2 a volume and thus any changes to that folder made by build steps are not brought on to the following build containers.

Resources