Building with Maven

A number of Maven plugins are available for building and deploying Docker images. We’re going to use Fabric8.

1. Adding the Docker plugin

We recommend adding and configuring the Docker plugin in your build’s parent POM so you don’t need to configure it in module POM files.

Add the following to the build plugins configuration in the parent POM for your project:

<plugin>
    <groupId>io.fabric8</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>0.26.1</version>
    <configuration>
        <skip>true</skip> (1)
        <images>
            <image>
                <name>%a:%l</name>
                <build>
                    <from>adoptopenjdk/openjdk8</from> (2)
                    <tags>
                        <tag>latest</tag>
                    </tags>
                    <assembly>
                        <descriptorRef>artifact-with-dependencies</descriptorRef>
                    </assembly>
                </build>
            </image>
        </images>
    </configuration>
</plugin>
1 This line sets skip to true. By default, no Docker image will be built for child modules. This is convenient because it means that Maven modules that are just libraries don’t have to have any Fabric8 configuration in them, when you do a Docker build of your whole project they will just be skipped.
2 This line enables adoptopenjdk/openjdk8. You can use any Docker image that provides a JDK, this is the one we recommend for open source users of OpenShift. It is certified by Lightbend for running our products. If you’re a RedHat customer, you will likely prefer to use the RedHat certified OpenJDK base images, which use a RedHat certified OpenJDK build on RHEL, which is also certified by Lightbend. To use OpenJDK, change this line to:
<from>registry.access.redhat.com/redhat-openjdk-18/openjdk18-openshift</from>

2. Git hash based version numbers

This step is optional, but we recommend basing the version number of your application on the current git hash, since this ensures that you will always be able to map whats deployed to production back to the exact version of your application being used.

There are a number of Maven plugins available for interacting with git, we recommend the Maven git commit id plugin. It allows us to make git-based properties available to the build, which we can then use to compute the version number.

Follow these steps to configure the git commit id plugin:

  1. Add the plugin to the build section of your parent POM:

    <plugin>
        <groupId>pl.project13.maven</groupId>
        <artifactId>git-commit-id-plugin</artifactId>
        <version>2.2.6</version>
        <executions>
            <execution>
                <phase>validate</phase>
                <goals>
                    <goal>revision</goal>
                </goals>
            </execution>
        </executions>
        <configuration>
            <dateFormat>yyyyMMdd-HHmmss</dateFormat>
            <dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
            <generateGitPropertiesFile>false</generateGitPropertiesFile>
        </configuration>
    </plugin>
  2. In the properties section of the parent POM, create a version number based on the commit time and id. Using the commit time is useful because it makes it possible to sort tags chronologically:

    <properties>
       <version.number>${git.commit.time}.${git.commit.id.abbrev}</version.number>
    </properties>
  3. Reconfigure the Fabric8 plugin to use this version number as a tag. You can either update the name property to use %a:${version.number] instead of %a:%l, or, add an additional tag, like so:

    <tags>
        <tag>${version.number}</tag>
        <tag>latest</tag>
    </tags>
The version number will only change upon a git commit. If you are not using the latest tag in your deployment spec, when you update your project and want to redeploy, commit your changes first so you get a new version number. and make sure that version number correlates to what is in the git repository at that commit hash.

3. Per module configuration

Now that we’ve configured the plugin build, we can modify our individual services to enable building a Docker image. In the pom.xml in the Shopping Cart service implementation project, add the following:

<plugin>
    <groupId>io.fabric8</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <configuration>
        <skip>false</skip>
        <images>
            <image>
                <build>
                    <entryPoint>
                       java $JAVA_OPTS -cp '/maven/*' play.core.server.ProdServerStart
                    </entryPoint>
                </build>
            </image>
        </images>
    </configuration>
    <executions>
        <execution>
            <id>build-docker-image</id>
            <phase>package</phase>
            <goals>
                <goal>build</goal>
            </goals>
        </execution>
    </executions>
</plugin>

As you can see, now we’re overriding the skip configuration from the parent POM. We’ve also configured the startup command to run our application. Finally, we’ve added the docker:build execution to our package phase, so that when we run mvn package, the docker image will be built.

4. Building the docker image

Now that we’re set up, we can build our docker image. To do so, we need to tell the Fabric8 plugin which docker registry to use. This can be done using the docker.registry system property - this should include the namespace. Fabric8 also has built in support for authenticating with OpenShift, which can be enabled using the docker.useOpenShiftAuth system property. Let’s build and deploy the image for the shopping-cart project:

mvn -Ddocker.useOpenShiftAuth -Ddocker.registry=$DOCKER_REPO_URL/$NAMESPACE -am -pl shopping-cart package docker:push

This will package your project, build the docker images, tag them and push them to the OpenShift repository. The first time you run this it may take some time as it downloads the docker base image layers to your repository, but subsequent runs will be fast.

5. Configuring OpenShift image lookup

When you push a docker image to OpenShift’s internal registry, it will automatically create an image stream that the image can be consumed from.

Since we’re using Kubernetes deployments rather than OpenShift deployment configs, in order to ensure that our deployment can consume this from the internal OpenShift registry with an unqualified tag, we need to allow local lookups on it. This can be enabled by running the following command.

oc set image-lookup shopping-cart

For more information on image stream lookups, see the OpenShift documentation.

What’s next

With the images built and registered, let’s move on to Deploying Shopping Cart