Maven packaging with Docker - java

I have a Spring project and a corresponding JAR file.
After i change something in one of my Java class files and run mvn package, building my Docker image of that project later is using the cached JAR.
Only if i run mvn clean package, my Docker build process does not use the cached JAR:
Step 4/6 : COPY app/target/app-${VERSION}.jar app.jar
---> 19987e6dda16
Is that expected?
Do i always have to run mvn clean package instead of mvn package after changing some code?

Related

Best approach to maven project-specific scripts?

In npm we have the option to define project specific scripts in the package.json file as described here.
What is the best tool/approach to this with maven? I'd like a way to write cross-platform, reproducible scripts with minimal setup.
Example scripts and the raw commands:
Build the project into a JAR file, skipping tests, and then deploy as part of a docker-compose deployment
mvn package -Dmaven.test.skip=true
docker-compose up --build -d
Rebuild and replace the running container in the docker-compose deployment
mvn package -Dmaven.test.skip=true
docker-compose up -d --no-deps --build spring
Build the project and run tests without deploying
mvn clean install
These commands can be a pain to remember and this is a project that will be used by many students with limited maven and docker experience. So a tool that's easy to install and makes creating scripts that 'just work' when pulling the repository would be great.

How to Dockerize a Java application that depends on Maven local repositories?

