Packaging a Java Application in a Docker Image with Maven

By | February 14, 2017

In this article I am going to show how to build a Docker image containing a Java application using Maven. As an example, I will use a Spring Boot web application, which will be packaged into a Docker image. The application packaged does not need to be a Java application, but can be anything for which a Docker image can be created. I have, for instance, used the process described to make it possible to build regular Docker images on a Jenkins build server.

The Example Spring Boot Application

The Spring Boot web application I will use as an example Java application is created as follows:

  • Use this Spring Initializr link to generate the bare-bones Spring Boot web project with Thymeleaf templating support.
  • Open the Spring Boot project in your favourite IDE.
  • In src/main/java in the package se.ivankrizsan.spring, create a package named “controllers”.
  • In the new package, implement the class HelloController as this:

  • In src/main/resources/templates, create a file named hello.html with the following contents:

The example application can now be started by running the SpringbootDockerimageApplication class. To test the application, enter the http://localhost:8080/hello?name=Ivan URL in a local browser. There should be a greeting in the browser window on the following format:

Prepare for Docker Image Creation

Setting up to create a Docker image for a Java application consists of two steps; the first step is much like for any Docker image in that a Docker file is created and the static contents of the Docker image is gathered/created. The second part consists of adding a Maven profile to the project’s pom.xml file.

Docker Directory and Its Contents

The Docker file and any additional static contents of the Docker image is created in the source of the project. In this example it is in the src/main/resources/docker directory. The location of this directory can be changed by modifying a property, as we will see later.

  • Create a directory named “docker” in the src/main/resources directory.
  • In the src/main/resources/docker directory, create a directory named “application”.
  • In the src/main/resources/docker/application directory, create two directories named “bin” and “lib”.
  • In the src/main/resources/docker/application/bin directory, create a file named “start-app.sh” with the following contents:

  • In the src/main/resources/docker directory, create a file name “Dockerfile” with this contents:

Modify the Dockerfile accordingly if, for instance, you want to use another base image.

Maven Profile

To create the Docker image containing the Spring Boot application, I’ll use the following Maven plug-ins:

  • maven-resources-plugin
    Copies files to a directory in which the Docker image will be built.
    The files needed to build the Docker image are copied to a directory in the target directory of the project.
  • maven-dependency-plugin
    Copies the JAR file containing the application and any additional Maven artifacts to the Docker image build directory.
  • Spotify’s docker-maven-plugin
    Removes the Docker image produced by the project. Needed since, at the time of writing, the Maven plug-in used to build the Docker image will not overwrite an existing Docker image.
  • Spotify’s dockerfile-maven-plugin
    Builds the Docker image.

In the project’s Maven pom.xml file, I use a Maven profile to contain what is needed to build the Docker image. I have tried to rely on properties in the profile for configuration of the Docker image build in order to make it easier to adapt the profile to different Java applications.

The complete Docker image building Maven profile looks like this:

If we look at the different parts of the Maven profile, we can see:

  • There is a <dependencies> element.
    Add any additional Maven dependencies to, for instance, third party libraries that you want to include in the Docker image in this element.
  • In the <properties> element, there is a property named docker.image.name.
    This property contains the name of the Docker image that will be produced. I expect this property to be modified for each application. The Docker image tag will be the project’s version.
  • The next property in the <properties> element is docker.image.src.root.
    This property holds the relative path to the directory that contains the Dockerfile and any additional static contents that is to be included in the Docker image.
  • The final property in the <properties> element is docker.build.directory.
    This property holds the path to the directory in which the Docker image will be built.
  • In the <build> section of the profile, the first plug-in is the maven-resources-plugin.
    This plug-in is used to copy static contents from the directory pointed at by the docker.image.src.root property to the directory which location is specified by the docker.build.directory property. The entire directory structure is preserved.
  • The second plug-in in the <build> section is the maven-dependency-plugin.
    Using this plug-in, the JAR file that contains the Spring Boot application built by the project is copied to the application/lib directory in the directory in which the Docker image will be built. Recall that the location of the application JAR file is also stored into the environment variable JAR_PATH in the Dockerfile.
    Note that a destination filename is specified for the application JAR, in order to have a fixed filename to refer to in the Dockerfile.
  • The third plug-in in the <build> section is the docker-maven-plugin.
    Since the current version of the dockerfile-maven-plugin that we will discuss later does not overwrite existing Docker images, I have included this plug-in to be able to remove any existing Docker image when cleaning the Maven project.
  • The final plug-in is the dockerfile-maven-plugin.
    This is the plug-in that is responsible for building the Docker image. The main reason that I chose this plug-in over the alternatives is that it allows me to create a Docker image from a Dockerfile – just like it works when I am creating Docker images by hand.

Create the Docker Image

If we now open a terminal window and go to the directory that contains the pom.xml file of the example Spring Boot web application, we can build the Docker image using this Maven command:

After some time, the message BUILD SUCCESS should appear in the terminal and if you list the Docker images, you should see the new image listed:

Use the Docker Image

To start a Docker container using the newly produced Docker image, I use the command:

Opening the URL http://localhost:8080/hello?name=Ivan  (replace localhost with the appropriate IP if you run Docker in a virtual machine) in a browser, I see the same type of greeting that I saw when I was running the Spring Boot web application outside of the Docker container.

Happy coding!

Leave a Reply

Your email address will not be published. Required fields are marked *