JavaData & JavaUsing Java with Docker Engine

Using Java with Docker Engine

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Docker Engine is an all-in-one build platform for packaging, porting, and running containerized distributed applications. Docker Engine is similar to a virtual machine in that it runs on an OS kernel, but Docker is more different than similar to a virtual machine. Although a virtual machine encapsulates a whole of the guest OS kernel in addition to the application binaries and libraries, multiple Docker containers run in isolation on a single underlying OS kernel with each container having a lightweight encapsulation of the kernel with its own file system and networking. Another difference is that even though a virtual machine requires a hypervisor such as VirtualBox, which runs on the underlying OS with the guest OS running on top of the hypervisor, Docker Engine runs directly on the underlying OS Kernel. A Docker container includes the application binaries and all the required dependencies.

Docker01
Figure 1: Docker containers

A Docker container may be created and run using a Docker image, which is built from a Dockerfile. Software binaries are downloaded using a Docker image and a Docker container is created from the Docker image. A Dockerfile has a set of instructions to download software binaries, set environment variables, and run commands. A Dockerfile could inherit an instruction set from another Docker image using the FROM instruction. Most Docker images, including the openjdk image for Java, are based on a Linux OS Docker image. An interactive shell may be started on a Docker container that is created from a Docker image based on a Linux OS image and Linux commands run in the interactive shell.

In this tutorial, we shall run Java on Docker Engine and develop a Hello World Java application. We shall use the official Docker image for Java, the openjdk image. We shall discuss two methods to run Java in a Docker container:

  • Create a Docker container directly from the openjdk image, and
  • Create a Docker image based on the openjdk image for a Hello World Java application and create a Docker container from the Docker image for the Hello World application.

This tutorial has the following sections/sub-sections.

  • Setting the Environment
  • Pulling a Docker Image for Java
  • Using the openjdk Docker Image Directly
    • Running a Docker Container and Starting an Interactive Shell
    • Copying a Java Application to the Docker Container
    • Compiling and Running the Java Application
  • Creating a Docker Image for a Hello World Java Application
    • Creating a Dockerfile for a Java Application
    • Creating the Docker Image
    • Running the Dockerized Hello World Application
    • Starting an Interactive Shell on a Hello World Docker Container
    • Running the Java Application in the Interactive Shell
    • Running a Docker Container in Detached Mode for the Dockerized Hello World Application
    • Listing the Logs
  • Listing the Docker Images
  • Removing a Docker Container
  • Removing a Docker Image

Setting the Environment

