Skip to content

How to Dockerize Java Application

homepage-banner

In this guide, we will provide a step-by-step tutorial on how to Dockerize a Java Application. We will also cover best practices for using the Docker image in a production environment.

Prerequisites

To build a Java Docker image, you need to have the following prerequisites:

  1. Docker installed on your system.
  2. Java application JAR file that you want to Dockerize.

Build the Java JAR

If you already have your own Java application or JAR file, you can proceed to the next section.

If you are new to Java or need assistance in building a JAR file from a Spring Boot application, you can refer to our blog on building Java applications.

Alternatively, you can use the Java Petclinic Spring Boot application for testing purposes.

git clone https://github.com/techiescamp/java-spring-petclinic

cd java-spring-petclinic

mvn clean install -Dmaven.test.skip=true

Creating a Docker Image for a Java Application

To create a Docker image for a Java application, you first need to create a Dockerfile.

For this example, we will be using the base image techiescamp/jre-17:1.0.0.

Note: If you are unable to access the public Docker Hub registry, replace the base images with JRE base images provided by your organization’s private container registry.

Usually, the Dockerfile is placed in the application code folder. In this case, the application jar file would be located under the /target folder. If your jar file is in a different location, replace /target/*.jar with the actual path in the Dockerfile.

For example, the following tree shows that I have created the Dockerfile inside the application code folder, where I have the target folder containing the jar file.

.
├── Dockerfile
├── LICENSE.txt
├── pom.xml
├── readme.md
├── src
└──target

Now, create a Dockerfile in your application folder with the following content.

FROM techiescamp/jre-17:1.0.0
WORKDIR /app

# Copy the JAR file (/app)
COPY /target/*.jar ./java.jar

# Expose the port the app runs on
EXPOSE 8080

# Run the jar file
CMD ["java", "-jar", "java.jar"]

Here is an explanation of the Dockerfile:

  1. The ./app.jar instruction copies the JAR file(s) from the /target directory on the host machine to the /app directory inside the container. The JAR file(s) is then renamed to app.jar.
  2. This Dockerfile creates a Docker image using the eclipse-temurin:17-jre image as its base. It also copies the JAR file into the Docker image’s /app working directory.
  3. Additionally, it exposes port 8080 and uses the CMD instruction to run the JAR file.

Now, let’s build the Java application Docker image using the following command:

docker build -t java-application:1.0.0 .

Use the docker images command to list your Docker images, as shown below:

docker images

Once your Docker image build is finished, run the Docker image using the following command:

docker run -d -p 8080:8080 java-application:1.0.0

This command will run your Java application in a container. Make sure to change the port if you are using a different port.

Use the docker ps command to list the running containers, as shown below:

Now, check if your application is accessible in the browser using localhost:8080. I exposed my application on port 8080, so make sure to use the correct port number that you exposed.

Using Distroless Java Base Image

Here is an example Dockerfile that uses the Distroless Java base image from Google.

# Use the distroless Java base image
FROM gcr.io/distroless/java17-debian12

# Set the working directory in the container
WORKDIR /app

# Copy the JAR file into the container at /app
COPY target/*.jar java.jar

# Expose the port your app runs on
EXPOSE 8080

# Run the jar file
CMD ["java.jar"]

For the distroless Java image, the Entrypoint is set to java -jar by default. Therefore, we can directly use java.jar with the CMD as shown above.

Using Docker Multistage Build for a Java Application

With multistage build, you can build the Java application and dockerize it using a single Dockerfile.

Create a Dockerfile with the following content:

FROM techiescamp/jdk-17:1.0.0 AS build

# Copy the Java Application source code
COPY . /usr/src/

# Build Java Application
RUN mvn -f /usr/src/pom.xml clean install -DskipTests

FROM techiescamp/jre-17:1.0.0
WORKDIR /app

# Copy the JAR file from the build stage (/app)
COPY --from=build /usr/src/target/*.jar ./java.jar

# Expose the port the app runs on
EXPOSE 8080

# Run the jar file
CMD ["java", "-jar", "java.jar"]
  1. The above Dockerfile consists of two stages. The first stage is responsible for building the application, while the second stage runs the application.
  2. The first stage uses the base image techiescamp/jdk-17:1.0.0.
  3. The techiescamp/jdk-17:1.0.0 image includes JDK-17 and Maven-3.9.4, which are required for building the Java application.
  4. The Java application source code is copied and pasted into the /usr/src/ directory. Make sure to specify the path of your Java application source code.
  5. The application is then built using the mvn clean install command.
  6. The second stage uses techiescamp/jre-17:1.0.0 as its base image. It copies the JAR file from the build stage directory /usr/src/target/ to the current working directory /app with the name java.jar.
  7. Port 8080 is exposed, and the JAR file is executed using the java -jar command.

Now, build the image and run the container using the following command:

docker build -t java-application:2.0.0 .

Use the docker images command to list your docker image as given below

Once your Docker image build has been finished, run the Docker image using the command below

docker run -d -p 8080:8080 java-application:2.0.0

To run your Java application in a container, use the following command. If you are exposed to a different port, make sure to change the port accordingly.

To list the running containers, use the docker ps command.

Now, check if your application is running on the browser by accessing localhost:8080. In this example, I have exposed my application on port 8080, so make sure to use the port number you have exposed.

Best Practices

When working with Java application Docker images for production workloads, it is important to follow the Docker image best practices outlined below.

Lint Dockerfile

To check your Dockerfile for possible errors, security vulnerabilities, and performance problems, it is recommended to use Hadolint. Install Hadolint and run the following command to lint your Dockerfile:

hadolint Dockerfile

Ensure that you run this command in the same directory where your Dockerfile is located.

Scan for Vulnerabilities

Use tools like Trivy to scan Docker images for vulnerabilities. Install Trivy on your system and use the following command to scan your Docker image:

trivy image java-application:2.0.0

Replace java-application:2.0.0 with your Java Docker image.

Optimize Java Image Size

Optimizing Docker images is crucial in project environments.

In addition to following Dockerfile best practices and using distroless minimal images, you can also utilize the SlimToolkit to decrease the size of your Java Docker image.

To begin, create a preserved-paths.txt file that contains the names or paths of files you want to exclude from being removed during the slim run.

/app
/usr/bin/

In my txt file, I have specified the path to my application and the path where Java is installed. Now, run the following command to reduce the size of the Docker image using the txt file.

slim build --http-probe=false --preserve-path-file preserved-paths.txt java-application:2.0.0

This command will reduce the size of Docker images without affecting the file or file path mentioned in the txt file. If you check the size of the Docker image after executing this command, you will notice a significant reduction.

Versioning Docker Image

When tagging Docker images, it is recommended to use Semantic Versioning to ensure clarity and consistency in versioning practices. An example of a semantic version is 2.0.0.

java-application:2.0.0

You can also see that I used 1.0.0 for the first example image and 2.0.0 for the second example image.

Conclusion

I have covered most of the information and provided practical examples for Dockerizing a Java application.

In project environments, make sure to lint and run vulnerability scans before pushing to the registry. Usually, these tasks are taken care of by automated CI/CD pipelines.

Additionally, the choice of base image depends on the project requirements. It is recommended to use minimal base images whenever possible.

Reference

  • https://devopscube.com/dockerize-java-application/
Leave a message