Spring boot Gradle not generating wrapper and not producing runnable jar - java

I'm trying to create a Spring boot application which would be compiled and run completely in Docker, using a multi-staged dockerfile:
###############
#### Build ####
###############
FROM openjdk:13-alpine as builder
WORKDIR /usr/src/app
COPY . .
RUN path/to/gradlew build
################
#### Deploy ####
################
FROM openjdk:13-alpine
WORKDIR /usr/src/app
COPY --from=builder /usr/src/app/some/path /usr/src/app/
EXPOSE 8080
CMD [java, some/path/someJar.jar]
Two things I can't get straight:
There's no gradlew file and gradlew.bat file anywhere in my project. Even though there is a gradle/ directory and in gradle/wrapper/gradle-wrapper.properties I define Gradle version 3.5.1. In settings I tried 'default wrapper' and 'wrapper task configuration'.
Intellij Idea seems to resolve the gradle executable somehow. Don't know where the executable is.
There is some output generated by gradle when building. But nothing that I can run manually or convert to a nice docker command. It basically compiles the java classes and that's it. Running the main class in java doesn't work. Once again, using Intellij Idea 'run' works fine. What does Intellij do?

In order to create wrapper files you need to install Gradle in some other way first. Check installation documentation. After that you need to run command inside the root folder of your project:
gradle wrapper
This will generate required wrapper and wrapper.bat files. Then you can use those scripts to run from your Dockerfile. More details on working with wrapper can be found here.
After you generate the wrapper files you can configure the Intellij by going to Settings -> Build, Execution, Deployment -> Gradle and applying Use default gradle wrapper (recommended) radio button. Then IDEA will use it.

Related

Installing maven depencies from pom.xml in docker

I am trying to run a spring-boot maven project inside a docker environment. So the setup is as follows:
Docker is set up and installs Java, etc. (done only once)
App is run (can be any number of times)
What I am experiencing
Every time I run the spring-boot project by mvn spring-boot:run, it installs all the required libraries (every time I run the project) from the pom.xml (Java, Maven, etc. are preinstalled from the docker) and then runs the project.
What I am trying to do
This process of reinstalling every time is redundant and time-consuming, so I want to delegate this installation thing to the docker as well. Ideally, using the pom.xml to do the installations, though alternative ways are also welcome.
What I have tried so far
Install npm using a good tutorial, but it fails in Docker as we can't restart the terminal during docker build, while source ~/.bash_profile doesn't seem to work either.
Tried to build that project directly in docker (by RUN mvn clean install --fail-never) and copying both npm and node folders to the directory where I run the app. But it doesn't seem to work either as it's installing them every time without any change.
Can anyone please help me there? This problem has stuck the project. Thanks a lot!
From your question I understand that, in the Dockerfile you just install java, maven, etc. but does not build your project using mvn clean package install before executing mvn spring-boot:run (and that is redundant as well because mvn spring-boot:run does the build for you before staring the application).
You cannot skip installing maven dependency while running on containers as they are spun as they run. So it will be installed either while you call mvn clean install or mvn spring-boot:run.
What the max you can do is, using your devops pipeline, build the jar previously and in the Dockerfile just copy the build jar and execute.
Example Dockerfile in this case:
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
Here the previously build artifact is already available at target/

spring-boot-devtools Automatic Restart not working

I have a working Spring Boot 2.25 application built with mvn. As per this documentation I add
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
From the documentation:
As DevTools monitors classpath resources, the only way to trigger a restart is to update the classpath. The way in which you cause the classpath to be updated depends on the IDE that you are using. In Eclipse, saving a modified file causes the classpath to be updated and triggers a restart. In IntelliJ IDEA, building the project (Build -> Build Project) has the same effect.
With the application running I tried a simple
touch /path/to/app.jar
expecting the application to restart but nothing happened.
Okay, so maybe it's doing something smarter. I modified some source .java, recompiled the .jar, and cp'd it to replace the running .jar file and... nothing happened.
Also from the documentation
DevTools relies on the application context’s shutdown hook to close it during a restart. It does not work correctly if you have disabled the shutdown hook (SpringApplication.setRegisterShutdownHook(false)).
I am not doing this.
DevTools needs to customize the ResourceLoader used by the ApplicationContext. If your application provides one already, it is going to be wrapped. Direct override of the getResource method on the ApplicationContext is not supported.
I am not doing this.
I am running this in a Docker container, if that matters. From the documentation:
Developer tools are automatically disabled when running a fully packaged application. If your application is launched from java -jar or if it is started from a special classloader, then it is considered a “production application”. If that does not apply to you (i.e. if you run your application from a container), consider excluding devtools or set the -Dspring.devtools.restart.enabled=false system property.
I don't understand what this means or if it is relevant.
I want to recompile a .jar and replace it in the running docker container and trigger and application restart without restarting the container. How can I do this?
EDIT: I am using mvn to rebuild the jar, then docker cp to replace it in the running container. (IntelliJ IDEA claims to rebuild the project, but the jar files are actually not touched, but that's another story.) I am looking for a non-IDE-specific solution.
The Spring Boot Devtools offers for Spring Boot applications the functionality that usually is available in IDEs like IntelliJ in which you have the ability to, for example, restart an application or force a live browser reload when certain classes or resources change. This can be very useful in the development phase of your application.
It is typically used in conjunction with an IDE in such a way that it will be launched with the rest of your application by Spring Boot when detected in the classpath and if it is not disabled.
Although you can configure it to monitor further resources, it will usually look for changes in your application code, in your classes and resources.
It is important to say that, AFAIK, Devtools will monitor your own classes and resources in an exploded way, I mean, the restart process will not work if you overwrite your whole application jar, only if you overwrite some resources in your classes directory.
This functionality can be tested with Maven. Please, consider download a simple blueprint from Spring Initializr, with Spring Boot, Spring Boot Devtools and Spring Web, for example - in order to keep the application running. From a terminal, in the directory that contains the pom.xml file, run your application, for instance, with the help of the spring-boot-maven-plugin plugin included in the pom.xml:
mvn spring-boot:run
The command will download the project dependencies, compile and run your application.
Now, perform any modification in your source code, either in your classes or in your resources and, from another terminal, in the same directory, recompile your resources:
mvn compile
If you look at the first terminal window you will see that the application is restarted to reflect the changes.
If you are using docker for your application deployment, try reproducing this behavior can be tricky.
On one hand, I do not know if it makes sense, but you can try creating a maven based image and run your code inside, just as described above. Your Dockerfile can look similar to this:
FROM maven:3.5-jdk-8 as maven
WORKDIR /app
# Copy project pom
COPY ./pom.xml ./pom.xml
# Fetch (and cache) dependencies
RUN mvn dependency:go-offline -B
# Copy source files
COPY ./src ./src
# Run your application
RUN mvn springboot:run
With this setup, you can copy with docker cp your resources to the /app/target directory and it will trigger an application restart. As an alternative, consider mounting a volume in your container instead of using docker cp.
Much better, and taking into account the fact that overwriting your application jar will probably not work, you can try to copy both your classes and library dependencies, and run your application in a exploded way. Consider the following Dockerfile:
FROM maven:3.5-jdk-8 as maven
WORKDIR /app
# Copy your project pom
COPY ./pom.xml ./pom.xml
# Fetch (and cache) dependencies
RUN mvn dependency:go-offline -B
# Copy source files
COPY ./src ./src
# Compile application and library dependencies
# The dependencies will, by default, be copied to target/dependency
RUN mvn clean compile dependency:copy-dependencies -Dspring-boot.repackage.skip=true
# Final run image (based on https://stackoverflow.com/questions/53691781/how-to-cache-maven-dependencies-in-docker)
FROM openjdk:8u171-jre-alpine
# OPTIONAL: copy dependencies so the thin jar won't need to re-download them
# COPY --from=maven /root/.m2 /root/.m2
# Change working directory
WORKDIR /app
# Copy classes from maven image
COPY --from=maven /app/target/classes ./classes
# Copy dependent libraries
COPY --from=maven /app/target/dependency ./lib
EXPOSE 8080
# Please, modify your main class name as appropriate
ENTRYPOINT ["java", "-cp", "/app/classes:/app/lib/*", "com.example.demo.DemoApplication"]
The important line in the Dockerfile is this:
mvn clean compile dependency:copy-dependencies -Dspring-boot.repackage.skip=true
It will instruct maven to compile your resources and copy the required libraries. Although redundant for the typical Maven phase in which the spring-boot-maven-plugin repackage goal runs, the flag spring-boot.repackage.skip=true will instruct this plugin to not repackage the application.
With this Dockerfile, build you image (let's tag it devtools-demo, for example):
docker build -t devtools-demo .
And run it:
docker run devtools-demo:latest
With this setup, if now you change your classes and/or resources, and run mvn locally:
mvn compile
you should be able to force the restart mechanism in your container with the following docker cp command:
docker cp classes <container name>:/app/classes
Please, again, consider mounting a volume in your container instead of using docker cp.
I tested the setup and it worked properly.
The important think to keep in mind is to replace your exploded resources, not the whole application jar.
As another option, you can take an approach similar to the one indicated in your comments and run your Devtools in remote mode:
FROM maven:3.5-jdk-8 as maven
WORKDIR /app
# Copy project pom
COPY ./pom.xml ./pom.xml
# Fetch (and cache) dependencies
RUN mvn dependency:go-offline -B
# Copy source files
COPY ./src ./src
# Build jar
RUN mvn package && cp target/your-app-version.jar app.jar
# Final run image (based on https://stackoverflow.com/questions/53691781/how-to-cache-maven-dependencies-in-docker)
FROM openjdk:8u171-jre-alpine
# OPTIONAL: copy dependencies so the thin jar won't need to re-download them
# COPY --from=maven /root/.m2 /root/.m2
# Change working directory
WORKDIR /app
# Copy artifact from the maven image
COPY --from=maven /app/app.jar ./app.jar
ENV JAVA_DOCKER_OPTS "-agentlib:jdwp=transport=dt_socket,server=y,address=*:8000,suspend=n"
ENV JAVA_OPTS "-Dspring.devtools.restart.enabled=true"
EXPOSE 8000
EXPOSE 8080
ENTRYPOINT ["/bin/bash", "-lc", "exec java $JAVA_DOCKER_OPTS $JAVA_OPTS -jar /app/app.jar"]
For the Spring Boot Devtools remote mode to work properly, you need several things (some of them pointed out by Opri as well in his/her answer).
First, you need to configure the spring-boot-maven-plugin to include the devtools in your application jar (it will be excluded otherwise, by default):
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludeDevtools>false</excludeDevtools>
</configuration>
</plugin>
Then, you need to setup a value for the configuration property spring.devtools.remote.secret. This property has to do with the way remote debugging works in Spring Boot Devtools.
The remote debugging functionality consists of two parts, a client and a server. Basically, the client is a copy of your server code, and it uses the value of the spring.devtools.remote.secret configuration property to authenticate itself against the server.
This client code should be run from an IDE, and you attach your IDE debugging process to a local server exposed from that client.
Every change performed in the client monitored resources, remember, the same as in your server, is pushed to the remote server and it will trigger a restart if necessary.
As you can see, this functionality is again more appropriate from a development point of view.
If you need to actually restart your application by overwriting your jar application file, maybe a better approach will be to configure your docker container to run a shell script in your ENTRYPOINT or CMD. This shell script will monitor a copy of your jar, in a certain directory. If that resource changes, as a consequence of your docker cp, this shell script will stop the current running application version - this application is supposed to run from a different location to avoid problems when updating the jar -, replace the current jar with the new one, and then start the new application version. Not the same, but please, consider read this related SO answer.
In any case, when you run an application in a container, you are trying to provide a consistent and platform independent way of deployment for it. From this perspective, instead of monitoring changes in your docker container, a more convenient approach may be to generate and to deploy a new version of your container image with those new changes. This process can be automated greatly using tools like Jenkins, Travis, etcetera. These tools allow you to define CI/CD pipelines that, in response to a code commit, for example, can generate on the fly a docker image with your code and, it configured accordingly, deploy later this image to services like some docker flavor or Kubernetes, on premises or in the cloud. Some of them, especially Kubernetes, but swarm an even docker compose as well, will allow you to perform rolling updates without or with minimal application service interruption.
To conclude, probably it will not fit your needs, but be aware that you can use spring-boot-starter-actuator directly or with Spring Boot Admin, for instance, to restart your application.
Finally, as already indicated in the Spring Boot Devtools documentation, you can try a different option, not based on restart but in application reload, in hot swapping. This functionality is offered by commercial products like JRebel although there are some open sources alternatives as well, mainly dcevm and the HotswapAgent. This related article provides some insight in how these last two products work. This Github project provides complementary information about how to run it in docker containers.
I had a similar problem when using intellij idea, I saw somewhere that you had to use the build button for it to work.
In jsp the application reloads the files, it is not completely automatic, because intellij saves automatically -> this behavior is the default but there is I think a way to change it. -> To record manually and then that it reloads automatically.
Works for jsp apps only, if you try this with standard apps it will create a double frame execution (swing)
I am no shore because you are not saying explicitly if you tried this things but:
try to set this on true:(SpringApplication.setRegisterShutdownHook(true))
try adding manually in the dockerfile this property -Dspring.devtools.restart.enabled=true
I know it says that on default should be on true, but try to do it
manually
Maybe show us the dockerfile.
Later Edit:
Saw this in documentation:
repackaged archives do not contain devtools by default. If you want to
use certain remote devtools feature, you’ll need to disable the
excludeDevtools build property to include it. The property is
supported with both the Maven and Gradle plugins.
The Spring Boot developer tools are not just limited to local development. You can also use several features when running applications remotely. Remote support is opt-in, to enable it you need to make sure that devtools is included in the repackaged archive:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludeDevtools>false</excludeDevtools>
</configuration>
</plugin>
</plugins>
</build>
Then you need to set a spring.devtools.remote.secret property, for example:
spring.devtools.remote.secret=mysecret
Remote devtools support is provided in two parts; there is a server side endpoint that accepts connections, and a client application that you run in your IDE. The server component is automatically enabled when the spring.devtools.remote.secret property is set. The client component must be launched manually.
Documents from spring
In order to restart app with devtools you need to make sure following things.
Use any IDE or Build tools like maven gradle to start app
Using java -jar devtools will not work as it packages app.
Using maven you can run app like mvn spring-boot:run
Refer official documentation for more details.
I had similar issue after using dependency also spring boot was not picking up devtools configuration so I did following steps in eclipse.
installed eclipse (assuming you have already installed)
installed sts plugin from eclipse market (since i am eclipse generic version lover so prefer generic eclipse on top of that i installed sts plugin)
project --> build automatically
debug as --> spring boot application
done.

Slow gradle build in Docker. Caching gradle build

I am doing university project where we need to run multiple Spring Boot applications at once.
I had already configured multi-stage build with gradle docker image and then run app in openjdk:jre image.
Here is my Dockerfile:
FROM gradle:5.3.0-jdk11-slim as builder
USER root
WORKDIR /usr/src/java-code
COPY . /usr/src/java-code/
RUN gradle bootJar
FROM openjdk:11-jre-slim
EXPOSE 8080
WORKDIR /usr/src/java-app
COPY --from=builder /usr/src/java-code/build/libs/*.jar ./app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
I am building and running everything with docker-compose. Part of docker-compose:
website_server:
build: website-server
image: website-server:latest
container_name: "website-server"
ports:
- "81:8080"
Of course first build take ages. Docker is pulling all it's dependencies. And I am okay with that.
Everything is working ok for now but every little change in code causes around 1 min build time for one app.
Part of build log: docker-compose up --build
Step 1/10 : FROM gradle:5.3.0-jdk11-slim as builder
---> 668e92a5b906
Step 2/10 : USER root
---> Using cache
---> dac9a962d8b6
Step 3/10 : WORKDIR /usr/src/java-code
---> Using cache
---> e3f4528347f1
Step 4/10 : COPY . /usr/src/java-code/
---> Using cache
---> 52b136a280a2
Step 5/10 : RUN gradle bootJar
---> Running in 88a5ac812ac8
Welcome to Gradle 5.3!
Here are the highlights of this release:
- Feature variants AKA "optional dependencies"
- Type-safe accessors in Kotlin precompiled script plugins
- Gradle Module Metadata 1.0
For more details see https://docs.gradle.org/5.3/release-notes.html
Starting a Gradle Daemon (subsequent builds will be faster)
> Task :compileJava
> Task :processResources
> Task :classes
> Task :bootJar
BUILD SUCCESSFUL in 48s
3 actionable tasks: 3 executed
Removing intermediate container 88a5ac812ac8
---> 4f9beba838ed
Step 6/10 : FROM openjdk:11-jre-slim
---> 0e452dba629c
Step 7/10 : EXPOSE 8080
---> Using cache
---> d5519e55d690
Step 8/10 : WORKDIR /usr/src/java-app
---> Using cache
---> 196f1321db2c
Step 9/10 : COPY --from=builder /usr/src/java-code/build/libs/*.jar ./app.jar
---> d101eefa2487
Step 10/10 : ENTRYPOINT ["java", "-jar", "app.jar"]
---> Running in ad02f0497c8f
Removing intermediate container ad02f0497c8f
---> 0c63eeef8c8e
Successfully built 0c63eeef8c8e
Successfully tagged website-server:latest
Every time it freezes after Starting a Gradle Daemon (subsequent builds will be faster)
I was thinking about adding volume with cached gradle dependencies but I don't know if that is core of the problem. Also i could't find good examples for that.
Is there any way to speed up the build?
Build takes a lot of time because Gradle every time the Docker image is built downloads all the plugins and dependencies.
There is no way to mount a volume at the image build time. But it is possible to introduce new stage that will download all dependencies and will be cached as Docker image layer.
FROM gradle:5.6.4-jdk11 as cache
RUN mkdir -p /home/gradle/cache_home
ENV GRADLE_USER_HOME /home/gradle/cache_home
COPY build.gradle /home/gradle/java-code/
WORKDIR /home/gradle/java-code
RUN gradle clean build -i --stacktrace
FROM gradle:5.6.4-jdk11 as builder
COPY --from=cache /home/gradle/cache_home /home/gradle/.gradle
COPY . /usr/src/java-code/
WORKDIR /usr/src/java-code
RUN gradle bootJar -i --stacktrace
FROM openjdk:11-jre-slim
EXPOSE 8080
USER root
WORKDIR /usr/src/java-app
COPY --from=builder /usr/src/java-code/build/libs/*.jar ./app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
Gradle plugin and dependency cache is located in $GRADLE_USER_HOME/caches. GRADLE_USER_HOME must be set to something different than /home/gradle/.gradle. /home/gradle/.gradle in parent Gradle Docker image is defined as volume and is erased after each image layer.
In the sample code GRADLE_USER_HOME is set to /home/gradle/cache_home.
In the builder stage Gradle cache is copied to avoid downloading the dependencies again: COPY --from=cache /home/gradle/cache_home /home/gradle/.gradle.
The stage cache will be rebuilt only when build.gradle is changed.
When Java classes are changes, cached image layer with all dependencies is reused.
This modifications can reduce the build time but more clean way of building Docker images with Java applications is Jib by Google.
There is a Jib Gradle plugin that allows to build container images for Java applications without manually creating Dockerfile.
Building image with application and running the container is similar to:
gradle clean build jib
docker-compose up
Docker caches its images in "layers." Each command that you run is a layer. Each change that is detected in a given layer invalidates the layers that come after it. If the cache is invalidated, then the invalidated layers must be built from scratch, including dependencies.
I would suggest splitting your build steps. Have a previous layer which only copies the dependency specification into the image, then runs a command which will result in Gradle downloading the dependencies. After that's complete, copy your source into the same location where you just did that, and run the real build.
This way, the previous layers will be invalidated only when the gradle files change.
I haven't done this with Java/Gradle, but I have followed the same pattern with a Rust project, guided by this blog post.
You can try and use BuildKit (now activated by default in the latest docker-compose 1.25)
See "Speed up your java application Docker images build with BuildKit!" from
Aboullaite Med.
(This was for maven, but the same idea applies to gradle)
let's consider the following Dockerfile:
FROM maven:3.6.1-jdk-11-slim AS build
USER MYUSER
RUN mvn clean package
Modifying the second line always invalidate maven cache due to false dependency, which exposes inefficient caching issue.
BuildKit solves this limitation by introducing the concurrent build graph solver, which can run build steps in parallel and optimize out commands that don’t have an impact on the final result.
Additionally, Buildkit tracks only the updates made to the files between repeated build invocations that optimize the access to the local source files. Thus, there is no need to wait for local files to be read or uploaded before the work can begin.
As the other answers have mentioned, docker caches each step in a layer. If you could somehow get only the downloaded dependencies into a layer, then it would not have to be re downloaded each time, assuming the dependencies haven't changed.
Unfortunately, gradle doesn't have a built-in task to do this. But you can still work around it. Here's what I did:
# Only copy dependency-related files
COPY build.gradle gradle.properties settings.gradle /app/
# Only download dependencies
# Eat the expected build failure since no source code has been copied yet
RUN gradle clean build --no-daemon > /dev/null 2>&1 || true
# Copy all files
COPY ./ /app/
# Do the actual build
RUN gradle clean build --no-daemon
Also, make sure your .dockerignore file has at least these items, so that they're not sent in the docker build context when the image is built:
.gradle/
bin/
build/
gradle/
Just as an addition to other people answers, if your internet connection is slow, as it downloads dependencies every single time, you might want to set up sonatype nexus, in order to keep the dependencies already downloaded.
I used a slightly different idea. I scheduled a nightly build on my Jenkins building the entire Gradle project:
docker build -f Dockerfile.cache --tag=gradle-cache:latest .
# GRADLE BUILD CACHE
FROM gradle:6.7.1-jdk11
COPY build.gradle.kts /home/gradle/code/
COPY settings.gradle.kts /home/gradle/code/
COPY gradle.properties /home/gradle/code/
COPY ./src /home/gradle/code/src
WORKDIR /home/gradle/code
RUN gradle bootJar -i -s
Then I start my builds from this "cache image" so I can leverage all the Gradle goodness:
docker build --tag=my-app:$version .
# GRADLE BUILD
FROM gradle-cache:latest as gradle
COPY build.gradle.kts /home/gradle/code/
COPY settings.gradle.kts /home/gradle/code/
COPY gradle.properties /home/gradle/code/
RUN rm -rf /home/gradle/code/src
COPY ./src /home/gradle/code/src
WORKDIR /home/gradle/code
RUN gradle bootJar -i -s
# SPRING BOOT
FROM openjdk:11.0.9.1-jre
COPY --from=gradle /home/gradle/code/build/libs/app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-Xmx2G", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
Remember about pruning unused images every week or so.
I don't know much about docker internals, but I think that the problem is that each new docker build command, will copy all files and build them (if it detects changes in at least one file).
Then this will most likely change several jars and the second steps needs to run too.
My suggestion is to build on the terminal (outside of docker) and only docker build the app image.
This can even be automated with a gradle plugin:
https://github.com/Transmode/gradle-docker (one example, I did not search thoroughly)

How to deploy Spring Boot + gradle service on Openshift

I've read tons of documentation and tutorials, but still cannot get through this.
I want to start developing a service using Spring boot and Gradle and deploy it on openshift.
With fabric8, there is a handy command 'mvn' clean install -Dfabric8.mode=openshift
to run the deployment.
This uses maven tho, and I'm with Gradle.
How can I do it? I know that I need an s2i-builder, but I cannot understand how to use them.
I know that fabric8, uses jboss-fuse-6/fis-java-openshift as s2i build, I may want to use the same for my builds.
Also, I would like to know if there is a way to redeploy from local files (this should be called a binary deploy) for dev purposes. As last thing, the very next step for me is setting up Jenkins but to get started I just really want to know how to proceed.
I've this simple Dockerfile:
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", "-jar", "/app.jar"]
I'm using this plugin: "gradle.plugin.com.palantir.gradle.docker:gradle-docker:0.13.0" that gives me the Gradle task: ./gradlew build docker.
This container gets built successfully, and if I run it locally with docker run -p 8080:8080 it.example/microservice it runs perfectly fine. Added this bit of content just because I feel I'm not too far.

What is the purpose of mvnw and mvnw.cmd files?

When I created a Spring Boot application I could see mvnw and mvnw.cmd files in the root of the project. What is the purpose of these two files?
These files are from Maven wrapper. It works similarly to the Gradle wrapper.
This allows you to run the Maven project without having Maven installed and present on the path. It downloads the correct Maven version if it's not found (as far as I know by default in your user home directory).
The mvnw file is for Linux (bash) and the mvnw.cmd is for the Windows environment.
To create or update all necessary Maven Wrapper files execute the following command:
mvn -N io.takari:maven:wrapper
To use a different version of maven you can specify the version as follows:
mvn -N io.takari:maven:wrapper -Dmaven=3.3.3
Both commands require maven on PATH (add the path to maven bin to Path on System Variables) if you already have mvnw in your project you can use ./mvnw instead of mvn in the commands.
Command mvnw uses Maven that is by default downloaded to ~/.m2/wrapper on the first use.
URL with Maven is specified in each project at .mvn/wrapper/maven-wrapper.properties:
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip
To update or change Maven version invoke the following (remember about --non-recursive for multi-module projects):
./mvnw io.takari:maven:wrapper -Dmaven=3.3.9
or just modify .mvn/wrapper/maven-wrapper.properties manually.
To generate wrapper from scratch using Maven (you need to have it already in PATH run:
mvn io.takari:maven:wrapper -Dmaven=3.3.9
The Maven Wrapper is an excellent choice for projects that need a specific version of Maven (or for users that don't want to install Maven at all). Instead of installing many versions of it in the operating system, we can just use the project-specific wrapper script.
mvnw: it's an executable Unix shell script used in place of a fully installed Maven
mvnw.cmd: it's for Windows environment
Use Cases
The wrapper should work with different operating systems such as:
Linux
OSX
Windows
Solaris
After that, we can run our goals like this for the Unix system:
./mvnw clean install
And the following command for Batch:
./mvnw.cmd clean install
If we don't have the specified Maven in the wrapper properties, it'll be downloaded and installed in the folder $USER_HOME/.m2/wrapper/dists of the system.
Maven Wrapper plugin
Maven Wrapper plugin to make auto installation in a simple Spring Boot project.
First, we need to go in the main folder of the project and run this command:
mvn -N io.takari:maven:wrapper
We can also specify the version of Maven:
mvn -N io.takari:maven:wrapper -Dmaven=3.5.2
The option -N means –non-recursive so that the wrapper will only be applied to the main project of the current directory, not in any submodules.
Source 1 (further reading): https://www.baeldung.com/maven-wrapper
short answer: to run Maven and Gradle in the terminal without following manual installation processes.
Gradle example:
./gradlew clean build
./gradlew bootRun
Maven example:
./mvnw clean install
./mvnw spring-boot:run
"The recommended way to execute any Gradle build is with the help of the Gradle Wrapper (in short just “Wrapper”). The Wrapper is a script that invokes a declared version of Gradle, downloading it beforehand if necessary. As a result, developers can get up and running with a Gradle project quickly without having to follow manual installation processes saving your company time and money."
Gradle would also add some specific files corresponding to the Maven files Gradlew and Gradle.bat
In the windows OS, mvnw clean install is used for the maven clean and install activity, and mvnw spring-boot:run is used to run the Spring boot application from Command Prompt.
For Eaxmple:
C:\SamplesSpringBoot\demo>mvnw clean install
C:\SamplesSpringBoot\demo>mvnw spring-boot:run
By far the best option nowadays would be using a maven container as a builder tool. A mvn.sh script like this would be enough:
#!/bin/bash
docker run --rm -ti \
-v $(pwd):/opt/app \
-w /opt/app \
-e TERM=xterm \
-v $HOME/.m2:/root/.m2 \
maven mvn "$#"

Categories

Resources