Continues Delivery with Heroku
Overview¶
Continuous Delivery (or Continuous Deployment, or CD) is a software engineering approach in which software functionalities are delivered frequently through automated deployments.
We will be using Heroku, a platform as a service (PaaS) based on a managed container system, with integrated data services, for deploying and running software applications. Heroku is primed for continuous delivery.1 It is, in a nutshell, a cloud application platform that lets you deploy your server online. By taking care of most things related to deployment, it makes it easy to get your application up and running.
Deploying Javalin on Heroku¶
Before we get started, you must:
- Create a free Heroku account (sign up)
- Install the Heroku CLI
Build a simple Javalin App¶
Create a new Gradle Java project herokuDemo
in IntelliJ and add the following dependencies to it
1 2 | compile 'org.slf4j:slf4j-simple:1.8.0-beta4' compile 'io.javalin:javalin:3.7.0' |
Create the following Java class:
1 2 3 4 5 6 7 | public class Application { public static void main(String[] args) { final int PORT = 7000; Javalin app = Javalin.create().start(PORT); app.get("/", ctx -> ctx.result("Hello Heroku!")); } } |
You can run this application and point your browser to http://localhost:7000/
to see the Hello Heroku!
message!
Prepare to deploy¶
We want to package our Javalin application as a single executable file that can be run on Heroku. We are going to make a fat JAR
file2 for this purpose.
A fat JAR contains your application and all the dependencies needed to run your application.
Gradle is able to package your Java application into a JAR file but, by default, it does so without including the project dependencies.
We can overwrite the default behavior by adding a few lines to the project's build.gradle
:
1 2 3 4 5 6 7 8 | jar { manifest { attributes 'Main-Class' : 'Application' } from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } } |
Now you can run Gradle's jar
task: open the terminal at the root directory of your Java project and type the following command:3
1 | $ ./gradlew build jar |
Once the process is finished, you can find your newly packaged JAR file in the build/libs
directory. Verify that the archive is valid by running the following command:
1 | $ java -jar build/libs/herokuDemo-1.0-SNAPSHOT.jar |
Heroku Gradle Plugin¶
To deploy Gradle based JVM applications directly to Heroku, we will use a heroku-gradle plugin. Add the plugin to your build.gradle
:
1 2 3 | plugins { id "com.heroku.sdk.heroku-gradle" version "1.0.4" } |
Moreover, you need to add a configuration for the heroku-gradle plugin; add the following to your build.gradle
:
1 2 3 4 5 6 | heroku { jdkVersion = 1.8 processTypes( web: "java -jar build/libs/herokuDemo-1.0-SNAPSHOT.jar" ) } |
Making Javalin Listen on the Correct Port¶
When we deployed Javalin locally, we used the 7000
port on localhost
. Heroku assigns your application a new port every time you deploy it, so we have to get this port and tell Javalin to use it:
1 2 3 4 5 6 7 8 9 10 11 12 13 | public static void main(String[] args) { final int PORT = getHerokuAssignedPort(); Javalin app = Javalin.create().start(PORT); app.get("/", ctx -> ctx.result("Hello Heroku!")); } private static int getHerokuAssignedPort() { String herokuPort = System.getenv("PORT"); if (herokuPort != null) { return Integer.parseInt(herokuPort); } return 7000; } |
Heroku needs Git¶
Heroku is deeply integrated with the Git workflow. To create and deploy a heroku app, you must make sure the project is tracked by a Git repository. If that is not the case, make one in terminal (you need initiate git at the root of your Gradle-Java project):
1 | $ git init |
Deploy¶
Before deployment, you must create a Heroku app using the Heroku CLI; open the terminal at the root directory of your Java project and type the following command:
1 | $ heroku create |
Note
You "create" the app once, before deploying for the first time.
Then, run the following command:4
1 | $ ./gradlew build deployHeroku |
If all goes well, you will get a message that looks like this
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | > Task :deployHeroku -----> Packaging application... - app: evening-hollows-96506 - including: build/ -----> Creating build... - file: build/heroku/build.tgz - size: 4MB -----> Uploading build... - success -----> Deploying... remote: remote: -----> heroku-gradle app detected remote: -----> Installing JDK 1.8... done remote: -----> Discovering process types remote: Procfile declares types -> web remote: remote: -----> Compressing... remote: Done: 55.1M remote: -----> Launching... remote: Released v3 remote: https://evening-hollows-96506.herokuapp.com/ deployed to Heroku remote: -----> Done BUILD SUCCESSFUL in 17s 5 actionable tasks: 2 executed, 3 up-to-date |
You can point your browser to the URL of your Heroku application. For example, the example above is deployed at https://evening-hollows-96506.herokuapp.com/.
SparkJava and Heroku
Deploying a SparkJava application to Heroku is almost identical. Here is a repository to demonstrate the process for your reference.
-
Read more about Continuous Delivery on Heroku at https://www.heroku.com/continuous-delivery. ↩
-
JAR stands for Java ARchive. It is used for aggregating many Java files into one. It is the preferred way to bundle a Java application. Read more on Oracle's website. ↩
-
You can also run this task in IntelliJ from the Gradle Tool Window ↩
-
You can configure IntelliJ to run this task by following the instructions here. ↩