Example based explanation about Docker

“It makes deployment easier”, “It makes environments more equal to each other”, “It is just a trend”. These are some quotes people give to the phenomena Docker. In this tutorial, I show some basic things with Docker.

But first; What the hell is Docker? Docker is a light weight opensource framework to package an application in a container. The purpose of this container is that it can runs anywhere (in the cloud, on your own computer or in your own datacenter) without configuring each environment seperately. The idea behind this principle is that the container contains everything; your application, the configuration of your applications, shares and also a OS, which is mainly Linux.

The advantage of using Docker over traditional VM wares is resource management. Each VM ware contains an complete OS installation. However, I also stated above that a docker container contains the OS. This is true, but this is also one of the main differences; A docker container contains a subset of the linux kernel; cgroups and namespaces. By using containers, resources could be isolated. This means that you can limit a container to use a max CPU load, I/O load or memory usage. In a traditional VM ware architecture, an hypervisor is used to create and manage VM’s. Docker containers manages themselves, it doesn’t require an hypervisor. This also spares resources. The image below shows the difference between a VM architecture (left) and a container architecture (right).

In this tutorial, I show how to setup, create a docker image and create a container from this image. I have the following setup:

  • Mac OSX; however, you can also use Windows or Linux if you want 🙂
  • Java combined with Vertx. Vertx is a reactive java framework. More information about this: https://vertx.io
  • I use Maven to manage my java libraries. I also use a Maven plugin to create a Docker image. One of the advantages of this setup is that it also makes it easy to use in build tools like Jenkins. I use the Netbeans IDE, but you can also use other Java IDE’s with Maven support like Eclipse or IntelliJ.

First, you need to install Docker. The installation could be found at: https://docs.docker.com/engine/installation/ and follow the instructions. For this tutorial, the community edition is enough.

For this tutorial, I created a simple application with Vertx. The code starts an webserver at port 8080 and shows a message when you browse to the given URL. Below, you see the java code. Like traditional maven projects, the code should be places under src/main/java/nl/example

package nl.example;

import io.vertx.core.AbstractVerticle;

public class MainVerticle extends AbstractVerticle {

    @Override
    public void start() throws Exception {
        vertx.createHttpServer().requestHandler(req -> {
              req.response()
                 .putHeader("content-type", "text/plain")
                 .end("Test from Ewout Reinders");
            }).listen(8080);
        System.out.println("HTTP server started on port 8080");
    }
}

Secondly, we need to setup the Maven POM. Below you see the Maven POM

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>nl.example</groupId>
    <artifactId>ewout-vtx-example</artifactId>
    <version>1.0.0-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <vertx.version>3.5.0</vertx.version>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            
            <!-- Maven shade plugin to create a 
                 MANIFEST for the given Vertx verticle -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.4.3</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                          <transformers>
                              <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                  <manifestEntries>
                                      <Main-Class>io.vertx.core.Launcher</Main-Class>
                                      <Main-Verticle>nl.example.MainVerticle</Main-Verticle>
                                  </manifestEntries>
                              </transformer>
                              <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                  <resource>META-INF/services/io.vertx.core.spi.VerticleFactory</resource>
                              </transformer>
                          </transformers>
                          <artifactSet>
                          </artifactSet>
                          <outputFile>${project.build.directory}/${project.artifactId}-${project.version}-fat.jar</outputFile>
                      </configuration>
                    </execution>
                </executions>
            </plugin>
            
            <!-- Used for Netbeans IDE to startup the application without 
                 docker container, for development purposes -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.5.0</version>
                <configuration>
                    <mainClass>io.vertx.core.Launcher</mainClass>
                    <arguments>
                        <argument>run</argument>
                        <argument>nl.example.ewout-vtx-example.MainVerticle</argument>
                    </arguments>
                </configuration>
            </plugin>
            
            <!-- Maven docker plugin which creates an 
                 Docker Image based on a given directory -->
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>0.4.13</version>
                <executions>
                    <execution>
                        <id>docker</id>
                        <phase>package</phase>
                        <goals>
                            <goal>build</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <dockerDirectory>${project.basedir}/src/main/docker</dockerDirectory>
                    <imageName>ewout-test-vertx</imageName>
                    <resources>
                        <resource>
                            <targetPath>/verticles</targetPath>
                            <directory>${project.build.directory}</directory>
                            <includes>
                                <include>${project.artifactId}-${project.version}.jar</include>
                            </includes>
                        </resource>
                </configuration>
            </plugin>    
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>io.vertx</groupId>
            <artifactId>vertx-core</artifactId>
            <version>${vertx.version}</version>
        </dependency>
        <dependency>
            <groupId>io.vertx</groupId>
            <artifactId>vertx-unit</artifactId>
            <version>${vertx.version}</version>
        </dependency>
    </dependencies>

</project>

The POM contains information about the build process. The most interesting part is the docker-maven plugin. The POM also contains the name of the image, directory of the DockerFile, you can add extra additional dependencies, resources etc.

And the last step is that we need to create an Docker file in the folder given by the POM above. This Docker file will be included in the image and activated when a container is created. Check the code below. This file should be placed in the folder src/main/docker (see the POM above) and the name of the file must be ‘DockerFile’ without extension because the maven-docker plugin expects a file in this folder as a start point.

# Extend vert.x image
FROM vertx/vertx3

# Setup some variables
ENV VERTICLE_HOME /usr/verticles
ENV VERTICLE_NAME nl.example.MainVerticle

# Copy the build result in target (verticles) to my predefined path.
COPY ./verticles $VERTICLE_HOME

# Start the application
ENTRYPOINT ["sh", "-c"]
CMD ["exec vertx run $VERTICLE_NAME -cp $VERTICLE_HOME/*"]

In this case I extend from an existing docker image that is made by the vertx community to make life easy. This image contains preinstalled binaries, so i could use my minimal jar. It is also possible to create your own image without extension and setup java by yourself and using the FAT jar. This takes some more time to configure.

If you want to run/test this project, simply use the command: mvn build or mvn clean build. This command with the pom above is doing the following

  • Download and installs all necessary maven plugins
  • Download and installs all dependencies
  • Creates 2 jars in the target directory; FAT jar and minimal jar. Difference between these jars is that the FAT jar contains all necessary vertx jars, the minimal jar doesn’t. In our case, we use the minimal jar
  • Creates an docker image. First, it creates an docker folder contains all necessary dependencies (target/docker). Based on that folder, it creates an docker image.

Next step is to open your command line and type: docker images. Now you see 2 images; ewout-test-vertx image, based on the maven POM and a vertx3 image, which was used to create the ewout-test-vertx image. It is important to note that our ewout-test-vertx image doesn’t contain any reference to the vertex3 image. The vertx/vertex3 was only used to create the image because ewout-test-vertx extends from it (check the DockerFile above). You can throw this image away if you want by using the command:

docker image rm vertex/vertx3.

Last step is to create an instance (also known as container) of this image. We can do that by using the following command:

docker run -p 8080:8080 ewout-test-vertx

In this command, we publish an container of this image on port 8080, mapped to 8080. If you see our java code, we have a webserver running on port 8080. In the command above, we map this port number to the same one of our container. We can also use a different port to map to (for example 80).

If you open de browser and go to localhost:8080, you see the application is up and running. Congratulations, you got your first application running with an docker image :-).

This is a very basic setup and shows how to use docker in a development environment. If you want more information and details about docker: https://www.docker.com/