1. Introduction

Gradle plugin for managing Docker images and containers using via its remote API. The heavy lifting of communicating with the Docker remote API is handled by the Docker Java library. Please refer to the library’s documentation for more information on the supported Docker’s client API and Docker server version.

This plugin requires Gradle >= 2.5 to work properly.

1.1. Benefits

There are various benefits for using this plugin:

  1. Seamless integration with the build tool Gradle and its DSL.

  2. Handles complicated communication logic between Docker client and daemon under the covers.

  3. Simplifies the definition of complex workflows.

  4. Minimizes build script setup logic by providing sensible conventions for different use cases.

1.2. Limitations

The functionality of the plugin does not cover all possible use cases. Be aware of the following limitations:

  • A task type may not provide all possible options for the underlying Docker operation. Open an issue if you feel like it should be supported.

  • You cannot build multi-container applications via Docker Compose. The Avast Docker Compose plugin has proven to be a capable alternative.

  • Managing a Docker Swarm and/or Stack is not supported.

1.4. Provided Plugins

The binary distribution is available on the Gradle plugin portal, Bintray’s JCenter and Maven Central. It contains the following plugins:

Plugin Id Automatically applies Type Description

com.bmuschko.docker-remote-api

-

DockerRemoteApiPlugin

Provides custom tasks for interacting with Docker via its remote API.

com.bmuschko.docker-java-application

com.bmuschko.docker-remote-api

DockerJavaApplicationPlugin

Creates and pushes a Docker image for a Java application.

com.bmuschko.docker-spring-boot-application

com.bmuschko.docker-remote-api

DockerSpringBootApplicationPlugin

Creates and pushes a Docker image for a Spring Boot application.

Which plugin you chose in your project entirely depends on the use case you want to fulfill. Refer to the relevant portions of the user guide that describe the purpose and usage of each plugin in more detail.

1.5. Getting Started

The plugin can be applied with the buildscript syntax or the plugin DSL. Let’s say you’d want to go with the plugin that provides the plain Docker operations for managing Docker images and containers. See the Gradle user guide for more information on applying plugins.

1.5.1. Aplying the Plugin Using the buildscript Syntax

build.gradle
buildscript {
    repositories {
        maven {
            url 'https://plugins.gradle.org/m2/'
        }
    }
    dependencies {
        classpath 'com.bmuschko:gradle-docker-plugin:3.6.1'
    }
}

apply plugin: 'com.bmuschko.docker-remote-api'

1.5.2. Applying the Plugin using the Plugin DSL

build.gradle
plugins {
    id 'com.bmuschko.docker-remote-api' version '3.6.1'
}

1.5.3. Applying the Plugin From a Script Plugin

Applying the plugin from a script plugin requires the use of the fully-qualified class name due to a bug in Gradle core. Be aware that the plugin DSL cannot be used to apply a binary plugin from a script plugin.

gradle/docker.gradle
buildscript {
    repositories {
        maven {
            url 'https://plugins.gradle.org/m2/'
        }
    }
    dependencies {
        classpath 'com.bmuschko:gradle-docker-plugin:3.6.1'
    }
}

apply plugin: com.bmuschko.gradle.docker.DockerRemoteApiPlugin
build.gradle
apply from: 'gradle/docker.gradle'

2. Remote API Plugin

The plugin com.bmuschko.docker-remote-api allows for interacting with Docker via its remote API. You can model any workflow imaginable by creating enhanced task of the custom task provided by the plugin.

2.1. Usage

build.gradle
buildscript {
    repositories {
        maven {
            url 'https://plugins.gradle.org/m2/'
        }
    }
    dependencies {
        classpath com.bmuschko:gradle-docker-plugin:3.6.1'
    }
}

apply plugin: 'com.bmuschko.docker-remote-api'

// Import task types
import com.bmuschko.gradle.docker.tasks.image.*

// Use task types
task buildMyAppImage(type: DockerBuildImage) {
    inputDir = file('docker/myapp')
    tag = 'test/myapp:latest'
}

The plugin automatically resolves the Docker Java library with the pre-configured version under the covers. The only configuration you will have to provide in your build script is the repository hosting the library and its transitive dependencies. One repository that hosts them all is Maven Central.

build.gradle
repositories {
    mavenCentral()
}

2.2. Extension

The plugin defines an extension with the namespace docker. The following properties can be configured:

Property name Type Default value Description

url

String

see below

The server URL to connect to via Docker’s remote API.

certPath

File

null

The path to certificates for communicating with Docker over SSL.

apiVersion

String

null

The remote API version. For most cases this can be left null.

The default value is now generated based on a best guess attempt given the operating system and environment:

Operating system Value

Unix-based machine

unix:///var/run/docker.sock

Windows-based machine (and everything else)

tcp://127.0.0.1:2375

Image pull or push operations against the public Docker Hub registry or a private registry may require authentication. You can provide those credentials in the registryCredentials closure:

Property name Type Default value Description

url

String

https://index.docker.io/v1/

The registry URL.

username

String

null

The registry username.

password

String

null

The registry password.

email

String

null

The registry email address.

2.2.1. Working With a TLS-enabled Docker Instance

Starting with Docker version 1.3, TLS is enabled by default. Please consult the Docker documentation "Protect the Docker daemon socket" to set up your certificate. The following example demonstrates how to configure the plugin to use those certificates. Additionally, this code snippet shows how to set the user credentials.

build.gradle
docker {
    url = 'https://192.168.59.103:2376'
    certPath = new File(System.properties['user.home'], '.boot2docker/certs/boot2docker-vm')

    registryCredentials {
        url = 'https://index.docker.io/v1/'
        username = 'bmuschko'
        password = 'pwd'
        email = 'benjamin.muschko@gmail.com'
    }
}

2.2.2. Working With Google Cloud And Using a Key File

