bmuschko Docker Gradle plugin review

bmuschko Docker Gradle plugin review

If you just want to build Docker images within your Gradle project then it might frustrate you to have to decide which plugin to use. At the time of writing, there were 149 plugins listed on the Gradle plugin portal matching the search term Docker.

Whilst I can’t make the choice for you, this article will help you get to a decision, with a review of the bmuschko Docker Gradle plugin. You’ll quickly learn what it can do (quite a lot, actually) and how it can help you in your own project.

So you can figure out if this plugin is right for you, the review is scored across 3 categories: ease of use, completeness, and up-to-dateness.

First off though, let’s see what this plugin can do.

bmuschko Docker plugin overview

The plugin actually consists of 3 separate plugins, each covering different use cases for integrating Docker into a Gradle build:

  1. Java application plugin – this opinionated plugin is one of the quickest ways for you to Dockerise a Java application, without even having to write a Dockerfile. It sets up all the Gradle tasks required to build images and push them to a remote repository.
  2. Spring Boot application plugin – very similar to the Java application plugin, except for Spring Boot applications
  3. Remote API plugin – this plugin doesn’t add any extra tasks to your Gradle project. Instead, it offers a suite of task classes for common Docker commands, for you to define whatever tasks you need.

Since these 3 use cases are quite distinct, I think it makes sense for them to be split into separate plugins. That way we’re not inheriting functionality into our Gradle project that we don’t need.

How can we use them though?

Docker Java application plugin

For any Java application with a public static void main(String[]) method you can use this plugin to easily build it into a Docker image. A dockerBuildImage Gradle tasks is exposed, which when run will generate an appropriate Dockerfile and use it to build the image.

An example

Suppose we have this simple Java application.

package com.tomgregory;

public class App {
    public String getGreeting() {
        return "Hello World!";
    }

    public static void main(String[] args) {
        System.out.println(new App().getGreeting());
    }
}

In the build.gradle we can apply the Docker Java application plugin like this.

plugins {
    id 'java'
    id 'com.bmuschko.docker-java-application' version '7.0.1'
    // any other plugins
}

Now when we run ./gradlew tasks we have these additional Docker tasks available.

Docker tasks
------------
dockerBuildImage - Builds the Docker image for the application.
dockerCreateDockerfile - Creates the Docker image for the application.
dockerPushImage - Pushes created Docker image to the repository.
dockerSyncBuildContext - Copies the distribution resources to a temporary directory for image creation.

Let’s run the first one, dockerBuildImage.

$ ./gradlew dockerBuildImage

> Task :app:dockerBuildImage
Building image using context 'C:\personal\simple-java\app\build\docker'.
Using images 'simple-java/app:latest'.
Step 1/7 : FROM openjdk:11-jre-slim
 ---> 940f48bb6c92
Step 2/7 : LABEL maintainer=TomGregory
 ---> Using cache
 ---> 2169d987a590
Step 3/7 : WORKDIR /app
 ---> Using cache
 ---> bda77ef65f36
Step 4/7 : COPY libs libs/
 ---> Using cache
 ---> 9a3b4620b302
Step 5/7 : COPY classes classes/
 ---> Using cache
 ---> ee500f46c913
Step 6/7 : ENTRYPOINT ["java", "-cp", "/app/resources:/app/classes:/app/libs/*", "com.tomgregory.App"]
 ---> Using cache
 ---> 2d2f640960f9
Step 7/7 : EXPOSE 8080
 ---> Using cache
 ---> 3e6e7d0a7a75
Successfully built 3e6e7d0a7a75
Successfully tagged simple-java/app:latest
Created image with ID '3e6e7d0a7a75'.

BUILD SUCCESSFUL in 3s
4 actionable tasks: 4 executed

We can see right away that an image has been built. Let’s run the image.

$ docker run --rm 3e6e7d0a7a75
Hello World!

And we get the expected output. Pretty straightforward, don’t you think?

Docker Spring Boot application plugin

This plugin works for an application with a class annotated with @SpringBootApplication containing a public static void main(String[]) method. The dockerBuildImage Gradle task will then generate an appropriate Dockerfile and build the application into a Docker image.

An example

Let’s use this Spring Boot API example application, and apply the plugin to it to get it built into a Docker image.

Apply the plugin like this in the build.gradle.

