Dockerize your Java Application

Garrett Sweeney
Cloud Tidbits
Published in
6 min readDec 6, 2018

As everyone and their brother moves to Kubernetes, its good to know how to Dockerize applications. This is a small tutorial on how to create a Dockerfile for a spring.io/guides project, build an image, push our image to dockerhub, and run our containerized application locally.

A quick word on Docker

Why Docker? It solves the problem of “it runs on my machine”. Instead of delivering jars, wars, whatever — you deliver “images”.

All someone needs to run your “image” on their machine is Docker installed.

This is awesome because the previous standard was to deliver artifacts, which means there was a dependency on environment setup and dependencies installed. But now, all of that is delivered in your image! “It runs on my machine” is now much much less of a thing.

Get Setup Locally

I’m working on a Mac, so I’ll give a short description on how I got set up. If you’re working on something else, this is all pretty google-able.

First, create an account on https://cloud.docker.com/. Navigate to the Repositories section. It will be empty of course, but be aware that this is where we’ll be pushing our images.

I then followed the instructions on the docker website to install docker for mac. It’s pretty simple, but you’ll have a whale available like below:

Look! A whale to the left

Anyway, click the whale and login with the same credentials you created when registering on cloud.docker.com.

Next, ensure that you have docker installed by running by checking with the following command in your terminal:

$ docker --version
Docker version 18.09.0-ce, build 4d60db4

Awesome, onward!

Clone a sample Java application

As I said in the introduction, I’m going to clone a sample spring.io/guides app. I’ll then build the Dockerfile to dockerize this java app.

Go ahead and clone the “Serving Web Content with Spring MVC” project:

git clone https://github.com/spring-guides/gs-serving-web-content.git

The spring guides have several projects buried into what you clone. Please navigate to the completed project and add an empty file in this directory called Dockerfile

cd ./complete
touch Dockerfile

I also enjoy seeing the structure of what I have cloned with tree . Your current directory should now look like this.

Another word on Docker

Before I start adding commands to the Dockerfile, let me give you the gist of what a Dockerfile does.

First, a Dockerfile always starts with another image called a “base-image”. This is the building block for our image, and examples include things like a red hat image or an Ubuntu image. This image can be as fat or as lean as you’d like, as we can add things to this image or build “layers”.

So, if you start with an image that already has Java installed, we won’t have to install Java later in the Dockerfile. If you don’t start with an image that is already installed, then we’ll have to install Java. At the end, this Dockerfile will be used to build another image. This final image (with all dependencies and your application added) can be delivered to those who want to run your application.

Building the Dockerfile

Like I just said, we have to choose an image to start with. I’m going to start with Ubuntu. To make our base image Ubuntu, add this line:

FROM ubuntu:latest

What’s latest? Images have tags. They are often versions, but “latest” will pull the latest published ubuntu image in DockerHub. And what’s DockerHub? A public registry of images available for your use!

Now we need to install a dependency, the jre (which is required on any machine to run a java application). Dockerfiles have a RUN command that we can utilize as if we were installing a jre on an ubuntu machine from the command line.

RUN \
# Update
apt-get update -y && \
# Install Java
apt-get install default-jre -y

Awesome, now our image has java installed.

Now, where is our jar file? If you remember our project structure, we have a java application locally. Let’s build it with mvn clean install . This should build your java application and put the jar in you ./target/gs-serving-web-content-0.1.0.jar directory.

And now that we know the relative path of our jar to our Dockerfile, we can utilize the Docker ADD command.

ADD ./target/gs-serving-web-content-0.1.0.jar spring-mvc-example.jar

This command adds the local ./target/gs-serving-web-content-0.1.0.jar artifact as spring-mvc-example.jar .

When our application is running, it is running on port 8080 . Lets use the docker EXPOSE command to open up that port.

EXPOSE 8080

And finally, let’s run the jar! Utilize the CMD docker command to run our jar.

CMD java -jar spring-mvc-example.jar

Altogether, your Dockerfile should look like this:

A third word on Docker

At this point I hope you realize the benefit of docker, as we can control the machine where our application is running.

Previously, we would pass along a jar file and hope that jar finds a place to live that is configured correctly.

We can now use this Dockerfile to generate an image that can deliver consistent behavior in any environment that supports Docker.

Let’s Build and Run the Image Locally

I’ll reiterate that we need to have our jar built at this point. If you have not built the java project, do so now:

java -version
mvn --version
mvn clean install

To build the image with the name spring-mvc-sample-image :

docker build . -t spring-mvc-sample-image

You can verify the image built correctly with docker images :

$ docker imagesREPOSITORY                TAG                 IMAGE ID            CREATED             SIZEspring-mvc-sample-image   latest              8fa27ad00edd        34 minutes ago      540MB

Now, let’s bring up a container called sample-mvc-sample-container based on your image spring-mvc-sample-image .

docker run -t -p 8080:8080 --name sample-mvc-sample-container spring-mvc-sample-image

You can add -d to your docker run command to run the container in the background. However, if you run the command above (with -t) you’ll find yourself in the container (and seeing the Spring application logs). With -t, you should see logs that say the application starts up correctly. With -d, you will have command docker ps -a to find your container and docker logs <container_id> to view the Spring application logs.

Use ctrl + c to exit the container. Now command docker ps -a .

$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
736f9cdc1499 spring-mvc-sample-image "/bin/sh -c 'java -j…" 2 hours ago Up 2 hours 8080/tcp sample-mvc-sample-container

There’s your container! Up and running. Just right there you have an ubuntu machine running your java application. If you want to go back inside the container running your java application, command docker exec -it <container-id> /bin/bash .

Finally, tag and push the Image to the public Dockerhub

First, list the image and find the one you built

$ docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEspring-mvc-sample-image latest 8fa27ad00edd 34 minutes ago 540MB

Next, tag the image by grabbing the image id(8fa27ad00edd) and tagging it with your docker username a name of your choice. My docker username is gsweene2 and the name I tag it with is gsweene2/spring-mvc-sample-image:0.1 . A docker tag consists of a name and a version , separated by a : .

docker tag 8fa27ad00edd gsweene2/spring-mvc-sample-image:0.1

Finally, push! Use the same name you tagged the image with, like gsweene2/spring-mvc-sample-image:0.1 .

docker push gsweene2/spring-mvc-sample-image:0.1

Find your image in DockerHub

You should be able to find it at cloud.docker.com after you log in, but the URL pattern appears to be:

https://cloud.docker.com/repository/docker/<username>/<image_name>

Any questions? This is documented well on the internet, but contact me at garrett.d.sweeney@gmail.com!

--

--