build.gradle
docker {
    registryCredentials {
        url = 'https://gcr.io'
        username = '_json_key'
        password = file('keyfile.json").text
    }
}

2.2.3. Working With a Docker Instance Without TLS

The following example assumes that you disabled TLS on your Docker instance. You can do so by setting DOCKER_TLS=no in the file /var/lib/boot2docker/profile.

build.gradle
docker {
    url = 'tcp://192.168.59.103:2375'
}

On Unix the Docker daemon listens by default on unix:///var/run/docker.sock.

On Windows the Docker daemon listens by default on npipe:////./pipe/docker_engine though this is not currently supported. We instead fall back to tcp://127.0.0.1:2375.

2.3. Custom task types

2.3.1. Misc

The plugin provides the following general-purpose custom task types:

Type Description

DockerClient

Passes the raw docker-java client to the onNext closure if it’s defined.

DockerInfo

Displays system-wide information.

DockerVersion

Show the docker version information.

2.3.2. Images

The plugin provides the following custom task types for managing images:

Type Description

Dockerfile

Creates a Dockerfile based on the provided instructions.

DockerBuildImage

Builds an image from a Dockerfile.

DockerCommitImage

Creates a new image from a container’s changes.

DockerInspectImage

Returns low-level information on the image.

DockerListImages

Lists images in registry.

DockerPullImage

Pulls an image from the registry.

DockerPushImage

Pushes an image to a registry.

DockerRemoveImage

Removes an image from the filesystem.

DockerTagImage

Tags an image in registry.

DockerSaveImage

Saves an image to file.

DockerLoadImage

Loads an image from file.

2.3.3. Containers

The plugin provides the following custom task types for managing containers:

Type Description

DockerCopyFileToContainer

Copies a path from the host into the container.

DockerCopyFileFromContainer

Copies a path from the container as a tar file on to the host.

DockerCreateContainer

Creates a container.

DockerInspectContainer

Returns low-level information on the container.

DockerKillContainer

Kills the container for a given id.

DockerRemoveContainer

Removes the container for a given id from the filesystem.

DockerRenameContainer

Rename a container.

DockerRestartContainer

Restarts the container for a given id.

DockerStartContainer

Starts the container for a given id.

DockerStopContainer

Stops the container for a given id.

DockerWaitContainer

Blocks until container for a given id stops.

DockerLogsContainer

Copies the container output to the Gradle process standard out/err.

DockerExecContainer

Executes a command within a running container.

DockerInspectExecContainer

Inspects task executed inside container with DockerExecContainer command.

2.3.4. Networks

The plugin provides the following custom task types for managing networks:

Type Description

DockerCreateNetwork

Creates a network.

DockerInspectNetwork

Returns low-level information on the network.

DockerRemoveNetwork

Removes the network.

2.3.5. Extras

The plugin provides the following additional tasks:

Type Description

DockerExecStopContainer

Shut down container with cmd, polling for it to enter a non-running state, and if that does not succeed in time issue stop request.

DockerLivenessContainer

Polls an arbitrary containers logs for a message indicating liveness.

DockerWaitHealthyContainer

Blocks until the container for a given id becomes healthy.

2.4. Reactive Streams

As needed, we will implement reactive methods as described in reactive-streams. We implement these here as optional closures for all tasks. Currently the only supported methods are onError, onNext, onComplete. Various examples on how to use these can be found in our reactive tests

2.4.1. Reacting to an Error

The onError closure is passed the exception that is thrown for you to handle. If you silently ignore we will not throw the exception behind the scenes. The below example is a common use-case that arises when someone wants to remove a container whether it exists or not but does not want to fail hard.

build.gradle
apply plugin: 'com.bmuschko.docker-remote-api'

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

task removeContainer(type: DockerRemoveContainer) {
    targetContainerId { 'container-that-does-not-exist' }
    onError { exception ->
        // Ignore exception if container does not exist otherwise throw it
        if (!exception.message.contains('No such container'))
            throw exception
    }
}

2.4.2. Reacting to Data Returned by an Operation

The onNext closure is passed the next iterative response upon execution. For all other tasks we simply hand you back the object that is given to us by docker-java which is a pojo representation of the json handed back by docker. Thus, and much like the onError closure, all delegation is now in your control. Any properties/values expected to be set will not be done unless you do them.

Iterative tasks are things like DockerBuildImage, DockerLogsContainer, DockerListImages. These tasks have output which can be iterated over. The example below demonstrates how we iterate over each log message passing that to the closure for the user to work on.

build.gradle
apply plugin: 'com.bmuschko.docker-remote-api'

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

task logContainer(type: DockerLogsContainer) {
    targetContainerId { 'container-that-does-exist' }
    follow = true
    tailAll = true
    onNext { message ->
        // Each log message from the container will be passed as it's made available
        logger.quiet message.toString()
    }
}

2.4.3. Reacting to the Completion of an Operation

The onComplete closure is not passed anything upon execution. It works in the same fashion that doLast does but is instead part of this task and thus executes before doLast does. This closure executes only upon success. The below example demonstrates how this works.

build.gradle
apply plugin: 'com.bmuschko.docker-remote-api'

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

task removeContainer(type: DockerRemoveContainer) {
    targetContainerId { 'container-that-does-exist' }
    onComplete {
        println 'Executes first'
    }
    doLast {
        println 'Executes second'
    }
}

2.5. Examples

The following usage examples demonstrate code for common use cases. More scenarios can be found in the functional tests.

2.5.1. Creating a Dockerfile And Building an Image

A Dockerfile can be created by the Dockerfile custom tasks. The Dockerfile instructions need to be declare in the correct order.

build.gradle
apply plugin: 'com.bmuschko.docker-remote-api'

import com.bmuschko.gradle.docker.tasks.image.Dockerfile
import com.bmuschko.gradle.docker.tasks.image.DockerBuildImage

task createDockerfile(type: Dockerfile) {
    destFile = project.file('build/mydockerfile/Dockerfile')
    from 'ubuntu:12.04'
    maintainer 'Benjamin Muschko "benjamin.muschko@gmail.com"'
}

task buildImage(type: DockerBuildImage) {
    dependsOn createDockerfile
    inputDir = createDockerfile.destFile.parentFile
    tag = 'bmuschko/myimage:latest'
}

2.5.2. Executing Functional Tests Against a Running Container

The following example code demonstrates how to build a Docker image from a Dockerfile, starts up a container for this image and exercises functional tests against the running container. At the end of this operation, the container is stopped.

build.gradle
apply plugin: 'com.bmuschko.docker-remote-api'

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

task buildMyAppImage(type: DockerBuildImage) {
    inputDir = file('docker/myapp')
    tag = 'test/myapp:latest'
}

task createMyAppContainer(type: DockerCreateContainer) {
    dependsOn buildMyAppImage
    targetImageId { buildMyAppImage.getImageId() }
    portBindings = ['8080:8080']
}

task startMyAppContainer(type: DockerStartContainer) {
    dependsOn createMyAppContainer
    targetContainerId { createMyAppContainer.getContainerId() }
}

task stopMyAppContainer(type: DockerStopContainer) {
    targetContainerId { createMyAppContainer.getContainerId() }
}

task functionalTestMyApp(type: Test) {
    dependsOn startMyAppContainer
    finalizedBy stopMyAppContainer
}

2.5.3. Linking With Other Containers

In many situations your container does not start without dependencies like database. In that case you may wish using traditional linking:

build.gradle
apply plugin: 'com.bmuschko.docker-remote-api'

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

task buildMyAppImage(type: DockerBuildImage) {
    inputDir = file('docker/myapp')
    tag = 'test/myapp'
}

task createDBContainer(type: DockerCreateContainer) {
    targetImageId { 'postgres:latest' }
    containerName "docker_auto_${buildMyAppImage.buildTagName}"
}

task createMyAppContainer(type: DockerCreateContainer, dependsOn: [buildMyAppImage, createDBContainer]) {
    targetImageId { buildMyAppImage.getImageId() }
    portBindings = ['8080:8080']

    // doFirst required! #319
    doFirst{
        // `database` there will be host used by application to DB connect
        links = [ "${createDBContainer.getContainerId()}:database" ]
    }

    // If you use Systemd in containers you should also add lines. #320
    binds = [ '/sys/fs/cgroup': '/sys/fs/cgroup' ]
    tty = true
}

task startMyAppContainer(type: DockerStartContainer, dependsOn: createMyAppContainer) {
    targetContainerId { createMyAppContainer.getContainerId() }
}

task stopMyAppContainer(type: DockerStopContainer) {
    targetContainerId { createMyAppContainer.getContainerId() }
}

task functionalTestMyApp(type: Test, dependsOn: startMyAppContainer) {
    finalizedBy stopMyAppContainer
}

3. Java Application Plugin

The plugin com.bmuschko.docker-java-application is a highly opinionated plugin for projects applying the application plugin. Under the covers the plugin preconfigures tasks for creating and pushing Docker images for your Java application. The default configuration is tweakable via an exposed extension.

3.1. Usage

build.gradle
buildscript {
    repositories {
        maven {
            url 'https://plugins.gradle.org/m2/'
        }
    }
    dependencies {
        classpath com.bmuschko:gradle-docker-plugin:3.6.1'
    }
}

apply plugin: 'com.bmuschko.docker-java-application'

3.2. Extension

The plugin defines an extension with the namespace javaApplication as a child of the docker namespace. The following properties can be configured:

Property name Type Default value Description

baseImage

String

openjdk:jre-alpine

The Docker base image used for Java application.

exec

Closure

Create ENTRYPOINT using script from Application plugin

The ENTRYPOINT and/or CMD Dockerfile instructions

maintainer

String

Value of user.home system property

The name and email address of the image maintainer (Deprecated).

port

Integer

8080

The Docker image entry point port used for the Java application (Deprecated)

ports

Integer[]

[]

The Docker image exposed ports (if provided, this values will override port configuration property)

tag

String

<project.group>/<applicationName>:<project.version>

The tag used for the Docker image.

build.gradle
docker {
    javaApplication {
        baseImage = 'dockerfile/java:openjdk-7-jre'
        maintainer = 'Benjamin Muschko "benjamin.muschko@gmail.com"'
        ports = [9090, 5701]
        tag = 'jettyapp:1.115'
    }
}

3.2.1. Adding custom instructions to Dockerfile

The exec extension property accepts a Closure which delegates to the Dockerfile.CompositeExecInstruction subset of the Dockerfile task. It allows for specifying custom ENTRYPOINT or CMD commands at an appropriate location in the Dockerfile.

build.gradle
docker {
    javaApplication {
        baseImage = 'dockerfile/java:openjdk-7-jre'
        maintainer = 'Benjamin Muschko "benjamin.muschko@gmail.com"'
        ports = [9090, 5701]
        tag = 'jettyapp:1.115'
        exec {
            defaultCommand 'server'
            entryPoint 'myApp/bin/containerLaunch.sh'
        }
    }
}

3.3. Tasks

The plugin provides a set of tasks for your project and preconfigures them with sensible defaults.

Task name Depends On Type Description

dockerCopyDistResources

distTar

Sync

Copies the resource files (like the Java application’s TAR file) to a temporary directory for image creation.

dockerDistTar

dockerCopyDistResources

Dockerfile

Creates the Docker image for the Java application.

dockerBuildImage

dockerDistTar

DockerBuildImage

Builds the Docker image for the Java application.

dockerPushImage

dockerBuildImage

DockerPushImage

Pushes created Docker image to the repository.

3.4. Examples

The following usage examples demonstrate code for common use cases. More scenarios can be found in the functional tests.

3.4.1. Using the Plugin for an Application Run on Jetty

build.gradle
apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'com.bmuschko.docker-java-application'

version = '1.0'
sourceCompatibility = 1.7

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.eclipse.jetty.aggregate:jetty-all:9.2.5.v20141112'
}

