Docker build fails to find source folder for COPY command - java

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.

Related

Docker Springboot Webapp Included Libraries

I've got a Springboot jar deployed as a webapp via Docker. Here is the basic outline of my Dockerfile.
#
# Build App
#
FROM maven:3.6.3-openjdk-15-slim AS build
# Copy Parent Project
COPY src /home/app/src
COPY pom.xml /home/app
RUN mvn -f /home/app/pom.xml clean package -DskipTests
#
# Deploy App
#
FROM openjdk:15-jdk-alpine
COPY --from=build /home/app/my-app/target/my-app-rest-0.0.1-SNAPSHOT.jar /usr/local/lib/app.jar
ENTRYPOINT exec java -Djava.security.egd=file:/dev/./urandom -jar /usr/local/lib/app.jar
I originally found a pattern similar to this Dockerfile around the internet and I thought I understood most of it, but one thing is eluding me: where are all of the dependency jars that are needed by my app.jar to run? My project is running and executing just fine, so those have to be somewhere in my container. But I've searched and searched but can't find any of the dependency jars or even the WEB-INF directory for my webapp. I know that my actual application jar is in /usr/local/lib/, but that's about all I can deduce.
Is there some default location where the dependency/webapp config would go? Is there something that I can add to my Dockerfile to define where it should go?
Spring boot puts all your dependencies (jars) in fat executable jar, which is the one you are passing to the run stage, and the exact one you are running with the java command.
Since jar files are just compressed archives you can extract them using unzip an peek inside them:
docker cp <container-id>:/home/app/my-app/target/my-app-rest-0.0.1-SNAPSHOT.jar myjar.jar
unzip myjar.jar -d myjar
ls -al myjar/BOOT-INF/lib
And you'll get the list of all the jars you spring boot app depends on.
More information here and here
Maven is used to build your .jar package, while you only need to put the .jar package into docker image and add java -jar ... as the entry point.
Note that Docker is strongly recommending programmers to separate applications into individual docker images. Even if you can have both Maven and .jar together, don't do that.
Is there some default location where the dependency/webapp config would go?
Yes. This is the Dockerfile I use at work. You run maven commands such as clean, package on your development machine, instead of inside a Dockerfile.
FROM openjdk:8-jdk-alpine
# You want to change JDK version.
ADD target/*.jar app.jar
# You have to place this Dockerfile in the SAME directory with the target folder. Then this Dockerfile pulls whatever jar you have under target, renames it to app.jar and adds it to the build.
EXPOSE 9001
# You want to change this to whatever port your java app listens on.
ENTRYPOINT ["java", "-jar", "/app.jar"]
# Typical command you use to run .jar package but this time, you use it as the entrypoint.
As soon as you have that .jar package, cd into the Dockerfile directory and docker build ..

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.

Maven packaging with Docker

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?

I can't find my jar file when trying to copy it in a multi stage docker build

So I am very new to docker and I have been trying to dockerise my spring-boot application. I managed to get it working with a given JAR file but now I would like to make a multi stage build to build the JAR file using gradle so that I don't have to manually generate the JAR before running docker build {app-name}
This is my current setup. It fails to find the jar file and I don't know how I can navigate the filesystem to find it (other than running shell commands in the dockerfile to print out the files & folders)
DOCKERFILE
FROM gradle:jdk8 as build
COPY --chown:gradle:gradle . /home/gradle/src
WROKDIR /home/gradle/src
RUN gradle clean build --parallel
FROM openjdk:8-alpine
WORKDIR /usr/app
COPY --from=build /home/gradle/src/app-name.jar /usr/app/
RUN sh -c 'touch app-name.jar'
ENTRYPOINT ["java", "-jar", "app-name.jar"]
Console Output
Step 7/9. : COPY —from=build /home/gradle/src/app-name.jar /usr/app/
COPY failed: stat /var/lib/ldocker/overlay2/22e326d9f26f581a629417c35e226428f3cc63fd496799c55dde4be413ca26690/merged/home/gradle/src/app-name.jar: no such file or directory
The COPY directive needs to copy from gradle's build/libs/ directory which is the default location for build artifacts - as it stands it's looking for the JAR in the project root. This should work:
COPY —from=build /home/gradle/src/build/libs/app-name.jar /usr/app
This assumes the Dockerfile is located in your project's root directory. If it's not, then you'll need to adjust the copy path used in the dockerfile accordingly.

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

Categories