Dropwizard in a Docker Container

Dropwizard Dec 29, 2016

This is a basic walk-through of taking a Dropwizard service and running it in a Docker Container. We are not going to cover a full fledged deployment system, but at the end you should be able to bounce requests off of your java service running in production.

What should you get from this post?

  • Some pointers to my favorite resources for Docker.
  • The basics Docker stuff to build an image with your Dropwizard service.
  • Explanation of the important bits and some helpful pointers.

What it is not:

  • Not a production ready deployment system. This guide is only meant as an initial walk-through to gain familiarity with the major tools.
  • Automated anything - this is intended to be a guide for getting your hands dirty.

What You Need to Start

This guide assumes:

  • Running on a linux system (for dev and production). OSX cats may need to jump through special hoops, but I doubt it.
  • I chose Ubuntu 16.04 for my dev and live environment.
  • A digital ocean droplet is used as a test bed to validate the system. I don't get payed by digital ocean, I just love their service. Especially when I want a little more control than Heroku where I host my other side projects.
  • You can totally skip this step, I chose to verify my system by also confirming that it could run on one of the popular hosts. This will serve as a jumping off point for my future experiments if I decide to try kubernetes or I just want to try horizontally scaling for performance testing.
  • You already went through my previous post on Dropwizard and you have a Dropwizard fat shaded jar that you are ready to fire up.

I Highly recommend going through the initial docker tutorial https://docs.docker.com/engine/getstarted/ It will help you get docker install locally, and it will take you through the basics of the verbiage, building an image, and running it.

Step 1

Assuming you have a Dropwizard service you can start like java -jar target/dropwizard-sample-0.0.1-SNAPSHOT.jar server hello-world.yml and you have docker engine running locally.

Lets create a Dockerfile that will tell Docker how to build the image. You would go ahead and place this is the root of your project directory

FROM openjdk:8-jdk

COPY hello-world.yml /data/dropwizard-sample/hello-world.yml
COPY /target/dropwizard-sample-0.0.1-SNAPSHOT.jar /data/dropwizard-sample/dropwizard-sample-0.0.1-SNAPSHOT.jar

WORKDIR /data/dropwizard-sample

RUN java -version

CMD ["java","-jar","dropwizard-sample-0.0.1-SNAPSHOT.jar","server","hello-world.yml"]

EXPOSE 8080-8081
Step 1 Explanation
  • FROM openjdk:8-jdk I chose this as a base image hub.docker.com openjdk

  • This looked like the most popular image on hub.docker.com. I am not going to pull punches here, I don't know how I feel about the state of https://hub.docker.com/ I will leave it up to the reader, but I don't get the sense of a vibrant community (maybe that's just because everyone else build their own java containers from scratch and I am noob).

  • COPY Get your artifacts copied over. You could use ADD but based on the documentation https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#add-or-copy I went with COPY.

  • WORKDIR Best practice for setting the working directory https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#workdir

  • RUN Just a basic sanity check of the Java version. You can omit.

  • CMD ["java","-jar","dropwizard-sample-0.0.1-SNAPSHOT.jar","server","hello-world.yml"] This is where things get interesting. Based on the best practices guide, I pass in the executable and all the parameters.

  • I initially farted around with using RUN here, but it was largely unsuccessful once I wanted the container to run in the background.

  • EXPOSE Pretty self explanatory, just expose the ports that matter to your dropwizard service 8080 for the main resources and 8081 for the admin stuff.

Step 2 - Build

From the root of your project, your going to want to run

# Replace with your desired tag.
docker build -t <INSERT-YOUR-TAG> .

Nothing really crazy is going on here, you should pick your own tag to use, I used docker build -t dropwizard-skeleton-test .. If you want more info on the build command https://docs.docker.com/engine/reference/commandline/build/

Example results:

Sending build context to Docker daemon 20.26 MB
Step 1 : FROM openjdk:8-jdk
 ---> 861e95c114d6
Step 2 : COPY hello-world.yml /data/dropwizard-sample/hello-world.yml
 ---> Using cache
 ---> f74a54fd6d5d
Step 3 : COPY /target/dropwizard-sample-0.0.1-SNAPSHOT.jar /data/dropwizard-sample/dropwizard-sample-0.0.1-SNAPSHOT.jar
 ---> dcd989b2e229
Removing intermediate container 52aaaeb47ba1
Step 4 : WORKDIR /data/dropwizard-sample
 ---> Running in 5060db706738
 ---> 2189981a3656
Removing intermediate container 5060db706738
Step 5 : RUN java -version
 ---> Running in d39ca2cbcadc
openjdk version "1.8.0_111"
OpenJDK Runtime Environment (build 1.8.0_111-8u111-b14-2~bpo8+1-b14)
OpenJDK 64-Bit Server VM (build 25.111-b14, mixed mode)
 ---> fc6e3bd4b45a
Removing intermediate container d39ca2cbcadc
Step 6 : CMD java -jar dropwizard-sample-0.0.1-SNAPSHOT.jar server hello-world.yml
 ---> Running in 2a41cd8a570f
 ---> f34ac176ea4a
Removing intermediate container 2a41cd8a570f
Step 7 : EXPOSE 8080-8081
 ---> Running in dc7d956daff7
 ---> 2e609cece81a
Removing intermediate container dc7d956daff7
Successfully built 2e609cece81a

Step 3 - Run

Now it is time to run the container.

# Run locally in interactive mode
docker run -p 8080:8080 -it dropwizard-skeleton-test

# Run in detached mode (you will need to look to docker see the log/stdout stream.
docker run -d -p 8080:8080 dropwizard-skeleton-test
  • -p Select the port you want to expose with the first port being the one you want to expose on the host machine, and the second being the port the service in the container is expecting.

  • Example if you wanted to serve 7070 and 7071 on the host machine, but didn't want to take the time to change the default 8080 on dropwizard, you could use something like -p 7070-7071:8080-8081

  • -it Runs as an interactive process https://docs.docker.com/engine/reference/run/ (so we see stuff stream by in the terminal).

  • -d Run in detached mode (runs in the background).

Step 4 - Validate

I am a big fan of the cheat sheet https://github.com/wsargent/docker-cheat-sheet

  • docker ps I get a ton of millage out this command. Which will show you wants currently going on in docker.

  • docker stats This will give a quick and dirty view into current behavior of our containers (CPU/MEM/IO).

  • docker start <container> and docker stop container

  • docker ps -a Shows all the containers, even if they aren't running. Maybe you want to cleanup some old ones? https://coderwall.com/p/ewk0mq/stop-remove-all-docker-containers

Step 5 - Run on Remote Host

Since I am still relatively new to Docker and I don't have a strategy for deployment (at least in the context of these posts). I am going to go ahead and just scp the stuff I need over to my remote host and build the image there. I could totally build it locally and send the container, or publish it to a container repo... but I wanted to see things start to dance before I go down that rabbit hole.

# Move the JAR
scp target/dropwizard-sample-0.0.1-SNAPSHOT.jar root@INSERT_YOUR_DESTINATION_IP:/root/container-test
# Move your yml file.
scp hello-world.yml root@INSERT_YOUR_DESTINATION_IP:/root/container-test

Once there you should be able to easily re-run steps 2-3 from in the /root/conatiner-test directory.

Apologies if this feels like a cop out, I will hopefully come up with a strategy for this that is worth sharing in the context of a basic blog post.

Cheat Sheet - Helpful Command Reference

# Clean up java env and construct a new artifact.
mvn clean package
# Fire up your shaded jar locally.
java -jar target/dropwizard-sample-0.0.1-SNAPSHOT.jar server hello-world.yml

Additional Resources