Deploying Gradle Apps to Heroku with Docker

In this post, you’ll learn how to deploy a Docker-based Gradle application to Heroku using the Heroku Docker CLI. We’ll use a simple Ratpack app as an example, but you can follow along with any Gradle application. This is a Mac and Linux guide only (until Docker supports docker-compose on Windows).

Prerequisites

You’ll need a few pieces of software before you get started:

You’ll also need to create a free Heroku account. Then login from the terminal like so:

$ heroku login

Once that’s complete, you can install the Heroku Docker CLI with this command:

$ heroku plugins:install heroku-docker

Now you’re ready to deploy.

Deploying an App

To begin, clone the Ratpack demo app to your local machine:

$ git clone https://github.com/heroku/gradle-getting-started
$ cd gradle-getting-started

The app is already prepared for Heroku. It contains a Procfile, which tells Heroku how to run the app, and an app.json file that contains some meta-data about the app. The important part of the app.json file is the "image" element, shown below:

{
  "name": "Getting Started with Gradle on Heroku",
  "description": "A bare-bones Ratpack app, which can easily be deployed to Heroku.",
  "image": "heroku/gradle",
  "addons": [ "heroku-postgresql" ]
}

The "image" element is what Heroku uses to determine the base Docker image to run the container from. The "addons" element determines what additional services will be attached to your container. The Heroku currently supports Postgres, Redis and a few others services with more to come. Given this configuration, we can initialize the app with the following command:

$ heroku docker:init
Wrote Dockerfile
Wrote docker-compose.yml

This created a Dockerfile based on the heroku/gradle image and a docker-compose.yml defining the containers in your environemnt (including a local Postgres database running on Docker).

Now run this command to start the application in a container:

$ docker-compose up web

The first time you run this it will take a while as Gradle downloads the app’s dependencies into the Docker container. Dut don’t worry, they’ll be cached. You’ll also see a Postgres database initialize and start up – all running locally.

When the container has finished booting, you’ll see some output like this:

web_1 | [main] INFO ratpack.server.RatpackServer - Ratpack started for http://localhost:8080

Open the app in a browser by running this command:

$ open "http://$(docker-machine ip default):8080"

Now try accessing the database. The sample contains a little bit of code that inserts a value into a column. It looks like this:

Statement stmt = connection.createStatement();
stmt.executeUpdate("CREATE TABLE IF NOT EXISTS ticks (tick timestamp)");
stmt.executeUpdate("INSERT INTO ticks VALUES (now())");
ResultSet rs = stmt.executeQuery("SELECT tick FROM ticks");

Browse to the /db path to see it in action:

$ open "http://$(docker-machine ip default):8080/db"

Your containerized web app and database are now connected. You’ve created a local cloud right here on your machine. Now you can create a Heroku app and deploy to the public cloud. First, provision a new app thusly:

$ heroku create
Creating limitless-mesa-1279... done, stack is cedar-14
https://limitless-mesa-1279.herokuapp.com/ | https://git.heroku.com/limitless-mesa-1279.git

And deploy to Heroku with the Docker CLI

$ heroku docker:release
Remote addons: heroku-postgresql (1)
Local addons: heroku-postgresql (1)
Missing addons:  (0)
Creating local slug...
Building web...
...
uploading slug...
releasing slug...
Successfully released limitless-mesa-1279!

You can open the remote app with this command:

$ heroku open

Now you can get to work on modifying this app.

Development Workflow

In your normal workflow, you’d want to make some changes and see them appear in the Docker container. We’ll demonstrate how that works. Open the src/main/java/Main.java and look for the /hello route:

.get("hello", ctx -> {
  ctx.render("Hello!");
})

Change the "Hello!" string to anything you’d like. Save the file, and then run these commands:

$ docker-compose build web
...
$ docker-compose up web
...
web_1 | [main] INFO ratpack.server.RatpackServer - Ratpack started for http://localhost:8080

Open the app in a browser again and navigate to the /hello path to see your changes. Each time you modify your app, you need to re-build the image and then launch the up command. You can also get terminal access to the image by running the shell command thusly:

$ docker-compose build shell
Building shell...
...
root@7c7b5905b2a0:~/user#

From this shell, you can run one-off tasks like database migrations.

Heroku’s Docker support is currently in beta. As we work to make the integration better, we’d love to hear your feedback so we can focus on building the things you need. Feel free to reach out to me directly with you thoughts and ideas.

You can visit the Heroku Dev Center for more information on Heroku’s Docker CLI. And you can learn more about Ratpack and Docker from their respective documentation sites. You can also find more information about deploying Gradle apps to Heroku on the Dev Center.