Redefine Java Virtualization Deployment with Docker

Last week, we shared with you "redefine the deployment of Java Virtualization with Docker (Foundation)", it is estimated that some small partners have long been unable to feel the feeling of anxious bar. Today, Xiyun and everyone to share in the docker in the deployment of java application of the actual case.


Dockerfile contains a series of instructions that tell Docker how to build a mirror that specifies the base point of the mirror, as well as configuring every detail of the mirror. The following is a Dockerfile example, which is a CentOS image of the Dockerfile.

Listing 1. CentOS Dockerfile

FROM scratch
MAINTAINER The CentOS Project <> - ami_creator
ADD centos-7-20150616_1752-docker.tar.xz /

Volumes for systemd

VOLUME ["/ run", "/ tmp"]

Environment for systemd

ENV container = docker

For systemd usage this changes to / usr / sbin / init

Keeping it as / bin / bash for compatibility with previous

CMD [& quot; / bin / bash & quot;]

Most of the content is a comment, there are four main commands:
1. <code> FROM scratch </ code>: All Dockerfiles are inherited from a base image. In this example, the CentOS image is inherited from the "scratch" image, which is the root of all mirroring. This configuration is fixed, indicating that this is one of the Docker's root images.
2. <code> MAINTAINER … </ code>: The <code> MAINTAINER </ code> directive specifies the owner of the mirror, and the owner of this example is CentOS Project.
3. <code> ADD centos … tar.xz </ code>: The <code> ADD </ code> directive tells Docker to upload the specified file to the image, and if the file is compressed, it will be unpacked path. In this example, Docker will upload a CentOS operating system Gzip package, and extract to the root directory of the system.
<Code> CMD ["/ bin / bash"] </ code>: Finally, the <code> CMD </ code> directive tells the Docker what command to execute, in which case the Bourne Again Shell (bash) terminal.
Now you know what Docker looks like, and then look at Tomcat official Dockerfile, Figure 2 illustrates the structure of this file.
This architecture may not be as simple as you think, but we will slowly learn it, in fact, it is very logical. The root of all Dockerfile mentioned above is <code> scratch </ code>, followed by the <code> debian: jessie </ code> image, which is based on standard mirroring, and Docker does not need to duplicate the invention Wheel, every time you create a new mirror, as long as based on a stable image to continue to build a new image can be, in this case, <code> debian: jessie </ code> is an official Debian Linux image, like the top Of CentOS, it has only three lines of instructions.

Code Listing 2. debian: jessie Dockerfile

FROM scratch
ADD rootfs.tar.xz /
CMD [&quot;/bin/bash&quot;]

In the above figure we also see the Dockerfile with two additional mirroring, CURL and Source Code Management, mirrored <code> buildpack-deps: jessie-curl </ code> as shown in Listing 3.

Listing 3. buildpack-deps: jessie-curl Dockerfile

