How to Run Java in a Docker Container?



Docker allows you to set up Java environments that you can use in production and development servers alike. It enhances the efficiency and the manageability of executing Java programs. Irrespective of the underlying configurations, environment, and dependencies, Docker allows you to run Java programs reliably, and consistently across all the platforms. It greatly simplifies the deployment procedure as well and the problem of “it works only on my machine” is resolved.

You can run Java in Docker containers using the two main approaches discussed below −

  • You can use the official Java Docker base images provided by Oracle or AdoptOpenJDK.
  • You can create your own Docker images with custom dependencies tailored specifically for Java applications by using Dockerfiles.

In this chapter, we will explain both of these approaches to create and run Java applications inside the Docker container with the help of step-by-step instructions, commands, and examples.

Benefits of Using Docker Containers to Run Java Applications

There are several benefits associated with running Java applications inside Docker containers. They enhance the development and deployment workflows and improve scalability and reliability. Here are some of the key advantages of using Docker containers for Java applications.

  • Isolation − Ensures independent operation.
  • Consistency − Maintains uniform runtime environments.
  • Portability − Facilitates easy migration between environments.
  • Resource Efficiency − Maximizes resource utilization.
  • Scalability − Allows seamless adjustment to workload demands.

How to Run Java in Docker Using Java Base Images?

One of the easiest ways to run Java in Docker is by using the existing Java base images provided by trusted organizations like Oracle or AdoptOpenJDK. To do so, here are the steps and commands.

Step 1: Pull the Java Base Image

You can start by pulling the Java base image from Docker Hub using the Docker pull command. For example, if you want to pull the OpenJDK 11 image from AdoptOpenJDK, you can use the following command.

docker pull adoptopenjdk/openjdk11

Step 2: Run the Docker Container

Now that you have the base image pulled to your local, you can run the Docker container using the pulled image. You can specify the Java application JAR that you want to run inside the container and copy it to the container. To do so, you can use the following command.

docker run -d --name my-java-container -v 
   /path/to/your/jar:/usr/src/app/my-java-app.jar adoptopenjdk/openjdk11

In this command −

  • -d − This flag helps you to detach the container and you can run it in the background.
  • --name my-java-container − You can assign a name to the running container for your reference using this flag.
  • -v /path/to/your/jar:/usr/src/app/my-java-app.jar − This flag helps you to mount the directory that contains your Java application JAR into the container at /usr/src/app/my-java-app.jar.
  • adoptopenjdk/openjdk11 − This is the name of the base image that you want to pull.

Step 3: Access the Container's Bash

If you want to check whether Java is installed in the container that you created using the Docker image, you can access the bash shell of the container. To do so, you can use the following command.

docker exec -it my-java-container /bin/bash

In this command −

  • docker exec − It lets you execute a command inside a running container.
  • -it − It allocates a pseudo-TTY and helps keep the stdin open. This allows you to interact with the container's bash shell.
  • my-java-container − This is the name of the running container.
  • /bin/bash − This specifies the command that you want to execute inside the container. This command opens a bash shell inside the container.

Step 4: Check Java Installation

Now that you have access to the bash shell of the container, you can check if Java is installed by running the below command.

java -version

This command is used to display the version of Java and JDK that has been installed in the container. On running this command, if you see the information related to the Java version, it means Java is installed properly in the container.

Now that you have verified the successful installation of Java inside the container, you can exit the bash of the container by typing “exit” and pressing the enter key.

How to Use Dockerfile to Create Custom Java Images?

You can define your specific environment and run configurations for your Java applications using a Dockerfile to create and build Docker images. Here are the steps that you can follow to create a custom Docker image using Dockerfile.

Step 1: Create a Dockerfile

First, create a Dockerfile in the directory of your Java application. In the Dockerfile, we will mention the instructions to build image layers. Here’s a Dockerfile for a Docker image that has Java pre-installed in it −

# Use a base Java image
FROM adoptopenjdk/openjdk11:latest

# Set the working directory inside the container
WORKDIR /usr/src/app

# Copy the Java application JAR file into the container
COPY target/my-java-app.jar .

# Expose the port on which your Java application runs (if applicable)
EXPOSE 8080

# Command to run the Java application
CMD ["java", "-jar", "my-java-app.jar"]

In this Dockerfile −

  • FROM − You can use FROM to specify the base image to be used. In this case, we have used OpenJDK 11 from AdoptOpenJDK as the base image.
  • WORKDIR − This directive helps you to set the default working directory inside the Docker container where all the subsequent commands will be run.
  • COPY − It helps you to copy the Java application JAR file from your local directory into the container.
  • EXPOSE − This directive helps you to expose a particular port of the Docker container. You can adjust the port number based on your application's configuration.
  • CMD − You can use this directive to define the default command to be run when the container starts. In this case, we will execute the Java application JAR file.

Step 2: Build the Docker Image

Now that you have your Dockerfile ready, navigate to the path where your Dockerfile is located and run the Docker build command below to create the Docker image.

docker build -t my-custom-java-image .

In this command −

  • -t my-custom-java-image − The -t flag tags the Docker image with a custom name for meaningful future references.
  • Dot − The dot here specifies the build context. In this case, it is the current directory containing the Dockerfile.

Step 3: Run the Docker Container

You can check whether your image has been built successfully using the “docker images” command. If the image is built successfully, you can run a container for that image using the below command.

docker run -d --name my-java-container my-custom-java-image

In this command −

  • -d − This option detaches the container which helps you to run it in the background.
  • --name my-java-container − Similar to providing a name to an image, you can use it to provide a meaningful name to your container.
  • my-custom-java-image − This is the name of the image that you want to create and run a container for.

If you want to verify if the Java application is running as expected, you can run the “docker exec” command mentioned in the previous approach to access the bash shell of the container. You can then verify the log or check the active processes running inside the container.

Key Tips for Setting Up Java in Docker

No doubt, Docker helps you with the seamless setup, development, and deployment of Java applications. Here are a few tips that can enhance your experience of running Java in Docker.

  • Consider your application’s requirements and security before choosing the appropriate Java base image and other dependencies.
  • Optimize your Java runtime by managing the environment variables effectively. This includes memory settings, time zones, etc.
  • You can minimize redundant image pulls and installations of dependencies by leveraging the caching layer mechanisms of Docker image building.
  • Ensure that you regularly update the Docker images including Java versions, fix vulnerabilities, bug fixes, etc.
  • Try to minimize the image size to reduce the attack surface which further enhances security and lowers maintenance.

Frequently Asked Questions

Q1. How do I debug Java applications running in Docker containers?

You may debug Java applications that are running in Docker containers by setting up the Java Virtual Machine (JVM) to accept connections for remote debugging. To allow remote debugging, you can set the `JAVA_OPTS` environment variable within the Docker container and provide the JVM debug options (e.g., `-agentlib:jdwp`). Additionally, you must expose the debug port while launching the Docker container with the `-p` or `-P` flag (which is 5005).

Once configured, you can step through the code, set breakpoints, and inspect variables while connecting to the remote debugger from your command-line debugger or Integrated Development Environment (IDE). This makes it easier to identify and fix problems with Java applications running inside Docker containers.

Q2. How can I optimize the performance of Java applications running in Docker containers?

Several techniques are used to optimize the performance of Java applications operating in Docker containers in order to guarantee effective resource use and reduce overhead. One method is to carefully adjust the garbage collection and heap size of the Java Virtual Machine (JVM) according to the memory and CPU resources that are available. To adjust the maximum and initial heap sizes, respectively, you can use JVM options like `-Xmx` and `-Xms`.

You can also select the garbage collector (such as G1GC) based on the memory usage patterns of the application. Additionally, resource contention can be avoided and consistent Java application performance in Docker containers can be guaranteed by making use of Docker's resource constraints (such as memory and CPU limits) and isolating container workloads using container orchestration systems like Kubernetes.

Q3. How do I manage logging and monitoring for Java applications running in Docker containers?

Using logging frameworks (like Log4j, Logback) and monitoring tools (like Prometheus, and Grafana) to gather and examine application metrics and logs is part of managing logging and monitoring for Java applications running in Docker containers.

The Java application can be set up to write logs to standard error or output streams, which Docker then catches and sends to logging drivers (such syslog or JSON files) for centralized logging. Furthermore, you can use libraries such as Dropwizard Metrics or Micrometer to instrument your Java application with metrics, and then expose those metrics through JMX or HTTP endpoints for monitoring.

Advertisements