Sunday, December 20, 2015

How to build docker image from Gradle


Once you have an application written in Java and built with Gradle the natural step in these days might be to put this app into a Docker container. And there is a possibility to build docker images directly from Gradle (which is a preferred way for me - much better than having an external script with docker commands).

First possibility is to use some ready made solution like a gradle plugin. There are few of them, but I have experience with gradle-docker. What it does for you is that it even creates a Dockerfile - you just have to describe its contents in a DSL provided by the plugin. The result might look like this:

apply plugin: 'com.bmuschko.docker-java-application
docker {
    url = 'unix:///var/run/docker.sock'
    javaApplication {
        baseImage = 'java:8'
        maintainer = 'Alena Varkočková'
        port = 80
        tag = "someinternaldockerregistry.com/${project.group}/$applicationName:$version"
    }
    registryCredentials {
        url = 'someinternaldockerregistry.com'
    }
}
In the background these properties are transformed to the actual dockerfile, that is saved into the build/docker folder. But to be honest, I don’t like this approach at all - instead of using a pretty straightforward language of Dockerfiles that you are probably already familiar with, you have to learn new DSL and hope that the result will be what you are expecting it to be. I think that everyone working with Docker should know the Dockerfile format and should write that by himself/herself. So my next step was to use the plugin to build the image but use my own  Dockerfile. And you can do that quite easily.
apply plugin: 'com.bmuschko.docker-remote-api'

import com.bmuschko.gradle.docker.tasks.image.DockerBuildImage
import com.bmuschko.gradle.docker.tasks.image.DockerPushImage
import com.bmuschko.gradle.docker.DockerRegistryCredentials

def DOCKER_GROUP = 'docker'
def dockerRegistryCredentials = new DockerRegistryCredentials()

dockerRegistryCredentials.url = 'someinternaldockerregistry.com'
task dockerBuildImage(type: DockerBuildImage) {
    dependsOn distTar
    group = DOCKER_GROUP

    url = 'unix:///var/run/docker.sock'
    inputDir = project.projectDir
    tag = "${dockerRegistryCredentials.url}/${project.group}/$applicationName:$version"
    registryCredentials = dockerRegistryCredentials
}

task dockerPushImage(type: DockerPushImage) {
    group = DOCKER_GROUP

    dependsOn dockerBuildImage

    imageName = "${dockerRegistryCredentials.url}/${project.group}/$applicationName"
    tag = project.version
}
This is better. I was kind of excited by this approach for a little while - until I figured out that the plugin supports only a small subset of docker build options. If you need something special, you have to write it by yourself. In the background, the plugin uses another abstraction over docker, docker-java client and it actually has the same problems. Docker API is changing so rapidly and new features are coming almost instantly that these abstractions cannot keep up to this pace and you are constantly dealing with some features missing. That’s when I realized that I don’t need the abstractions at all. My last version (without the plugin) now looks like the next example. It is very simple and straightforward and I like it.

def imageName = "someinternaldockerregistry.com/${project.group}/$applicationName:$version"
task dockerBuildImage(type:Exec) {
   dependsOn distTar
   group = 'docker'

   commandLine 'docker', 'build', '-t', imageName, '--build-arg', "version=$version", '.'
}

task dockerPushImage(type:Exec) {
   dependsOn dockerBuildImage
   group = 'docker'

   commandLine 'docker', 'push', imageName
}

14 comments:

  1. Hi,

    this is going to be some kind of self advertising - but I cannot hold myself back ;-)

    You already mentioned the pain points of a restrictive abstraction on a fast moving project like Docker. I'm also an author of a Gradle Docker plugin, with yet another Docker client under the hood. In contrast to the docker-java library, I didn't try to add too much constraints or actual types on the Docker API. Instead, I more or less only adapt the HTTP layer to the Java/Groovy world.

    If you have a little bit of time, I'd be glad if you give it a try. You'll find the plugin at https://github.com/gesellix/gradle-docker-plugin, for examples just keep following the links in the readme.

    You might ask, why you should even bother. I'd say that you probably come to the point where you don't want to maintain a matching docker binary for your Gradle projects. At least that's where I came from and that one aspect I kept in mind when not adding too much restrictions or abstractions. Similar thoughts are written at https://gesellix.net/choosing-a-library/

    If you like, please leave me some feedback, either via GitHub issue tracker or via Twitter @gesellix. Thanks!

    ReplyDelete
  2. Wonderful article, very useful and well explanation. Your post is extremely incredible. I will refer this to my candidates...
    Dotnet Training in Chennai

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. this app is a one stop solution to download audio and video directly to your android mobile both youtube and others similar video sites. https://snaptube-apk.com

    ReplyDelete
  6. Among the best Android app to transfer files from mobile to mobile is Xender App. http://showbox-app.net

    ReplyDelete

  7. Thank you for taking the time to provide us with your valuable information. We strive to provide our candidates with excellent care and we take your comments to heart.As always, we appreciate your confidence and trust in us.

    SAP training in Chennai

    ReplyDelete
  8. Great and useful article. Creating content regularly is very tough. Your points are motivated me to move on.


    SEO Company in Chennai

    ReplyDelete
  9. Hey.
    Thanks for this article.
    All in all i followed the same road, i tryed some of the various docker plugins for gradle but was a bit disappointed to have to work with a specific DSL.
    In the end i also came back to a plain Dockerfile and a few gradle tasks (remotely) invoking my docker server (through a local docker client).
    I just use the "ADD" function in my Dockerfile to inject and automatically untar the build/distributions/ tar built with gradle.
    And i run the image on my remote docker server also through gradle (with a simple run --rm command), it works fine and allows to locally cancel the container/app with a regular CTRL-C.

    ReplyDelete
  10. wonderful blog about programing i really like reading it you should also visit Case Study Solution it really has some good cases you can look into

    ReplyDelete
  11. I have read your blog its very attractive and impressive. I like it your blog.

    Java Training in Chennai Core Java Training in Chennai Core Java Training in Chennai

    Java Online Training Java Online Training JavaEE Training in Chennai Java EE Training in Chennai

    ReplyDelete
  12. Actuary Assignment Help, Actuarial science assignment help in the actuarial field of science from primary to complex level for the understudies of US UK. Actuary Assignment Help

    ReplyDelete
  13. Really an amazing post..! By reading your blog post i gained more information.
    Bulk SMS Chennai

    ReplyDelete