mainClassName = 'com.bmuschko.gradle.docker.application.JettyMain'

docker {
    javaApplication {
        maintainer = 'Jon Doe "jon.doe@gmail.com"'
    }
}

3.4.2. Additional Instructions in Dockerfile

You can add additional instructions to the dockerfile using dockerDistTar and Dockerfile task DSL:

build.gradle
dockerDistTar {
    instruction {'RUN ls -la'}
    environmentVariable('JAVA_OPTS', '-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap')
}

will result in

FROM java
LABEL maintainer=user
ADD javaapp-1.0.0-SNAPSHOT.tar /
ENTRYPOINT ["/javaapp-1.0.0-SNAPSHOT/bin/javaapp"]
EXPOSE 8080
RUN ls -la

Or you can use form

build.gradle
dockerDistTar.instructionsFromTemplate file('Dockerfile.tmpl')

4. Spring Boot Application Plugin

The plugin com.bmuschko.docker-spring-boot-application is a highly opinionated plugin for projects applying the Spring Boot plugin. Under the covers the plugin preconfigures tasks for creating and pushing Docker images for your Spring Boot application. The default configuration is tweakable via an exposed extension. The plugin reacts to either the java or war plugin.

4.1. Usage

build.gradle
buildscript {
    repositories {
        maven {
            url 'https://plugins.gradle.org/m2/'
        }
    }
    dependencies {
        classpath com.bmuschko:gradle-docker-plugin:3.6.1'
    }
}