FROM debian:jessie
RUN apt-get update &amp;&amp; apt-get install -y --no-install-recommends \
ca-certificates \
curl \
wget \
&amp;&amp; rm -rf /var/lib/apt/lists/*

Use the <code> apt-get </ code> in the Dockerfile to install the <code> curl </ code> and <code> wget </ code> so that the mirror can download the software from other servers. The <code> RUN </ code> directive causes Docker to execute a specific command in the running instance, in which case it updates all libraries (<code> apt-get update </ code>) and executes <code> apt -get install </ code> to install <code> curl </ code> and <code> wget </ code>.

<Code> buildpack-deps: jessie-scp </ code> The Dockerfile is shown in Listing 4.

Listing 4. buildpack-deps: jessie-scp Dockerfile

FROM buildpack-deps:jessie-curl
RUN apt-get update &amp;&amp; apt-get install -y --no-install-recommends \
bzr \
git \
mercurial \
openssh-client \
subversion \
&amp;&amp; rm -rf /var/lib/apt/lists/*

This Dockerfile installs source management tools such as Git, Mercurial, and Subversion.

Java Dockerfile will be more complicated, as shown in Listing 5.

Listing 5. Java Dockerfile

FROM buildpack-deps:jessie-scm

A few problems with compiling Java from source:

1. Oracle. Licensing prevents us from redistributing the official JDK.

2. Compiling OpenJDK also requires the JDK to be installed, and it gets

Really hairy.

RUN apt-get update & amp; & amp; apt-get install -y unzip & amp; & amp; rm -rf / var / lib / apt / lists / *
RUN echo 'deb jessie-backports main'> /etc/apt/sources.list.d/jessie-backports.list

Default to UTF-8 file.encoding

ENV JAVA_DEBIAN_VERSION 8u66-b01-1 ~ bpo8 + 1


And … 46872

RUN set -x \
& Amp; & amp; apt-get update \
& Amp; & amp; apt-get install -y \
Openjdk-8-jdk = & quot; $ JAVA_DEBIAN_VERSION & quot; \
Ca-certificates-java = & quot; $ CA_CERTIFICATES_JAVA_VERSION & quot;
& Amp; & amp; rm -rf / var / lib / apt / lists / *


RUN /var/lib/dpkg/info/ca-certificates-java.postinst configure

If you're reading this and have any feedback on how this image could be

Improve, please open an issue or a pull request so we can discuss it!

In a nutshell, the Dockerfile uses the security parameters to execute the <code> apt-get install -y openjdk-8-jdk </ code> to download and install Java, and the ENV directive configures the system's environment variables.

Finally, Listing 6 is Tomcat's Dockerfile .

Listing 6. Tomcat Dockerfile

FROM java:7-jre
ENV CATALINA_HOME /usr/local/tomcat
RUN mkdir -p &quot;$CATALINA_HOME&quot;


RUN gpg –keyserver –recv-keys \
05AB33110949707C93A279E3D3EFE6B686867BA6 \
07E48665A34DCAFAE522E5E6266191C37C037D42 \
47309207D818FFD8DCD3F83F1931D684307A10A5 \
541FBE7D8F78B25E055DDEE13C370389288584E7 \
61B832AC2F1C5A90F0F9B00A1C506407564C17A3 \
79F7026C690BAA50B92CD8B66A3AD3F4F22C4FED \
9BA44C2621385CB966EBA586F72C284D731FABEE \
A27677289986DB50844682F8ACB77FC2E86E29AC \
A9C5DF4D22E99998D9875A5110C01C5A2F6059E7 \
DCFD35E0BF8CA7344752DE8B6FB21E8933C60243 \
F3A04C595DB5B6A5F1ECA43E3B7BBB100D811BBE \
RUN set -x \
& Amp; & amp; curl -fSL & quot; $ TOMCAT_TGZ_URL & quot; -o tomcat.tar.gz \
& Amp; & amp; curl -fSL & quot; $ TOMCAT_TGZ_URL.asc & quot; -o tomcat.tar.gz.asc \
& Amp; & amp; gpg –verify tomcat.tar.gz.asc \
& Amp; & amp; tar -xvf tomcat.tar.gz –strip-components = 1 \
& Amp; & amp; rm bin / *. Bat \
& Amp; & amp; rm tomcat.tar.gz *
CMD [& quot; & quot ;, & quot; run & quot;]

Strictly speaking, Tomcat uses Java 7's parent Dockerfile (the default latest Java version is 8). This Dockerfile sets the <code> CATALINA_HOME </ code> and <code> PATH </ code> environment variables, and then creates the <code> CATALINA_HOME </ code> directory with the <code> mkdir </ code> WORKDIR </ code> instruction changes the current working path to <code> CATALINA_HOME </ code>, and the <code> RUN </ code> directive executes a series of commands on the same line:

  1. Download Tomcat Compression Pack.
  2. Download the file verification code.
  3. Verify that the downloaded file is correct.
  4. Unzip the Tomcat archive.
  5. Delete all batch files (we are running on Linux).
  6. Delete the archive file.

Writing these commands to the same line, corresponding to the Docker is a command, and finally the Docker will cache the results of the implementation, Docker has a strategy to detect when the mirror needs to be rebuilt, and verify the instructions in the construction process is correct. When a command changes the image, the Docker caches the results of each step, and the Docker can start the mirror of the last correct instruction.

The <code> EXPOSE </ code> directive causes Docker to expose the specified port when it starts a container. As we did before we started, we need to tell the Docker which physical port will be mapped to the container (<code> -p </ code > Parameter), the role of <code> EXPOSE </ code> is the definition of the Docker container port. Finally, Dockerfile starts Tomcat using the script.


Simple review

Using Dockerfile to build Tomcat from scratch is a long process, we sum up the steps so far:

  1. Install Debian Linux.
  2. Install curl and wget.
  3. Install the source management tool.
  4. Download and install Java.
  5. Download and install Tomcat.
  6. Exposure to the Docker instance on port 8080.
  7. Start Tomcat with

Now you should become a Dockerfile expert, and the next step we will try to build a custom Docker image.

Deploy custom application to Docker

Because the main concern of this guide is how to deploy Java applications in Docker, rather than the application itself, I will build a simple Hello World servlet. You can get this project from GitHub , the source code is nothing special, just a servlet that outputs "Hello World!" More interesting is the corresponding Dockerfile , as shown in Listing 7.

Code Listing 7. Dickerfile for Hello World servlet

FROM tomcat
ADD deploy /usr/local/tomcat/webapps

May not look the same, but you should be able to understand the role of the above code is:
* <Code> FROM tomcat </ code> indicates that this Dockerfile is built on Tomcat-based mirroring.
* <Code> ADD deploy </ code> tells Docker to copy the "deploy" directory from the local file system to the / usr / local / tomcat / webapps path in the Tomcat image.

Compile the project locally using the maven command:

mvn clean install

This will generate a war package, target / helloworld.war, copy the file to the project's docker / deploy directory (you need to create it first), and finally you will use the top Dockerfile to build the Docker image, in the project docker directory Execute the following command:

docker build -t lygado/docker-tomcat .

This command causes Docker to build a new image from the current directory (indicated by the dot number) and tagged <code> lygado / docker-tomcat </ code> with "<code> -t </ code>", in this example , Lygado is my DockerHub username, docker-image is the mirror name (you need to replace it with your own username). To see if the build is successful you can execute the following command:

$ docker images
lygado/docker-tomcat latest ccb455fabad9 42 seconds ago 849.5 MB

Finally, you can load the mirror with the following command:

docker run -d -p 8080:8080 lygado/docker-tomcat

After this instance is started, you can use the following URL access (replace the IP in your URL with your virtual machine's IP):


Or that way, you can use the container ID to terminate this instance.

Docker push

Once you have built and tested your Docker image, you can push this image to your DockerHub account:
docker push lygado/docker-tomcat

In this way, your mirror can be accessed by the world, of course, for privacy, you can also push to the private Docker warehouse.
In the following, we will integrate the Docker into the application's build process, with the goal of producing a Docker image that contains the application after the build application is complete.

Integrate Docker into the Maven build process

In the previous section, we created a custom Dockerfile and deployed the WAR package to it. This means copying the WAR package from the target directory of the project to the <code> docker / deploy </ code> directory and running the docker from the command line. This is not how much effort, but if you need frequent changes and test the code, you will find this process is very cumbersome. And if you need to build an application on a CI server and produce a Docker image, you need to figure out how to integrate Docker and CI tools.

Now we try a more efficient way to build a Docker image using the Maven and Maven Docker plugins.

My use case has these:
1. You can create a Tomcat-based Docker image for deploying my application.
2. can be built in the test.
3. Can be integrated into pre-integrated testing and post-integration testing.

Docker-maven-plugin can meet these needs, and easy to use and understand.

About the Maven Docker plugin

The plugin itself has a good document , here special about the two main components:

  1. Configure the Docker mirror to build and run in POM.xml.
  2. Describe which files to include in the mirror.

Listing 8 is a configuration of the plugins in POM.xml, which defines the configuration of the mirror and the configuration of the run.

Listing 8. POM file build section, Docker Maven plug-in configuration

&lt;dockerHost>tcp://;/dockerHost> &lt;certPath>/Users/shaines/.docker/machine/machines/default&lt;/certPath>

As you can see, this configuration is fairly simple and contains the following elements:

Plug-in definition

<Code> groupId </ code>, <code> artifactId </ code> and <code> version </ code> This information specifies which plugin to use.

Global Settings

The <code> dockerHost </ code> and <code> certPath </ code> elements define the location of the Docker host, which is used to start the container and specify the Docker certificate. The path to the Docker certificate is visible in the <code> DOCKER_CERT_PATH </ code> environment variable.

Mirror settings

All <code> image </ code> elements under the <code> build </ code> element are defined under the <code> images </ code> element, and each <code> image </ code> element is mirrored The configuration is the same as the configuration of <code> build </ code> and <code> run </ code>. The main configuration is the name of the mirror. In this case, it is my DockerHub username (<code> lygado </ Code>), the name of the mirror (<code> tomcat-with-my-app </ code>) and the mirror version number (0.1). You can also use Maven properties to define these values.

Mirror build configuration

When building a mirror, we use the <code> docker build </ code> command, and a Dockerfile to define the build process. The Maven Docker plugin also allows you to use Dockerfile, but in the example, we use a runtime to build Dockerfile in memory to build. Therefore, we define the parent image in the <code> from </ code> element, which is tomcat and then other configuration in <code> assembly </ code>.

Using Maven's <code> maven-assembly-plugin </ code>, you can define the output of a project, specifying a dependency, module, document, or other file into a separate distributed package. <Code> docking-maven-plugin </ code> inherited this standard. In this example, we chose the <code> dir </ code> mode, which is defined in the <code> src / main / docker / assembly .xml </ code> will be copied to the baseir in the Docker image. Other modes include <code> tar </ code>, <code> tgz </ code>, and <code> zip </ code>. The <code> basedir </ code> element defines the path to the placement file, which is Tomcat's webapps directory.

Finally, the <code> descriptor </ code> element specifies the <code> assembly </ code> file, which is located in <code> src / main / docker </ code> defined in <code> basedir </ code> The Above is a very simple example, I suggest that you read the relevant documents, in particular, you can understand the <code> entrypoint </ code> and <code> cmd </ code> elements, these two elements can be specified to start the Docker mirror Command, the <code> env </ code> element can specify an environment variable, and the <code> runCmds </ code> element is similar to the <code> RUN </ code> directive in the Dockerfile. The <code> workdir </ code> Working path, the <code> volumes </ code> element can specify the disk volume to mount. In short, this plugin implements the syntax required in all Dockerfile, so the Dockerfile directive used earlier can be used in this plugin.

Mirror run configuration

The <code> docker run </ code> command is used to start the Docker image, and you can pass some parameters to the Docker. In this example, we will use the <code> docker run -d -p 8080: 8080 lygado / tomcat-with-my-app: 0.1 </ code> command to start the mirror, so we only need to specify the port mapping.

The run element allows us to specify all runtime parameters, so we specified 8080 to map the 8080 in the Docker container to the Docker host. Alternatively, you can specify the volume to be mounted (using <code> volumes </ code>) in the run, or the container to be linked (using <code> links </ code>). <Code> docker: start </ code> is very common in the integration test, in the run section, we can use the wait parameter to specify a time period, so you can wait for a log output, or a URL is available Continue to go on, so you can ensure that the integration test before the start of the mirror has been running up.

Loading dependencies

The <code> src / main / docker / assembly.xml </ code> file defines which files need to be copied to the Docker image, as shown in Listing 9:
Listing 9. assembly.xml

&lt;assembly xmlns=&quot;;

In Listing 9, we can see a dependency collection containing <code> hello-world-servlet-example </ code>, and the destination path of the replication, <code> outputDirectory </ code> The previously mentioned <code> basedir </ code> is Tomcat's webapps directory.

This plugin has the following Maven targets:
1. docker: build: build mirror
2. docker: start: start the mirror
3. docker: stop: stop the mirror
4. docker: push: push the image to a mirror repository, such as DockerHub
5. docker: remove: delete the mirror locally
6. docker: logs: Output container logs

Build a mirror

You can get the source code from GitHub and build it with the following command:
mvn clean install

Build the Docker image with the following command:
mvn clean package docker:build

Once the mirror is built successfully, you can see in the return code of the <code> docker images </ code>
$ docker images
lygado/tomcat-with-my-app 0.1 1d49e6924d19 16 minutes ago 347.7 MB

You can start the mirror with the following command:

mvn docker:start

It can now be seen in <code> docker ps </ code>, which can then be accessed at the following URL:

Finally, you can stop the container with the following command:
mvn docker:stop

to sum up

Docker is a container virtualization technology that provides a series of Docker client commands to invoke the Docker daemon. On Linux, the Docker daemon can run directly on the Linux operating system, but on Windows and Mac, you need a Linux virtual machine to run the Docker daemon. The Docker image contains a lightweight operating system, and additionally contains the dependencies that the application runs. The Docker image is defined by Dockerfile and can contain a series of instructions for configuring mirroring in the Dockerfile.

In this open source Java project guide, I introduced the basis of Docker, explained CentOS, Java, Tomcat and other mirror Dockerfile details, and demonstrated how to use Tomcat mirror to build a new image. Finally, we use the docker-maven-plugin to integrate the Docker into the Maven build process. In this way, the test is made simpler, and the build process can be deployed on the CI server to the production environment.

The example application in this article is very simple, but the building steps involved can also be used in more complex enterprise applications. Enjoy the fun of Docker.

Thank you for reading this article! Thursday we will continue to share docker technical articles, please stay concerned!

For more information on docker, please watch the training video: !

If you need docker related products, please visit Xiyun official website Home: !

    Heads up! This alert needs your attention, but it's not super important.