Marathon Maven plugin from HolidayCheck

At HolidayCheck we are using both Docker and Apache Mesos with Mesosphere’s Marathon. Therefore for our development teams creating services using Maven we wanted to set up easy to use configurations bound to standard Maven lifecycle phases.

Starting with Docker Maven plugin

As wiring a Java/Scala project for Docker is possible by multiple existing plugins, we have chosen Spotify’s Docker Maven plugin, as it best suited our needs, was easy to integrate and allowed to use Git commit hashes (aside from standard artifact versions) in Docker image names for uniqueness.

Marathon Maven plugin usage example

You can have a look at the plugin on the GitHub:
https://github.com/holidaycheck/marathon-maven-plugin
or even start using it already in your project:

<plugin>
     <groupId>com.holidaycheck</groupId>
     <artifactId>marathon-maven-plugin</artifactId>
     <version>0.0.1</version>
     <configuration>
         <image>${docker-image-prefix}/${project.build.finalName}:${project.version}</image>
         <marathonHost>${marathon.protocol}://${marathon.host}:${marathon.port}</marathonHost>
     </configuration>
     <executions>
         <execution>
             <id>processConfig</id>
             <phase>install</phase>
             <goals>
                 <goal>processConfig</goal>
             </goals>
         </execution>
         <execution>
             <id>deploy</id>
             <phase>deploy</phase>
             <goals>
                 <goal>deploy</goal>
             </goals>
         </execution>
     </executions>
</plugin>

To interact with Marathon the plugin uses Marathon Java API client. In the processConfig goal the plugin takes marathon.json file currently located by default in root project directory, which might
look like the one here:

{
  "id": "/my-service-1",
  "container": {
    "type": "DOCKER",
    "docker": {
      "image": "docker-registry.your.org/my-team/my-service",
      "network": "BRIDGE",
      "portMappings": [
        {"containerPort": 7070},
        {"containerPort": 7071}
      ]
    }
  },
  "env": {
    "PATH_PREFIX": "/my-service",
    "_JAVA_OPTIONS": "-Xms64m -Xmx128m -XX:MaxPermSize=64m"
  },
  "instances": 1,
  "cpus": 0.5,
  "mem": 256,
  "healthChecks": [
    {
      "protocol": "HTTP",
      "portIndex": 0,
      "path": "/my-service/v1.0/healthcheck",
      "gracePeriodSeconds": 3,
      "intervalSeconds": 10,
      "timeoutSeconds": 10,
      "maxConsecutiveFailures": 5
    }
  ]
}

replaces container/docker/image with the value provided to the plugin and evaluated taking into account all used variables e.g.: docker-registry.your.org/my-team/my-service-1.0.
The result is put into project’s target directory by default. Then it’s being picked up by the deploy goal and submitted to Marathon’s API endpoint with some minor handling of a situation whether the app already exists or not in the cluster.

Docker and Marathon plugins join forces

As mentioned earlier the Marathon plugin goes well with the Docker plugin, mostly due to the fact that we might bind those two plugins together and hook them nicely to proper Maven lifecycle phases and (what is very important in our scenario) to use Git commit hash as the Docker image name detected previously by the Docker plugin to be used in Marathon plugin’ configuration:

<plugin>
    <groupId>com.spotify</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>0.2.6</version>
    <configuration>
        <imageName>${docker-image-prefix}/${project.build.finalName}:${project.version}-${gitShortCommitId}</imageName>
    </configuration>
    <executions>
        <execution>
            <id>build</id>
            <phase>install</phase>
            <goals>
                <goal>build</goal>
            </goals>
            <configuration>
                <maintainer>HolidayCheck</maintainer>
                <baseImage>${docker-registry}/lightweight/oracle-java-7-debian</baseImage>
                <cmd>java -jar /${project.name}.jar</cmd>
                <exposes>
                    <expose>7070</expose>
                </exposes>
                <resources>
                    <resource>
                        <targetPath>/</targetPath>
                        <directory>${project.build.directory}</directory>
                        <include>${project.build.finalName}.jar</include>
                    </resource>
                </resources>
            </configuration>
        </execution>
        <execution>
            <id>push</id>
            <phase>deploy</phase>
            <goals>
                <goal>push</goal>
            </goals>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>com.holidaycheck</groupId>
    <artifactId>marathon-maven-plugin</artifactId>
    <version>0.0.1</version>
    <configuration>
        <image>${docker-image-prefix}/${project.build.finalName}:${project.version}-${gitShortCommitId}</image>
        <marathonHost>${marathon.protocol}://${marathon.host}:${marathon.port}</marathonHost>
    </configuration>
    <executions>
        <execution>
            <id>processConfig</id>
            <phase>install</phase>
            <goals>
                <goal>processConfig</goal>
            </goals>
        </execution>
        <execution>
            <id>deploy</id>
            <phase>deploy</phase>
            <goals>
                <goal>deploy</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Now simply type:

mvn clean deploy

and you should have it deployed and running on your target environment.

Have a good time using Marathon Maven plugin! If you are willing to contribute your pull requests are welcome.

Leave a Reply

Your email address will not be published. Required fields are marked *