Getting Started with Java Development on Docker

Nov 7, 2014

This week Anna, Stephan, Timo and myself were at W-Jax a big conference in Munich on enterprise technologies and especially Java. The interest in Docker and Giant Swarm was astonishing. One question that came up quite often was: How do I get started with Java development on Docker? Personally, I’m a friend of small examples - leveraging a minimal framework with a couple of files and off you go. Unfortunately this is hard to find in the Java world, since most examples require some sort of IDE and deep knowledge in the appropriate web framework. With this article I try to fill this gap. It gets you started with Docker and Java with minimal overhead and upfront knowledge.


The Setup


There are tons of Java web stacks and we are not picking sides here. But we wanted a very minimal framework and chose Spark, a tiny Sinatra inspired framework for Java 8. If you look at the documentation of Spark it uses Maven as its build tool.

In our example we will leverage Maven and Docker’s layered file system to install everything from scratch and at the same time have small turn around times when recompiling changes.

So the prerequisites you need: no Java, no Maven, just Docker. Crazy, eh? ;-)


The Source and Config Files


For our example you have to add three files:

  • The Maven config: pom.xml
  • A Java class: Hello.java
  • The Dockerfile

The TL;DR readers who can’t wait, can just clone this repo:

git clone https://github.com/giantswarm/sparkexample

For the rest we will go into some detail on the structure of these three files below.


pom.xml


The pom.xml file contains a very basic Maven configuration. It configures the Spark dependencies using a Java 1.8 compiler and creates a fat jar with all the dependencies. I’m in no way a Maven expert so pull requests to make this example simpler and more streamlined are more than welcome.


Hello.java


The assembly section of the pom.xml defines a main class that is called when the app starts: sparkexample.Hello. Lets create this file in the subdirectory src/main/java/sparkexample/:

As you can see this is modern Java code: it uses static imports and lambda expressions, which makes this example quite compact. The class contains a main method, with a response to a root request (“/”). As common with HelloWorld this response is just a simple string. Please consult the Spark documentation for further information on expressing different routes.

Dockerfile

Finally we have our Dockerfile:

FROM java:8 

# Install maven
RUN apt-get update
RUN apt-get install -y maven

WORKDIR /code

# Prepare by downloading dependencies
ADD pom.xml /code/pom.xml
RUN ["mvn", "dependency:resolve"]
RUN ["mvn", "verify"]

# Adding source, compile and package into a fat jar
ADD src /code/src
RUN ["mvn", "package"]

EXPOSE 4567
CMD ["/usr/lib/jvm/java-8-openjdk-amd64/bin/java", "-jar", "target/sparkexample-jar-with-dependencies.jar"]

The Dockerfile uses a plain Java image (java:8) and starts with installing Maven. In the next step it only installs the project dependencies. We do this by adding the pom.xml and resolving the dependencies. As you will see, this allows Docker to cache the dependencies. In the next step we actually compile and package our app, and start it.

If we now rebuild the app without any changes to the pom.xml, the previous steps are cached and only the last steps are run. This makes turnaround times much faster.


Building and Running


Once you have these three files in place, it is very easy to build the Docker image:

$ docker build -t giantswarm/sparkexample .

Note that this will take a while when you start it for the first time since it downloads and installs Maven and downloads all the project’s dependencies. Every subsequent start of this build will only take a few seconds, as again everything will be already cached.

Once the image is built, start it with:

$ docker run -d -p 4567:4567 giantswarm/sparkexample

And test it with:

$ curl localhost:4567
hello from sparkjava.com

Now go ahead and change something in the source (like returning your own message) and rebuild this… Isn’t it great!?


Conclusion


Although this a very basic example. I hope I got you started and hooked with Java development on Docker. I am looking forward to your comments and thoughts. What should we add to this example? Meanwhile get your hands dirty, fool around with the files, and leave comments and pull requests with improvement suggestions.

Bringing more realistic/complex examples into production (and scaling them) requires some more thought. We at Giant Swarm are working hard to make this next step as seamless as what you saw above. If you want to be one of the first to play around with it, sign up for our private beta list now.