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.
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-jdkI 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).
COPYGet your artifacts copied over. You could use
ADDbut based on the documentation https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#add-or-copy I went with COPY.
WORKDIRBest practice for setting the working directory https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#workdir
RUNJust 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.
EXPOSEPretty 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/
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
-pSelect 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
-itRuns as an interactive process https://docs.docker.com/engine/reference/run/ (so we see stuff stream by in the terminal).
-dRun 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 psI get a ton of millage out this command. Which will show you wants currently going on in docker.
docker statsThis 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 -aShows 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 #-----------------------------------
- A very helpful blog you might consider if you want to utilize maven more in the container creation step. https://blog.philipphauer.de/building-dropwizard-microservice-docker-maven/
- Docker cheat sheet https://github.com/wsargent/docker-cheat-sheet
- Docker build reference https://docs.docker.com/engine/reference/builder/
- Docker run reference https://docs.docker.com/engine/reference/run/
- Docker best practices https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices