Thursday, June 18, 2020

Dockerizing Your Java EE Thorntail Microservice

Context


If you have read the article about Java EE Micro Services Using Thorntail then it's about time we followed up on a question that you and some of the viewers probably asked:

"What if I want to run this as a docker service?"

Well now we can look into that. There are various ways that one achieve this, the common way has been through the use of Docker Files. The Maven users now have an alternative through the Docker Maven Plugin, which inherits a lot from the behavior of a Docker File. I believe the Gradle developers may also have something similar. Anyway may be one day we can look into it.



Starting Up The Configuration


Reach out to your previous project based on the linked article mentioned above as we will be working on that. Open your pom.xml file. The plan is to use a maven profile to configure this so that we isolate the operations we can perform using the docker plugin. Add a new maven profile :

<profile>
<id>
docker</id>
<build>
<plugins>
<plugin>
<groupId>
io.fabric8</groupId>
<artifactId>
docker-maven-plugin</artifactId>
<configuration>
<images>
<image>
<name>
${project.build.finalName}</name>
<run>
<ports>
<port>
8881:8881</port>
</ports>
</run>
<build>
<from>
java:openjdk-8-jdk</from>
<ports>
<port>
8881</port>
</ports>
<assembly>
<basedir>
/</basedir>
<inline>
<files>
<file>
<source>
${project.build.directory}/${build.finalName}-thorntail.jar</source>
<outputDirectory>
/opt</outputDirectory>
</file>
</files>
</inline>
</assembly>
<cmd>
<shell>
java -jar /opt/${build.finalName}-thorntail.jar -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv4Addresses=true</shell>
</cmd>
</build>
</image>
</images>
</configuration>
<executions>
<execution>
<phase>
package</phase>
<goals>
<goal>
build</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>


That's all you need to get up and running, but before that, let's now get into a more detailed breakdown of what's happening.


The XML Explained


We have added the plugin with some configurations that I would like to delineate.

...
<name>
${project.build.finalName}</name>
...

This is a name of your Java Service that will be running in docker. So when you look at all your running containers, you should see the name you specified within these XML tags.


...
<run>
<ports>
<port>
8881:8881</port>
</ports>
</run>

...

We define how the container ports should be mapped to the host port. So we know that our app was initially configured at port 8881 based on our previous article, so for simplicity let's keep these the same as our initial configuration.



...
<build>
    <from>
java:openjdk-8-jdk</from>
        <ports>
            <port>
8881</port>
        </ports>
        <assembly>
            <basedir>
/</basedir>
            <inline>
                <files>
                    <file>
                        <source>
${project.build.directory}/${build.finalName}-thorntail.jar</source>
                            <outputDirectory>
/opt</outputDirectory>
                    </file>
                </files>
            </inline>
        </assembly>
        <cmd>
            <shell>
java -jar /opt/${build.finalName}-thorntail.jar -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv4Addresses=true</shell>
        </cmd>
</build>

...

We use the <build> tag to define how our custom docker image should be built

...
<from>
java:openjdk-8-jdk</from>
...

We are basing our image off the java:openjdk-8jdk image

...
<assembly>
     <basedir>
/</basedir>
    <inline>
        <files>
            <file>
                <source>
${project.build.directory}/${build.finalName}-thorntail.jar</source>
                <outputDirectory>
/opt</outputDirectory>
            </file>
        </files>
    </inline>
</assembly>
...

Part of building our image includes the files that may be involved in our service. In this case we want our bootable / executable ".jar" included since it's the actual service that we want to run. We also specify where the jar should be placed when inside the docker container. This destination path is "/opt". So this mean that the moment you have connected to our docker container, you should be able to see the jar if you change to the "/opt" directory or path.

...
<cmd>
    <shell>
java -jar /opt/${build.finalName}-thorntail.jar -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv4Addresses=true</shell>
</cmd>
...

This last part is the command to exectue when the image built and has created a container for us. This entry point is just a simple command that you would run on your local machine in order to bootstrap your Java API Service. So you do the same thing here, I have also added some java options in my command, which you may not need.



Building & Running Your Service

Cooooool stuff! So now we can try to run our applications, to do that all we need to do is build our image and then create our container and run it.


Let's build our service image using our new maven profile :


mvn docker:build -Pdocker



Next up we create and run our new container based on the new image :


mvn docker:start -Pdocker


And that's it, your container should be running. You can repeat the same REST API Postman test steps we did in our previous article and all should work as expected. You can also check if it's running using the docker list command as follows :


docker container ls





Great stuff! So that's all you need to do to dockerize your executable ".jar" file. My thoughts are that you should be able to do the same with a Spring Boot application. You may refer to more Docker Maven Plugins Operaions. For more insight.


Leave some comments below and you may checkout the GitHub Source Code to validate the steps.

1 comment: