How to Build a Docker Container for a Java Application

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



Leave a reply



Submit