plugins {
    id 'java'
    id 'io.spring.dependency-management' version "1.0.11.RELEASE"
    id 'org.springframework.boot' version '2.5.0'
    id 'com.bmuschko.docker-spring-boot-application' version '7.0.1'
    // other plugins
}

Running ./gradlew tasks now shows these additional tasks.

Docker tasks
------------
dockerBuildImage - Builds the Docker image for the application.
dockerCreateDockerfile - Creates the Docker image for the application.
dockerPushImage - Pushes created Docker image to the repository.
dockerSyncBuildContext - Copies the distribution resources to a temporary directory for image creation.

Notice how these tasks are the same as those for the Docker Java application plugin?

Now we just need to run the dockerBuildImage task.

$ ./gradlew dockerBuildImage

> Task :dockerBuildImage
Building image using context 'C:\workspace\spring-boot-api-example\build\docker'.
Using images 'spring-boot-api-example:0.1.0-snapshot'.
Step 1/7 : FROM openjdk:11-jre-slim
 ---> 940f48bb6c92
Step 2/7 : LABEL maintainer=TomGregory
 ---> Using cache
 ---> 2169d987a590
Step 3/7 : WORKDIR /app
 ---> Using cache
 ---> bda77ef65f36
Step 4/7 : COPY libs libs/
 ---> Using cache
 ---> 0199a4ded65f
Step 5/7 : COPY classes classes/
 ---> Using cache
 ---> bc2e9c33327a
Step 6/7 : ENTRYPOINT ["java", "-cp", "/app/resources:/app/classes:/app/libs/*", "com.tomgregory.ThemeParkApplication"]
 ---> Using cache
 ---> 293a52665e7c
Step 7/7 : EXPOSE 8080
 ---> Using cache
 ---> c4976c6e848f
Successfully built c4976c6e848f
Successfully tagged spring-boot-api-example:0.1.0-snapshot
Created image with ID 'c4976c6e848f'.

BUILD SUCCESSFUL in 10s
4 actionable tasks: 4 executed

The image has been created, so let’s go ahead and run it.

$ docker run --rm -p 8080:8080 c4976c6e848f

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.5.0)

This clearly shows that the Spring Boot application is now running. In the case of this application, I can also make a request to http://localhost:8080/ride and ensure I get a 200 response.

How the plugin generates the Dockerfile

Looking at the dockerBuildImage task output above, we can see the steps used in creating the Docker image. Rather than copying the jar file into the image, the plugin uses a layered approach and copies the libs and classes directories separately. This means less space is required to store the images when changes to the application are made.

Docker Remote API plugin

This plugin is named as such since it uses the Java Docker library to interact with Docker.

Once you’ve applied the plugin, you can use any of the provided classes to define your own tasks to run whatever Docker command you need. You can even wire tasks together in interesting ways.

If you need to use your own custom Dockerfile, then this is the plugin to use. You can either:

  • use an existing Dockerfile and wire it into your own task definition of type DockerBuildImage
  • have the plugin create one for you by defining a task of type Dockerfile and configuring it appropriately.

An example

Imagine I already have a Dockerfile I want to use in my project, located at docker/Dockerfile.

FROM openjdk:11-jre-slim
RUN echo "Gradle + Docker: best of friends" > important-message.txt
ENTRYPOINT ["cat", "important-message.txt"]

To build this custom Dockerfile, we first need to apply the plugin.

plugins {
    id 'com.bmuschko.docker-remote-api' version '7.0.1'
    // any other plugins
}

Now we have access to several task classes, helping us interact with the Docker API. For this example, we just want to build an image, so we’ll define a task of type DockerBuildImage.

import com.bmuschko.gradle.docker.tasks.image.*

tasks.register('dockerBuildImage', DockerBuildImage) {
    inputDir = file('docker')
}

There are many task parameters that you can set, but we’ll just set the inputDir which defines the Docker build context where the tasks expects to find the Dockerfile.

Now let’s run the newly defined dockerBuildImage task.

$ ./gradlew dockerBuildImage

> Task :dockerBuildImage
Building image using context 'C:\personal\docker-plugin-remote-api-example\docker'.
Step 1/3 : FROM openjdk:11-jre-slim
 ---> 940f48bb6c92
Step 2/3 : RUN echo "Gradle + Docker: best of friends" > important-message.txt
 ---> Using cache
 ---> 00b6dbc20b4e
Step 3/3 : ENTRYPOINT ["cat", "important-message.txt"]
 ---> Using cache
 ---> 1ae13e8d7f68