I have a Java Spring Boot web application that I'd like to containerize using Docker. I'm having trouble getting the mvn install command to work during the Docker build process because my project depends on some other Maven projects I've written that are installed in my local /.m2 folder but aren't available in the Maven central repository. I'd like to avoid adding these local projects to the public Maven central repository because they exist specifically to support this Spring Boot application and I'd like to keep them private.
If I wasn't using Docker, I could get around this problem by building a JAR with dependencies then deploying that .jar file. Is there any way for me to include these local dependencies in my Docker build process?
Here's the simple Dockerfile I'm trying to run:
# Step 1: Build with Maven
FROM maven:3.5-jdk-8-alpine
COPY . /usr/src/myapp
WORKDIR /usr/src/myapp
RUN mvn clean install
# Step 2: Run jar file with Java
FROM openjdk:8-alpine
WORKDIR /usr/src/myapp
COPY --from=0 /usr/src/myapp/target/myapp-1.0-SNAPSHOT.jar ./myapp.jar
ENTRYPOINT ["java", "-jar", "myapp.jar"]
I run this build command:
docker build -t myspringapp .
And it errors with the following message:
[ERROR] Failed to execute goal on project server: Could not resolve dependencies for project
com.website:myapp:jar:1.0-SNAPSHOT: The following artifacts could not be resolved:
com.website:dependency1:jar:0.1.0, com.website:dependency2:jar:0.1.0,
com.website:dependency3:jar:0.1.0:
Could not find artifact com.website:dependency1:jar:0.1.0 in central
(https://repo.maven.apache.org/maven2) -> [Help 1]
As an alternative question, can I just run the mvn clean install command on my development machine to produce the jar file then skip the whole Maven build part of the Docker image? Will my container still be able to replicate itself in an auto-scaling scenario? Do I lose anything by building the project separately from its Docker image/container?
Easiest thing to do would be to just put your .m2 directory in the Docker build context, and make sure the build stage of the Dockerfile does a COPY of .m2 to wherever the base maven image is expecting it to be. That way, the build stage doesn't need to download your private JAR files.
To answer your alternative question, yes. It's not very 12-factor, but it's definitely doable to do the JAR build outside of the Docker ecosystem, then just COPY the pre-built JAR file into the image.

How to make vert.x project work in a Docker container?

I downloaded a vert.x starter project from http://start.vertx.io/ and would like to run the compiled binary with java -jar .. inside a Docker container.
Current invocation command:
mvn package exec:java -DskipTests
Current Dockerfile:
FROM java:10
COPY target/project-1.0-SNAPSHOT.jar project.jar
ENTRYPOINT java -jar project.jar
which gives the following error message when run
no main manifest attribute, in
/project/target/vertx-start-project-1.0-SNAPSHOT.jar
Is there a simpler way than building a full deployment assembly as is usually done with Maven?
When you run a command like so:
mvn package exec:java
The vert.x specfic configuration will make Maven create:
SNAPSHOT.jar
SNAPSHOT-fat.jar
like so:
the fat.jar has all the files in it, so you only need to copy that jar file to the Docker image.
FROM openjdk:10-jre-slim
COPY target/SNAPSHOT-fat.jar fat.jar
ENTRYPOINT java -jar fat.jar
you build the docker image with:
docker build -t foo .
then run the docker image as a container with:
docker run -it foo
A runnable jar requires a Main-Class entry in MANIFEST.MF with the name of the class to launch.
You will most likely also need your dependencies copied in.
Consider this a full deployment of your application.
Like what Thorbjørn said, this command executes a "runnable" jar, which means it should have packed with a MANIFEST.MF that points to some certian main method in your project

Export jar with spring boot

I need to export executable jar from intellij spring boot project. its basic rest only. How can it possible. I have created the artifact jar and when i try to run it with java -jar xxx.jar it returns manifest file not found error.
Generally you have this error when you generate the JAR using the IDE directly (export option of Eclipse for example).
You can either use the Maven goals clean install or clean package to compile and generate the JAR in your target folder and/or local repository.
package - take the compiled code and package it in its distributable
format, such as a JAR.
install - install the package into the local repository, for use as a
dependency in other projects locally
The install will execute the package one step before install it on your local repository.
Maven Lifecycle Documentation
If you have installed maven, On the terminal of Intellij Idea use following code.
mvn clean package
Your Jar will be saved inside "target" folder inside the project directory

Docker build fails to find source folder for COPY command

I have a multi module maven project, and I want to create and publish an image for each module, except for a common, utility module, which is a dependency for all the other modules.
Project structure is like this:
project_root
common_module
-pom.xml
module_a
-pom.xml
-Dockerfile
module_b
-pom.xml
-Dockerfile
-pom.xml
-docker-compose.yml
To build module_a fox example, I need to copy the common_module folder too to the container, and run mvn install on the common folder first. If that is built, I can run mvn install on the module_a pom.xml too.
I'm new to Docker, and this is what I've been trying, which I think should work, according to the documentation of the COPY command, which states:
Multiple src resources may be specified but the paths of files and directories will be interpreted as relative to the source of the context of the build.
I have the following Dockerfile in module_a:
FROM openjdk:8-jre-alpine
# Install Maven
# (skipped for brevity)
# Create the project root
RUN mkdir -p /usr/src/project_root
WORKDIR /usr/src/project_root
# Copy all the necessary files for the packaging
# Copy the common module
COPY common_module /usr/src/project_root/common_module
# Copy the service registry module (src + config folder)
COPY module_a /usr/src/project_root/module_a
# Run maven install
RUN cd common_module
RUN mvn clean install
RUN cd ../module_a
RUN mvn clean install
And I issue this command from the project_root folder (making it the context of the build?):
docker build -t image_name:4.0 ./module_a
The build fails at the first COPY command, stating:
COPY failed: stat /var/lib/docker/tmp/docker-builder380120612/common_module: no such file or directory
I'm not even sure the RUN commands would work, as the build fails before those.
What am I doing wrong? How can one copy folders/files outside of the Dockerfile location?
By the way I'm running Docker version 18.03.1-ce, build 9ee9f40, on Windows 10 Pro.
When you run the command
docker build -t image_name:4.0 ./module_a
You define the build context as the module_a directory. Then you try to COPY the directory common_module into your container but it's not possible as it is not in the build context.
Use this command instead:
docker build -t image_name:4.0 -f ./module_a/Dockerfile .
This way module_a, common_module and module_b will be included in the build context.

Categories