Create an AWS EC2 instance from a CoreOS AMI. CoreOS is an OS designed for containers and Docker Engine is pre-installed on the OS. Another OS that supports Docker (https://docs.docker.com/engine/installation/) could also be used instead, but Docker would need to be installed on the OS. To create a CoreOS based AWS EC2 instance, refer to https://coreos.com/os/docs/latest/booting-on-ec2.html.

SSH login to the CoreOS instance and Docker Engine commands may be invoked directly with the “docker” command.

Docker02
Figure 2: Running the “docker” command

Pulling a Docker Image for Java

A Docker image should either be available on the local machine or from another repository such as Docker Hub to run a Docker container application. We shall be using the official Docker image openjdk available from the Docker Hub. A Docker container is run using the docker run command. A Docker image gets downloaded if not already not downloaded previously when the docker run command is run. Alternatively, a Docker image could be downloaded using the docker pull command. Download the openjdk Docker image using the docker pull command.

docker pull openjdk

Docker images are versioned using tags. The openjdk:latest image gets downloaded, which is the latest image for the openjdk image.

Docker03
Figure 3: The latest image

Subsequently, list the Docker images available on the local machine.

docker images

The openjdk image should get listed in addition to other images that may have been downloaded previously.

Docker04
Figure 4: The openjdk image

Using the openjdk Docker Image Directly

Next, we shall use the openjdk image to run a Hello World Java application. A Docker container may be run in one of two modes: background or foreground. The default mode is for a Docker container to run in the foreground. When run in the foreground, the Docker container process’s standard input, output, and error streams are attached to the console and output from the Docker container’s process may be viewed in the console. An interactive pseudo-tty may be started to interact with the application running in the Docker container. When run in the background with the -d option, the Docker container is not interacting with the command line from which the docker run command is run. An interactive pseudo-tty terminal may be started to connect to the Docker container’s process subsequently. The Docker container started in detached mode exits when the process used to start the Docker container exits.

Running a Docker Container and starting an Interactive Psuedo-TTY

To run a Docker container in the foreground and start a pseudo-tty, another pseudo-tty must not already be running on the command line console. Exit a tty if already running with the exit command. Start a Docker container with the docker run command and provide the -it options to keep STDIN open and start a psuedo-tty.

sudo docker run -it openjdk bash

A pseudo-tty gets started, from which application commands may be run to interact with the application running in the container.

Docker05
Figure 5: Starting the pseudo-tty

Because the openjdk Docker image is for Java, all the standard Java commands such as java and javac are available. Output the Java version with the java -version command.

Docker06
Figure 6: Output of the java -version command

Copying a Java Application to the Docker Container

We shall use a Hello World Java application in the tutorial. Copy the following listing to a file entitled HelloWorldApp.java.

class HelloWorldApp {
   public static void main(String[] args) {
      // Display the string.
      System.out.println("Hello World!");
   }
}

A pseudo-tty on a Docker container’s process does not directly support vi editor commands and a file cannot be created directly in the container. A file could be copied to the container using the docker cp command. To copy a command from the local machine to a Docker container, the command syntax is docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH. Obtain the Docker container ID from the tty command prompt.

Docker07
Figure 7: Obtaining the Docker container ID

Run the following command from the CoreOS command prompt to copy the Java application.

docker cp HelloWorldApp.java  c4393794390b: HelloWorldApp.java
HelloWorldApp.java

The Java application gets copied to the Docker container.

Docker08
Figure 8: Copying the Java application to the Docker container

List the files in the Docker container from the tty with the ls -l command and the HelloWorldApp.java should be listed.

Docker09
Figure 9: Listing the files in the Docker container

Compiling and Running the Java Application

Now that you have copied the Java application to the Docker container, compile the Java application.

javac HelloWorldApp.java

The application binaries file HelloWorldApp.class should get generated.

Docker10
Figure 10: Generating the application binaries file

Run the HelloWorld application.

java HelloWorldApp

The output from the application gets generated.

Docker11
Figure 11: Generating output from the application

Creating a Docker Image for a Hello World Java Application

The preceding discussion is one method to run a Java application on Docker Engine which is t first copy the application to a Docker container and subsequently run the application. But, if an application is much more bulky than a simple Hello World application a better option is to create a Docker image from the application and run a Docker container for the Docker image. As the application binaries are packaged in the Docker container copying of files to the Docker container is precluded. Next, we shall discuss creating a Docker image for the Hello World Java application and running the application in a container.

Creating a Dockerfile for a Java Application

A Dockerfile is a set of instructions or directives that could be used to build a Docker image. The Docker image would include all the application binaries including dependencies, and environment variable settings required to run a Docker container for the application.

First, set up the directory and file structure from which the Docker image is to be built. Create a directory (helloworld for example), set directory permissions to global (777), and change directory (cd) to the directory.

sudo mkdir helloworld
sudo chmod 777 helloworld
cd helloworld

The directory structure should be similar to the following; the directory name helloworld is arbitrary.

Docker12
Figure 12: Viewing the directory structure

Create a Java application file HelloWorldApp.java.

Docker13
Figure 13: Creating the Java application file

Create a file called Dockerfile and copy the following listing to the file.

FROM openjdk:7
COPY . helloworld
WORKDIR helloworld
RUN javac HelloWorldApp.java
CMD ["java", "HelloWorldApp"]

The directives in the Dockerfile are as follows.

Directive Discussion
FROM The base Docker image from which the new Docker image is to be built is set to opendjk
COPY The syntax is COPY <src>… <dest> and the directive copies the files and directories at the src path to the dest path within a Docker container’s file system.
WORKDIR Sets the working directory for any RUN, CMD, ENTRYPOINT, COPY, and ADD directives subsequent in the Dockerfile.
RUN Runs a command. In the example Dockerfilem the javac command is run to compile the Java application.
CMD Provides the defaults for a Docker container. The example Dockerfile runs the java command on the HelloWorldApp class.

The Dockerfile is shown in the vi editor.

Docker14
Figure 14: Viewing the Dockerfile in the vi editor

The file and directory structure should be as follows, with the helloworld directory as empty.

Docker15
Figure 15: Viewing the file and directory structure

Creating the Docker Image

The docker build command is used to build a Docker image using the instructions in the Dockerfile. The syntax to run docker build is as follows.

Docker16
Figure 16: The syntax to run docker build

For a complete set of options available to the docker build command, run the docker build -help command.

Docker17
Figure 17: Running the docker build -help command

Create a Docker image called “hello-world-app” from the source code at path “.”, which is the current directory, using the Dockerfile.

sudo docker build -f Dockerfile -t hello-world-app .

The Docker image hello-world-app gets built using the instructions in the Dockerfile.

Docker18
Figure 18: Building the Docker image

Running the Dockerized Hello World Application

The docker run command is used to run a Docker container for a Docker image. The following command runs a Docker container called hello-world-app (–name) from the Docker image hello-world-app and starts an interactive pseudo-tty (-it) on the container, and removes the container after it exits (–rm).

sudo docker run -it --rm --name hello-world-app
   hello-world-app

The Docker container for the Dockerized Hello World Application runs to output a message.

Docker19
Figure 19: Running the Hello World Application

Starting an Interactive Shell on a Hello World Docker Container

As an alternative to running a Docker container, we could start an interactive tty on the Docker container, which shall provide access to the binaries packaged in the Docker container’s file system. The following command starts an interactive bash shell on a Docker container:

sudo docker run -it hello-world-app bash

List the Docker container’s file system with ls -l and the HelloWorldApp binaries and application should get listed.

Docker20
Figure 20: Listing the Docker container’s file system

Running the Java Application in the Interactive Shell

The pseudo-tty provides access the same application commands as available to an openjdk Docker image container because the hello-world-app Docker image is built from the openjdk image. The java command may be run just as from a Linux OS on which Java has been installed.

Docker2
Figure 21: The Docker image

Run the HelloWorldApp with the following command.

java HelloWorldApp

The output message from the Java application gets generated.

Docker22
Figure 22: Generating the output message

Running a Docker Container in Detached Mode for the Dockerized Hello World Application

Previously, we ran the Docker container in the foreground and started an interactive tty on the container. But, a Docker container could also be run in detached mode with the -d option. The following command runs a Docker container called hello-world for Docker image hello-world-app in the background.

sudo docker run -d --name hello-world  hello-world-app

A Docker container gets started but no output is generated on the console because the container process’s standard output is not attached to the console.

Docker23
Figure 23: No output is generated

Listing the Logs

But, the Docker container runs nevertheless and generates an output that may be obtained from the logs for the container. The docker logs command is used to output a container’s logs. To get the logs for the hello-world container, run the following command:

docker logs hello-world

The message generated by the Docker container is output.

Docker24
Figure 24: Generating the output

Listing the Docker Images

The Docker images may be listed with the following command:

docker images

All the Docker images on the local machine get listed. The openjdk Docker image is listed twice with different tags, latest and 7.

Docker25
Figure 25: The Docker image is listed twice

Removing a Docker Container

All Docker containers, running and exited, may be listed with the following command:

docker ps -a

All Docker containers get listed. When not assigned a name explicitly, Docker containers get some default name generated by the Docker Engine. The exited containers have STATUS “Exited”.

Docker26
Figure 26: The Docker containers are listed

A Docker container may be removed with the docker rm command.

Docker27
Figure 27: Issuing the docker rm command

A Docker container must be stopped before removing the container. To remove all stopped containers, run the following command:

sudo docker rm $(sudo docker ps -a -q)

All stopped containers get removed.

Docker28
Figure 28: The stopped containers are removed

To remove only exited containers, the command is different.

sudo  docker rm -v $(sudo docker ps -a -q -f status=exited)

Removing a Docker Image

The docker rmi command is used to remove a Docker image. Remove the openjdk image with the following command:

docker rmi openjdk

The openjdk:latest Docker image gets removed. The tag “latest” is used if none is specified explicitly.

Docker29
Figure 29: The latest Docker image is removed

Similarly, remove the hello-world-app Docker image, which we created using a Docker file.

Docker30
Figure 30: Removing the hello-world-app Docker image

Listing the Docker images subsequently does not list the removed Docker images. A Docker image may be removed only if no Docker container using the image is running. At times, a Docker image may not get downloaded properly and a dangling image with REPOSITORY and TAG <none> gets listed.

Docker31
Figure 31: Listing a dangling image

The dangling Docker images may be removed with the following command:

sudo docker rmi $(docker images -f "dangling=true" -q)

All dangling Docker images get removed.

Docker32
Figure 32: Removing all dangling Docker images

Listing the Docker images subsequently does not list the dangling images.

Docker33
Figure 33: The dangling images are no longer listed

In this tutorial, we discussed using Java on Docker Engine with a Hello World application.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories