Maven mixin providing the ability to build, tag and deploy Docker images
Switch branches/tags
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.gitignore
README.adoc
bumpver.sh
pom.xml
release.sh

README.adoc

java-mavenmixin-docker

This module, for use within Apache Isis applications, provides a maven mixin that can be used to package up a webapp as a Docker image using the package phase, and then to upload that Docker image to a repository (eg docker hub) using the deploy phase. It also disables the regular maven-deploy-plugin (so that the <distributionManagement> section is not required).

The appropriate configuration is included in a <profile>, but which is disabled by default; it can be enabled using a Maven property.

How to Configure

To configure:

  • copy and paste the following into either the pom.xml of the consuming module or (better still) the pom.xml of the top-level parent of the consuming module:

    <properties>
        ...
        <mavenmixin-docker.version>0.0.4</mavenmixin-docker.version>
        <maven-deploy-plugin.version>2.8.1</maven-deploy-plugin.version>
        <docker-maven-plugin.version>1.0.0</docker-maven-plugin.version>
        ...
    </properties>

    and:

    <build>
        <pluginManagement>
            <plugins>
                ...
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>${maven-deploy-plugin.version}</version>
                </plugin>
                <plugin>
                    <groupId>com.spotify</groupId>
                    <artifactId>docker-maven-plugin</artifactId>
                    <version>${docker-maven-plugin.version}</version>
                </plugin>
                ...
            </plugins>
        </pluginManagement>
    </build>
  • update the following property/ies in the pom.xml of the consuming webapp module (with <packaging>war</packaging>):

    <properties>
        ...
        <docker-plugin.imageName>               (1)
            XXX/${project.parent.artifactId}
        </docker-plugin.imageName>
        <docker-plugin.imageTag>                (2)
            ${project.version}
        </docker-plugin.imageName>
        <docker-plugin.resource.include>        (3)
            ${project.parent.artifactId}.war
        </docker-plugin.resource.include>
        <docker-plugin.serverId>                (4)
            docker-hub
        </docker-plugin.serverId>
        <docker-plugin.registryUrl>             (5)
            https://index.docker.io/v1/
        </docker-plugin.registryUrl>
        ...
    </properties>
    1. the name of the image to be created. Change "XXX" as required; for example if deploying to docker hub then "XXX" will be the account name on docker hub.

    2. the tag of the image to be created, often ${project.version} but could be specified externally from a CI pipeline/job.

    3. the WAR file to include within the image. The idea is that the Dockerfile (below) copies this war file into the appropriate directory of the image. If using the jettywar mavenmixin then this could also be set to ${maven-war-plugin.warName}.war

    4. The id of the server to upload images to. This id is used to look up username/password credentials from ~/.m2/settings.xml; see below for further details on this. If not specified then "docker-hub" is assumed.

    5. The corresponding URL to upload images to. Note that the URL is not looked up from ~/.m2/settings.xml. If not specified then "https://index.docker.io/v1/" is assumed.

  • add the following to the pom.xml of the consuming webapp module:

    <build>
        <plugins>
            <plugin>
                <groupId>com.github.odavid.maven.plugins</groupId>
                <artifactId>mixin-maven-plugin</artifactId>
                <version>0.1-alpha-39</version>
                <extensions>true</extensions>
                <configuration>
                    <mixins>
                        <mixin>
                            <groupId>com.danhaywood.mavenmixin</groupId>
                            <artifactId>docker</artifactId>
                            <version>${mavenmixin-docker.version}</version>
                        </mixin>
                    </mixins>
                </configuration>
            </plugin>
        </plugins>
    </build>
  • if necessary, specify src/main/resources as a resource directory, with filtering (ie substitution of parameters) enabled:

    <build>
        <resources>
            <resource>
                <filtering>true</filtering>
                <directory>src/main/resources</directory>
            </resource>
            ...
        </resources>
        ...
    </build>
  • create a Dockerfile in src/main/resources/docker.

    For example:

    FROM incodehq/tomcat
    RUN rm -rf ${DEPLOYMENT_DIR}/ROOT
    COPY ${docker-plugin.resource.include} ${DEPLOYMENT_DIR}/ROOT.war
    EXPOSE 8080

    The incodehq/tomcat base image exposes the ${DEPLOYMENT_DIR} environment variable as the directory to deploy war files to. The ${docker-plugin.resource.include} property will be substituted with the value defined in the pom.xml. You can of course add other configuration into the Dockerfile, see the Dockerfile reference for details.

  • (if deploying to a docker registry), add the following to ~/.m2/settings.xml:

    <servers>
        <server>
          <id>docker-hub</id>                               (1)
          <username>danhaywood</username>                   (2)
          <password>XXXXXXXX</password>
          <configuration>
            <email>dan@haywood-associates.co.uk</email>     (3)
          </configuration>
        </server>
        ...
    </servers>
    1. corresponds to the value of the ${docker-plugin.serverId} property defined above

    2. username and password for the account defined for the repository (whose registry URL is defined by the ${docker-plugin.registryUrl} property)

    3. corresponding email address, as described in the spotify docker plugin README.

How to use

To create the image file:

mvn install -Dmavenmixin-docker

This will create an image and tagged it as both latest and using the consuming pom.xml's project.version. The two tagged images will be visible using docker images.

To also upload (push) the image to the docker registry:

mvn -pl webapp deploy -Dmavenmixin-docker

The -pl webapp runs the deploy in the webapp module (where the WAR file is built).

Where the image is uploaded to depends on the project.version of the consuming pom.xml:

  • if the project.version is a -SNAPSHOT, then docker-plugin.snapshotServerId and docker-plugin.snapshotRegistryUrl properties will be used.

  • if the project.version is not a -SNAPSHOT, then docker-plugin.releaseServerId and docker-plugin.releaseRegistryUrl properties will be used.

This allows unstable snapshot images to be pushed to a different registry than the stable release images.

The above assumes that the ${docker-plugin.imageName} property has been specified in the consuming pom.xml. If necessary, though, that property can also be specified from the command line, eg:

mvn deploy -Dmavenmixin-docker \
           -Ddocker-plugin.imageName=danhaywood/simpleapp

The underlying docker-maven-plugin also allows goals to be disabled using -DskipDocker and similar variants.

How to consume

To run the image:

docker run -d -p80:8080 XXX/imageName

where XXX/imageName is the value of ${docker-plugin.imageName} property specified in the consuming pom.xml. It should then be possible to access the application from http://localhost.

As a slightly more complex example, we can run two docker images, one with postgres backend database and the other running the application itself:

docker run --name postgres -d incodehq/postgres

and then:

ISIS_OPTS=""
ISIS_OPTS="${ISIS_OPTS}isis.persistor.datanucleus.impl.javax.jdo.option.ConnectionDriverName=org.postgresql.Driver"
ISIS_OPTS="${ISIS_OPTS}||isis.persistor.datanucleus.impl.javax.jdo.option.ConnectionURL=jdbc:postgresql://db:5432/incodehq"
ISIS_OPTS="${ISIS_OPTS}||isis.persistor.datanucleus.impl.javax.jdo.option.ConnectionUserName=incodehq"
ISIS_OPTS="${ISIS_OPTS}||isis.persistor.datanucleus.impl.javax.jdo.option.ConnectionPassword=incodehq"

docker run --name imageName --link postgres:db -e ISIS_OPTS=$ISIS_OPTS -p 80:8080 -d XXX/imageName

Again, the application can be accessed from http://localhost.

Note
this requires that the postgres JDBC driver is part of the application being built.

Known issues

None currently

Change Log

  • 0.0.4 - Various improvements:

    • Introduces docker-plugin.imageTag property to allow the image tag to be specified externally.

    • Removes distinction between release and snapshot repositories (external CI job can simply override)

      • docker-plugin.snapshotServerId and docker-plugin.releaseServerId replaced with docker-plugin.serverId

      • docker-plugin.snapshotRegistryUrl and docker-plugin.releaseRegistryUrl replaced with docker-plugin.serverId

    • Updated to 1.0.0 of spotify:docker-maven-plugin

  • if the project.version is not a -SNAPSHOT, then docker-plugin.releaseServerId and docker-plugin.releaseRegistryUrl properties will be used.

  • 0.0.3 - bind build goal to install phase rather than package phase. Provide the capability to deploy snapshot images and release images to different registries.

  • 0.0.2 - changed profile so is disabled by default

  • 0.0.1 - first release

License

Copyright 2016~date Dan Haywood

Licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.

Dependencies

This mixin module relies on the com.github.odavid.maven.plugins:mixin-maven-plugin, released under Apache License v2.0.

Maven deploy notes

The module is deployed using Sonatype’s OSS support (see user guide and this blog post).

The release.sh script automates the release process. It performs the following:

  • performs a sanity check (mvn clean install -o) that everything builds ok

  • bumps the pom.xml to a specified release version, and tag

  • performs a double check (mvn clean install -o) that everything still builds ok

  • releases the code using mvn clean deploy

  • bumps the pom.xml to a specified release version

For example:

sh release.sh 0.0.4 \
              0.0.5-SNAPSHOT \
              dan@haywood-associates.co.uk \
              "this is not really my passphrase"

where

  • $1 is the release version

  • $2 is the snapshot version

  • $3 is the email of the secret key (~/.gnupg/secring.gpg) to use for signing

  • $4 is the corresponding passphrase for that secret key.

Other ways of specifying the key and passphrase are available, see the pgp-maven-plugin's documentation).

If the script completes successfully, then push changes:

git push origin master && git push origin 0.0.3

If the script fails to complete, then identify the cause, perform a git reset --hard to start over and fix the issue before trying again. Note that in the dom’s `pom.xml the nexus-staging-maven-plugin has the autoReleaseAfterClose setting set to true (to automatically stage, close and the release the repo). You may want to set this to false if debugging an issue.

According to Sonatype’s guide, it takes about 10 minutes to sync, but up to 2 hours to update search.