Docker has fast become a favorite deployment format. For those of you who haven't used Docker, Docker is "package once, run anywhere". Docker does for software what shipping containers do for tangible goods. It has standard connection mechanisms for disk and networking. Additionally, it's easy to link Docker 'containers' together (eg link database Docker container with your application).
Advantages and Disadvantages
Not only is it a win for system administrators as it makes deployment management easier and more easily automated, but it's a win for Java developers and architects too. As the applications environment is portable and is packaged with your application, environment-specific problems and defects are greatly reduced. What runs in production is more like what you test with. In addition since your application runs with its own version of java and the operating system, you can upgrade your JDK and any native code you rely on with less fear of impacting other applications or even involving system administrators to make the native software change.
Getting past the hype, there are costs and disadvantages to using Docker. Running Docker and its associated tools is much easier on Linux; Windows has limited support. This fact creates inconveniences in most corporate environments where most development occurs on Windows. Yes, there is boot2docker, but that solution is far from complete or convenient. Platform differences also present issues adding maven functionality to produce docker images; maven builds are supposed to be platform independent. Additionally, Docker does have a learning curve.
Some may fear performance issues with an additional virtualization layer. IBM did a good study showing the performance impact to be negligible. All in all, the advantages of using Docker outweigh the costs.
A Java EE / Docker Example
As it turns out, producing a deployable docker image for Java Web application is easy. I leverage a packaging product such as Dropwizard or Spring Boot to make such deployments even easier. That said, Tomcat and many other containers have official Docker images available, so this step isn't strictly required.
As an example, I'll use a microservice I'm writing for a series of presentations called Moneta, named after the Greek goddess of memory. Moneta provides a Restful web service interface to selected portions of a relational database.
Artifacts for the Moneta product include a Dropwizard deployment for which I've defined a Docker image, which I've open sourced (here). I'll briefly go through the example as you might find it useful.
Sample Docker File
FROM java:7-jre
MAINTAINER Derek C. Ashmore
# External volume definitions
RUN mkdir /jarlib
VOLUME /jarlib
RUN mkdir /config
VOLUME /config
RUN mkdir /logs
VOLUME /logs
ENV MONETA_URL https://github.com/Derek-Ashmore/moneta/releases/download/moneta-0.9.1-alpha/moneta-dropwizard-0.9.1-alpha.jar
RUN curl -SL "$MONETA_URL" -o moneta-dropwizard.jar
ENV CLASSPATH /config:/jarlib/*.jar:moneta-dropwizard.jar
EXPOSE 8080 8081
ENTRYPOINT ["java", "-classpath", "$CLASSPATH", "-jar", "moneta-dropwizard.jar", "server", "/config/moneta-dropwizard.yaml"]
Docker files are scripts that produce runnable Docker images. A couple of items to note. In a Docker file, you expose ports and disk volumes to the outside world. I've exposed certain ports within the Docker container, but system administrators can map those ports differently when the container is run. For example, admins might map 8080 to 9125. In other words, the admins still need to coordinate ports; that is still managed outside Docker.
Additionally, I've created and exposed three file mount points. Admins map those volumes to physical disk when they run the container. I've elected to make the product configurable and extensible. The configuration and even additional jars can be supplied when the container is run. I've also exposed a file system for logs so they can be processed by a log management application, such as Splunk or Logsplash.
Docker Application Run Example
Bottom line, it's possible to run the same Docker container in multiple contexts. I can run different instances of Moneta against different databases and can horizontally scale it ad infinitum.
These mappings become evident in the command used to run the Moneta image.
docker run -d -p 8080:8080 -p 8081:8081 \
-v /c/Users/TheAshmores/moneta/dropwizard/config:/config \
-v /c/Users/TheAshmores/moneta/dropwizard/logs:/logs \
-v /c/Users/TheAshmores/moneta/dropwizard/jarlib:/jarlib \
force66/moneta-dropwizard
There are other possibilities. Docker recently announced a product called 'Compose' (here) that allows you to specify and configure multi-container applications. This makes coordination of multiple containers much easier. A compose discussion is best left for another post.