apply plugin: 'com.bmuschko.docker-spring-boot-application'

4.2. Extension

The plugin defines an extension with the namespace springBootApplication as a child of the docker namespace. The following properties can be configured:

Property name Type Default value Description

baseImage

String

openjdk:jre-alpine

The Docker base image used for the Spring Boot application.

ports

Integer[]

[8080]

The Docker image exposed ports.

tag

String

<project.group>/<project.name>:<project.version>

The tag used for the Docker image.

build.gradle
docker {
    springBootApplication {
        baseImage = 'openjdk:8-alpine'
        ports = [9090, 8080]
        tag = 'awesome-spring-boot:1.115'
    }
}

4.3. Tasks

The plugin provides a set of tasks for your project and preconfigures them with sensible defaults.

Task name Depends On Type Description

dockerSyncArchive

assemble

Sync

Copies the Spring Boot archive to a temporary directory for image creation.

dockerCreateDockerfile

bootJar or bootWar

Dockerfile

Creates the Docker image for the Spring Boot application.

dockerBuildImage

dockerCreateDockerfile

DockerBuildImage

Builds the Docker image for the Spring Boot application.

dockerPushImage

dockerBuildImage

DockerPushImage

Pushes created Docker image to the repository.

4.4. Examples

The following usage examples demonstrate code for common use cases. More scenarios can be found in the functional tests.