Successfully built 1ae13e8d7f68
Created image with ID '1ae13e8d7f68'.

BUILD SUCCESSFUL in 3s
1 actionable task: 1 executed

OK, so it built successfully. Now to run it.

$ docker run --rm 1ae13e8d7f68
Gradle + Docker: best of friends

We get the expected output, showing that we’ve successfully built an image using a custom Dockerfile.

Some other examples for the Docker Remote API plugin

To get the ideas flowing, here are some other examples of what you might do with this plugin.

  1. for your application, build a Dockerfile , a Docker image, then run a container
  2. run a container for a database, create whatever schema your application expects, then commit that container to an image. That way you always have a database ready-to-go.
  3. define a Gradle task to tag and push images, based on the current Gradle project version and branch name

Plugin review categories

Is the plugin easy to use?

Besides the slight confusion of the fact that the plugin is split in 3, it’s very easy to use for basic use cases. You’ve already seen that you can Dockerise Java and Spring Boot applications with a few lines of code.

Pros

  • easily get started with Java & Spring Boot applications
  • easily customise the Dockerfile, even using the opinionated Java application or Spring Boot application plugins. e.g. you could change the base image to a different version of Java.
  • some of the tasks implement up-to-date checks properly, meaning you don’t have to run the task again unnecessarily. For example, tasks of type DockerBuildImage create an output file in build/.docker containing the image id, meaning the Docker image only gets rebuilt when something actually changes.
  • there’s good documentation and some functional tests help understanding

Cons

  • the plugin uses the docker configuration extension, which is also used by the Palantir Docker plugin. This means that both of these plugins can’t be used in the same project.
  • no progress output is shown when an image is being pushed, even with the Gradle --info flag enabled

Ease-of-use score: 4/5

How complete is the plugin?

The Docker Remote API plugin aims to cover many of the most common Docker commands, including:

  • create a Dockerfile
  • build, commit, tag, and many other image operations
  • start, stop, exec, and many other container operations
  • create, remove, and inspect networks

This list is much more exhaustive than other plugins like the Palantir Docker plugin. Having each command available as a task to define in your build means you can chain them together to create complex behaviours e.g. build a Dockerfile > build an image > start a container > do some action to the container > commit the container to an image.

Pros

  • many Docker commands covered by provided task classes

Cons

  • Java application and Spring Boot application plugins do not provide a way to start a container out-of-the-box. You have to define this task separately.
  • no Docker Compose support, although this is covered already by other plugins like the Avast Docker Compose Plugin

Completeness score: 4/5

How up to date is the plugin?

This plugin was created in 2014 by Benjamin Muschko, who at the time was working as a engineer at Gradle. Compared to many other plugins I’ve seen, this one follows most Gradle best practices, such as defining task inputs and outputs.

Pros

  • knowledgeable team keeping the plugin up to date
  • PRs raised and dealt with promptly e.g. when JFrog announced discontinuation of the JCenter Maven repository on 3rd February 2021, a PR was raised in the plugin repository on 22nd February and closed on 5th March.
  • other issues are responded to by the team quickly e.g. looking at the last 5 GitHub issues tagged with question, all but one were dealt with within 2 days

Cons

None

Up-to-dateness score: 5/5

Conclusion

This plugin is one of the best ways to integrate Docker into your Gradle project, whether that be just building images or orchestrating more complex workflows using multiple Docker commands. It’s easy to get started, especially when working with Java or Spring Boot projects. Most of the Docker functionality is covered, and the team is responsive in keeping the plugin updated.

bmuschko Docker Gradle plugin overall score

87%

Hopefully by this point you have a better idea if this plugin will suit your use case. If you still have questions, please share what you’re trying to do in the comments below, and I’ll try to help you out.

Otherwise, head on over to the bmuschko Gradle Docker plugin GitHub page for more information and documentation. Also, if you’d like to learn about the Palantir Docker Gradle plugin, then check out the article Automating Docker Builds With Gradle.

Get going with Gradle course
Gradle icon

Want to learn more about Gradle?
Check out the full selection of Gradle tutorials.

bmuschko Docker Gradle plugin review

Leave a Reply

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

Scroll to top

Get the newsletter

Found this article helpful? Subscribe for monthly updates.

✅ All of my latest articles for the month
✅ Access to video tutorials
✅ Exclusive tips not found on my website