1. Overview

In this tutorial, we’ll look at ways to deploy a simple Spring Boot Java app to the cloud using Heroku, a platform that simplifies app deployment, management, and scaling by handling infrastructure.

2. Installation

For the purpose of this article, we’ll be using a simple Hello World Spring Java app, with Maven as a build system. The app will have one mapping that returns Hello, Heroku! when accessed.

2.1. Project Setup

With the Hello World project open, let’s add a few configuration files.

To begin, we create a Procfile in the project’s root directory. This file defines process types and explicitly outlines the command to launch our application. Once created, we add the following command:

web: java -Dserver.port=$PORT -jar target/*.jar

Now, we create a system.properties file within the root folder. In this file, we’ll specify the Java Runtime Environment that Heroku should use. By default, Heroku uses Java 8:

java.runtime.version=17

We’ve finished setting up our project. Next, we’ll configure Heroku, which will prepare us for deployment.

2.2. Heroku Setup

A requirement of the Heroku CLI is Git, and as such, we need to have it installed before proceeding.

Let’s log into the Heroku website and download the CLI client for Windows or use brew tap heroku/brew && brew install heroku for Mac.

Once installed, we can now create a Heroku project via the website or the CLI. Let’s open a terminal window and navigate to our project.

In order to use Heroku, we’ll need to log in with the CLI by using the command heroku login.

We now need to create a Git repo with git init as well as a Heroku app with heroku create. The system assigns a random name to the default app and sets the region to United States. However, users can easily modify these settings through the platform website.

3. Deploy via Heroku CLI

Let’s stage and commit our code and push the changes to the Heroku repository with git push heroku main.

Heroku automatically detects our Java application and initiates the build process. Upon successful completion, we can access our application through a web browser by visiting the provided URL, which typically resembles https://our-app-name.herokuapp.com/.

As a result, we should see the Spring app started and the website should display Hello, Heroku!.

Alternatively, we can quickly verify the app’s startup by executing heroku open in the terminal.

4. Deploy via Heroku Maven Plugin

In addition to using the CLI, Heroku supports building and releasing apps via a Maven plugin named Heroku Maven Plugin.

To use the plugin, we’ll need to add it to pom.xml:

<plugin>
    <groupId>com.heroku.sdk</groupId>
    <artifactId>heroku-maven-plugin</artifactId>
    <version>3.0.7</version>
    <configuration>
        <logProgress>true</logProgress>
    </configuration>
</plugin>

Once dependencies have been resolved, we can start deploying our app with the command mvn clean heroku:deploy.

This approach may be especially beneficial for applications that undergo lengthy compilation processes or those deployed through CI.

The plugin provides us with several configurations, contained in the configuration element of the pom.xml file. Let’s explore some of them.

To begin with, we can set the JDK version to be used by the plugin, which overrides the system.properties setting:

<jdkVersion>17</jdkVersion>

Additionally, we can configure variables, which override previously defined variables:

<configVars>
    <MY_VAR>SomeValue</MY_VAR>
</configVars>

Moreover, we can specify the command to start the application:

<processTypes>
    <web>java -Dserver.port=$PORT -jar target/*.jar
</processTypes>

5. Deploy via CI/CD Pipelines

For the next part of the article, we’re going to explore deployment with GitHub and GitLab.

Heroku provides us with a direct connection to GitHub, making it easier to deploy our app. With GitLab, on the other hand, a pipeline needs to be configured.

To use these options, we’ll need to have the project pushed to a repository on these platforms.

5.1. GitHub

With the Heroku website open, we select the project we’ve been working on. Subsequently, we navigate to the Deploy tab and choose GitHub as the deployment method.

After a quick sign-in, we search for and select our repository. Then, we enable Automatic Deploys so that any push to the main branch will automatically trigger a deployment on Heroku.

5.2. GitLab

With GitLab, we’ll have to add a .gitlab-ci.yml file to our project:

image: maven:3.8.7-eclipse-temurin-17

stages:
  - test
  - deploy

cache:
  paths:
    - .m2/repository
    - target

unit-test:
  stage: test
  image: maven:latest

  script:
    - echo "Maven test started"
    - "mvn test"

deploy_job:
  stage: deploy
  image: maven:latest

  script:
    - HEROKU_API_KEY=${HEROKU_API_KEY} mvn clean heroku:deploy

Additionally, we’ll need to add the Heroku API key to the GitLab CI/CD variables found in project Settings. The API key can be retrieved from the Heroku website by visiting the user profile.

Since we’re utilizing the Heroku Maven Plugin in our script, we need to incorporate an additional configuration into the pom.xml file. Specifically, we must add the application name as it appears on the Heroku platform. To achieve this, we define the application name within the plugin’s configuration element:

<appName>our-app-name</appName>

Pushing our change initiates the pipeline, which subsequently deploys the app.

6. Deploy With Docker

Assuming Docker is installed locally, we begin by creating a Dockerfile within the project’s root directory. We then populate with the following:

FROM maven:3.8.4-openjdk-17 AS build

WORKDIR /app

COPY . .

RUN mvn clean package -DskipTests

FROM openjdk:17-jdk-slim

WORKDIR /app

COPY --from=build /app/target/*.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]

With the above script, we use Maven to build the application, copy the built .jar file into a slimmer JDK image, and, expose port 8080 for the application to run.

Second, we need to add the application.properties file inside our resource folder to set the server port:

server.port=${PORT:8080}

By doing this, Docker can map the port to our Spring application port.

Third, we’ll build and execute the Docker image, ensuring its proper functionality:

docker build -t our-heroku-app .
docker run -p 8080:8080 our-heroku-app

Let’s curl localhost:8080 to check for the Hello, Heroku! string.

Finally, we must deploy and release our changes to Heroku. To achieve this, let’s execute a few commands in the terminal.

We start by running heroku container:login, to log us into the Heroku Container Registry. We then build and push the Docker image to Heroku with heroku container:push web –app our-heroku-app. Lastly, to release the image of our app, we use heroku container:release web –app our-heroku-app.

After release, our app should be live and we can verify by using the command heroku open –app our-heroku-app.

7. Conclusion

In this article, we’ve explored multiple approaches to deploying a Java app on Heroku.

We saw how to effortlessly set up and deploy a Heroku app using the provided CLI.

Furthermore, we leveraged the Heroku Maven Plugin’s commands to streamline deployments from both the terminal and CI/CD environments.

Finally, we understood the benefits of Docker for quick app deployment.

As always, the code can be found over on GitHub.