4.4.1. Using the Plugin For an Application Run on Tomcat

build.gradle
plugins {
    id 'war'
    id 'org.springframework.boot' version '2.0.3.RELEASE'
    id 'io.spring.dependency-management' version '1.0.5.RELEASE'
    id 'com.bmuschko.docker-spring-boot-application'
}

version = '1.0'
sourceCompatibility = 8
targetCompatibility = 8

repositories {
    jcenter()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
    providedRuntime 'org.apache.tomcat.embed:tomcat-embed-jasper'
}

docker {
    springBootApplication {
        baseImage = 'openjdk:8-alpine'
    }
}

5. About This Project

5.2. Contributing

Over the years, the plugin has tremendously grown in popularity. Contributions from the community are very welcome. Have a look at the contribution guidelines to get started.

5.3. Development

5.3.1. Executing the Plugin’s Test Suite With Custom Configuration

It is required to install and run Docker Community Edition (CE) on the machine running tests. Please refer to the installation manual for more information. The default setup can be configured with the help of the properties shown in the table below:

Description System/Project Property Environment Variable Default Value

Docker server URL

dockerServerUrl

DOCKER_HOST

unix:///var/run/docker.sock

Docker cert path

dockerCertPath

DOCKER_CERT_PATH

null

Docker private registry URL

dockerPrivateRegistryUrl

DOCKER_REGISTRY_HOST

http://localhost:5000

The following usage examples demonstrates running functional tests against the a Docker instance:

$ ./gradlew functionalTest

OR

$ ./gradlew functionalTest -PdockerServerUrl=unix:///var/run/docker.sock

OR

$ ./gradlew functionalTest -DdockerServerUrl=unix:///var/run/docker.sock

OR

$ export DOCKER_HOST=unix:///var/run/docker.sock && ./gradlew functionalTest

OR

$ ./gradlew functionalTest -PdockerServerUrl=http://192.168.59.103:2376

5.4. Release Process

This section describes the release process designed and implemented for this project. Its main purpose is to explain to developers and maintainers how to prepare and release a new version of the binaries and the documentation.

5.4.1. Tools

The release process uses some external libraries and services described in detail below.

gradle-git

The gradle-git plugin is used to automatically determine the project version. org.ajoberstar.release-opinion is applied in the main build.gradle and configured in gradle/release.gradle. Please refer to the plugin documentation for more details.

gradle-git-publish

The gradle-git-publish Gradle plugin is used to publish the documentation to gh-pages branch. It is applied and configured in the gradle/documentation.gradle file.

Travis CI

Travis CI service is used as our current CI/CD server. Build and deploy jobs are configured in .travis.yml file. Please refer its documentation for more details.

Bintray’s JCenter

Bintray’s JCenter service is used to publish plugin versions. The Bintray plugin uploads artifacts to a remote repository. The plugin configuration can be found in the gradle/publishing.gradle file.

5.4.2. Workflow

The release process is automated to some extent. The following steps describe the workflow.

  1. Developer updates RELEASE_NOTES.md with new planned version.

  2. Developer commits all changes in local working copy.

  3. Developer triggers new version release using the following command: ./gradlew release -Prelease.stage=final -Prelease.scope=[SCOPE] where [SCOPE] can be one of major, minor or patch, and determines which part of the version string <major>.<minor>.<patch> will be incremented.

  4. Gradle executes a build on developer’s machine which calculates new version string, creates new tag with it and pushes to the origin.

  5. When Gradle build is finished, developer’s work is done and the rest of the release process is automated.

  6. After push to the origin, Travis detects new tag and triggers a build.

  7. Travis is instructed to execute release stage when on Git tag.

  8. In this stage Gradle script assembles plugin binaries (with new version) and uploads them to Bintray (credentials are stored as secure variables in Travis). Furthermore, the API docs and the user guide are published to gh-pages branch (the access token is stored as secure variable).