Docker Containers With Gradle in 4 Steps

fourdoor Do you need to create a Docker image from your Java web app? Are you using Gradle? If so, then you are only 4 steps away from Docker nivana.

For this example, I’m going to use a simple Spring Boot application. You can find all the source code in my Github repository dubbed galoshe.

If you haven’t had a chance to see Spring Boot in action, then you’re in for a treat, especially if the words simple and Java web app in the same sentence make you flinch. That was certainly my long standing reaction until I took a serious look at Boot.

For instance, a quick and dirty “hello world” Boot app is essentially more imports & annotations than actual code. Check it out:

A simple Spring Boot application

package com.github.aglover.galoshe;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {

  public static void main(String[] args) {
    ApplicationContext ctx = SpringApplication.run(Application.class, args);
  }

  @RequestMapping("/")
  public String index() {
    return "Hello to you, world";
  }
}

Running this application is as easy as typing:

$ java -jar build/libs/galoshe-0.1.0.jar

That command will fire up an embedded web container with the request path / mapped to return the simple String “Hello to you, world”. You can define what port this application will run on via an application.properties file like so:

application.properties

server.port: 8080

Consequently, if I take my browser and point it to localhost:8080, I see the pedestrian, but oh-so-gratifying-when-you-see-it salutation.

Now that you’ve been introduced to the application I’d like to distribute as a Docker container, let me show you how to do it in 4 easy steps.

Keep in mind, however, that in order to use the gradle-docker plugin I use in this example, you’ll need to have Docker installed as the plugin shells out to the docker command.

Step 1: Apply some plugins

First and foremost, to Docker-ize your application, you’ll need to use two Gradle plugins: docker and application.

The gradle-docker plugin by Transmode is actually 1 of 2 available plugins for Dockering with Gradle. The other plugin by Ben Muschko of Gradleware is a bit more advanced with additional features, however, I find the Transmode plugin the easiest and quickest to get going.

The application plugin is actually included automatically via the spring-boot plugin in my particular example, however, if you aren’t using Boot, then you’ll need to add the following two plugins to your build.gradle file:

apply plugin: 'application'
apply plugin: 'docker'

As the docker plugin is a 3rd party plugin, you’ll need to tell Gradle how to find it via a dependencies clause.

Specifying the classpath for the docker plugin

buildscript {
    repositories { mavenCentral() }
    dependencies {
        classpath 'se.transmode.gradle:gradle-docker:1.1'
    }
}

Now your Gradle script is ready to start Docker-ing. Next up, you’ll need to provide some clues so the plugin can create a valid Dockerfile.

Step 2: Provide some properties

The gradle-docker plugin doesn’t directly create a Docker container – it merely creates a Dockerfile and then shells out to the docker command to build an image. Consequently, you need to specify a few properties in your build.gradle file so that the corresponding Dockerfile builds a valid container that automatically runs your application.

You need to provide:

  • The class to run i.e. the class in your application that contains a main method
  • The target JVM version (default is Java 7)
  • Optionally, a group id, which feeds into the corresponding Docker tag.

Accordingly, my build.gradle defines all three properties like so:

Defining properties for the docker plugin

group = 'aglover'
sourceCompatibility = 1.7
mainClassName = 'com.github.aglover.galoshe.Application'

A few notes about these properties. Firstly, Java 8 isn’t currently available for this plugin. If you don’t specify a sourceCompatibility, you’ll get Java 7. Next, the group property isn’t required; however, it helps in Docker tagging. For example, my project’s baseName is dubbed galoshe; consequently, when the plugin creates a Docker image, it’ll tag that image with the pattern group/name. So in my case, the corresponding image is tagged aglover/galoshe.

Finally, the mainClassName shouldn’t be too surprising – it’s the hook into your application. In truth, the plugin will create a script that your resultant Docker image will invoke on startup. That script will essentially call the command:

java -classpath your_class_path your_main_class

At this point, you are almost done. Next up, you’ll need to specify any Dockerfile instructions.

Step 3: Specify any required Dockerfile instructions

Dockerfiles contain specialized instructions for the corresponding image they create. There are a few important ones; nevertheless, my Boot app only requires one: port, which is set via the exposePort method of the plugin.

Consequently, to ensure my Docker container exposes port 8080 as defined in my application.properites file, I’ll add the following clause to my build.gradle file:

Specifying port 8080

distDocker {
    exposePort 8080
}

A few other aspects you can muddle with via the plugin are addFile which results in an ADD instruction, runCommand, which results in a RUN instruction, and finally setEnvironment, which creates an ENV instruction.

Now you’re done with your Gradle build. All that’s left to do is run your build and fire the image up!

Step 4: Build and run it

Provided you’ve configured the gradle-plugin properly, all that’s left to do is run your build. In this case, the command is simply distDocker.

Running my build

$ ./gradlew distDocker

The first time you run this command it’ll take a bit as various images will be downloaded. Subsequent runs will be lightning quick though.

After your build completes, your image will be created with the tag I noted earlier. In my case, the tag will be aglover/galoshe, which I can quickly see by running the images command:

Listing available local Docker images

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
aglover/galoshe     latest              332e163221bc        20 hours ago        1.042 GB
dockerfile/java     latest              f9793c257930        3 weeks ago         1.026 GB

I can subsequently run my image like so:

Running my container

docker run 332e163221bc

I can naturally go to my browser, hit localhost:8080 and find myself quite satisfied that my image runs a nifty greeting.

Of course, I would need to publish this image for others to use it; nevertheless, as you can see, the gradle-plugin allows me to quickly create Docker containers for Java apps.

Reference: Docker Containers With Gradle in 4 Steps from our JCG partner Andrew Glover at the The Disco Blog blog.
Related Whitepaper:

Bulletproof Java Code: A Practical Strategy for Developing Functional, Reliable, and Secure Java Code

Use Java? If you do, you know that Java software can be used to drive application logic of Web services or Web applications. Perhaps you use it for desktop applications? Or, embedded devices? Whatever your use of Java code, functional errors are the enemy!

To combat this enemy, your team might already perform functional testing. Even so, you're taking significant risks if you have not yet implemented a comprehensive team-wide quality management strategy. Such a strategy alleviates reliability, security, and performance problems to ensure that your code is free of functionality errors.Read this article to learn about this simple four-step strategy that is proven to make Java code more reliable, more secure, and easier to maintain.

Get it Now!  

Leave a Reply


+ 8 = sixteen



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

20,709 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books