How to build a docker container for a Java application
The docker registry hub has a Maven image that can be used to create java containers.
Using this approach the build machine does not need to have either Java or Maven pre-installed, Docker controls the entire build process.
Example
├── Dockerfile
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── org
│ │ └── demo
│ │ └── App.java
│ └── resources
│ └── log4j.properties
└── test
└── java
└── org
└── demo
└── AppTest.java
Image is built as follows:
docker build -t my-maven .
And run as follows:
$ docker run -it --rm my-maven
0 [main] INFO org.demo.App - hello world
Dockerfile
FROM maven:3.3-jdk-8-onbuild
CMD ["java","-jar","/usr/src/app/target/demo-1.0-SNAPSHOT-jar-with-dependencies.jar"]
Update
If you wanted to optimize your image to exclude the source you could create a Dockerfile that only includes the built jar:
FROM java:8
ADD target/demo-1.0-SNAPSHOT-jar-with-dependencies.jar /opt/demo/demo-1.0-SNAPSHOT-jar-with-dependencies.jar
CMD ["java","-jar","/opt/demo/demo-1.0-SNAPSHOT-jar-with-dependencies.jar"]
And build the image in two steps:
docker run -it --rm -w /opt/maven \
-v $PWD:/opt/maven \
-v $HOME/.m2:/root/.m2 \
maven:3.3-jdk-8 \
mvn clean install
docker build -t my-app .
__
Update (2017-07-27)
Docker now has a multi-stage build capability. This enables Docker to build an image containing the build tools but only the runtime dependencies.
The following example demonstrates this concept, note how the jar is copied from target directory of the first build phase
FROM maven:3.3-jdk-8-onbuild
FROM java:8
COPY --from=0 /usr/src/app/target/demo-1.0-SNAPSHOT.jar /opt/demo.jar
CMD ["java","-jar","/opt/demo.jar"]
Create Docker Image with Custom JDK
Your Dockerfile /Containerfile has always to begin with: FROM
.
This indicates a base image as you already commented.
A base image is in most cases a minimalistic type of OS like: ubuntu, alpine, ubi from redhat etc. and it provides a filesystem, package manager etc. Thus it is possible to use commands like wget, mkdir, as you have in your file.
Your main application starts with CMD <yourexe "param1" "parama2" ...>
After defining you Dockerfile you can create the image file with docker build
.
For Further information see:
https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
How to build a Docker container that starts a .jar and runs on a RaspberryPi 4B?
The problem is that the JRE still depends on the operating system and that depends on the platform architecture. The standard docker image for Java will most likely use a amd64/x64 based Linux OS with the appropriate JDK installed.
Raspberry PI, however, uses the ARM architecture, hence the output ARMv7 Processor rev 3 (v7l)
.
So you need an ARM-compatible image such as one of those: https://hub.docker.com/r/arm32v7/adoptopenjdk
I'm not sure how compatible ARM v7 and v8 are so I'd suggest you stick to the v7 images :)
Binding a local directory to java application container
The first thing is that you can't have spaces in the volume mapping option. I.e.
docker run --name mycontainer -v /users/myname/Desktop/OutputFolder : / myimage
should be
docker run --name mycontainer -v /users/myname/Desktop/OutputFolder:/ myimage
But that won't work because you're mapping your host directory onto the root of the image. When you do that, you 'hide' everything in the root directory and below it in the container, including your .jar file.
What you can do is map a single file onto the output file. As far as I can see, the file name of the output file in the container will be /SavedFile.xlsx
.
For this to work, the file must exists on the host before you start the container, so with the following 2 commands
touch /users/myname/Desktop/OutputFolder/SavedFile.xlsx
docker run --name mycontainer -v /users/myname/Desktop/OutputFolder/SavedFile.xlsx:/SavedFile.xlsx myimage
it should work and you should get your output in /users/myname/Desktop/OutputFolder/SavedFile.xlsx
on the host.
Is there a way to create docker image containing docker and java
In the past I solved the same issue writing the following Dockerfile
:
FROM maven:3.6.3-jdk-8
USER root
# Install docker CLI for docker images generation inside the container itself
RUN apt update -y
RUN apt install -y curl
RUN curl https://get.docker.com/builds/Linux/x86_64/docker-latest.tgz | tar xvz -C /tmp/ && mv /tmp/docker/docker /usr/bin/docker
# Customize here your container with your instructions...
Of course, you can change the FROM
image as per you needs.
Execute a simple java application using Docker
This happens, because you can't add any files to the Docker container from outside of the build context:
Extended description
The docker build command builds Docker images from a Dockerfile and a
“context”. A build’s context is the set of files located in the
specified PATH or URL. The build process can refer to any of the files
in the context. For example, your build can use a COPY instruction to
reference a file in the context.
Beside your Dockerfile
create a directory called jars
for instance, put your jar file, then:
ADD jars/DockerTesting-0.0.1-SNAPSHOT.jar /etc/test/
or simply you can copy all jars from there:
ADD jars/ /etc/test/
This way you should end up with a container having /etc/test/DockerTesting-0.0.1-SNAPSHOT.jar
inside. Anyway, any reason you put executables inside the /etc
directory? I mean this will work, but people expect to have system configuration files there only. More suitable location would be /var
or /usr/share
, or maybe even /app
;)
arm64 docker image built on arm64 machine (m1) does not create java runtime correctly with jlink
This is a duplicate of JLink does not produce redistributable image
TLDR, the linker expected by jlink was an x86 linker /lib64/ld-linux-x86-64.so.2
, however since the CPU that i'm attemping to run the jlink'ed jre on is an arm64 CPU, it does not have a x86 linker.
The root cause of this is the fact that I built the jre on an x86 github actions machine, and tried to run this on an arm64 machine.
At minium, it would be really nice to have an improved error message for this by the jdk teams.
One absolutely baffling error message is
bash: ./jre/bin/java: cannot execute binary file: Exec format error
If you found this question, here is where you can track our teams workarounds for this:
https://github.com/bitcoin-s/bitcoin-s/issues/4369
Related Topics
Java User.Home Is Being Set to %Userprofile% and Not Being Resolved
Execute Jsp Directly from Java
How to Use Classloader.Getresources() Correctly
Calling a Java Method to Draw Graphics
Java: Jackson Polymorphic JSON Deserialization of an Object with an Interface Property
Modifying Existing File Content in Java
How to Pause/Sleep/Wait in a Java Swing App
Jackson: How to Add Custom Property to the JSON Without Modifying the Pojo
What Is the Jvm Thread Scheduling Algorithm
Performance Difference Between Java 8 Lambdas and Anonymous Inner Classes
How to Execute .SQL Script File Using Jdbc
Looking for Java Spell Checker Library
Xml Element with Attribute and Content Using Jaxb
Can a Private Method in Super Class Be Overridden in the Sub-Class