You are currently viewing A pipeline to the cloud for spring boot microservices

A pipeline to the cloud for spring boot microservices

Automating the build pipeline to the cloud, the simple way

In this brief tutorial I’ll show you how to set up a Spring Boot project for deploying it into the cloud.

There are various tutorials for each single step here but I found none for the full process.

I’ll cover the basic set up, the configuration for testing, the build and deployment pipeline.

What you will need:

  • git installed
  • Atlassian Bitbucket account (it’s free you can create one here)
  • Heroku account (also free, here)
  • An IDE is nice to have (VS Code, IntelliJ, eclipse, whatever you prefer)

Set up the project using spring-initializr

Go to https://start.spring.io/ and generate your project with the following dependencies

  • Cloud Connectors
  • Spring Web Starter

Choose Java 11 in the Options
Download the resulting zip file and unpack it on your local drive.

Additional set up

We need some more dependencies and configuration than the spring initializr will include, so please copy the pom.xml from here:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.7.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <groupId>io.gaddings</groupId>
  <artifactId>cloud-deployment</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>cloud-deployment</name>
  <description>Demo project for Spring Boot</description>

  <properties>
    <java.version>11</java.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-cloud-connectors</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>rest-assured</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
      <plugin>
        <artifactId>maven-failsafe-plugin</artifactId>
        <version>2.22.0</version>
        <configuration>
          <includes>
            <include>**/*IT</include>
          </includes>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

Adding the “maven-failsafe-plugin” to the configuration here will allow us to execute unit tests and integration tests in separate steps of the maven lifecycle (test and verify).

Note: We will use Java 11 for this tutorial. Since the default version used by Heroku still is 8 we need to specify this.

To do that create a file named “system.properties” in your project root directory with the following content:

java.runtime.version=11

Do some hello world stuff

Note: This is not a Spring Boot tutorial. It’s all about the build and deployment pipeline. The code here has little practical use.

Create a class HelloWorldController.java (in a subpackage):

package io.gaddings.clouddeployment.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloWorldController {

  @GetMapping("/hello")
  public String helloWorld() {
    return "Hello, World!";
  }

}

Then create a unit test for it (in the test packages of course):

package io.gaddings.clouddeployment.controller;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.Before;
import org.junit.Test;

public class HelloWorldControllerTest {

  private HelloWorldController subject;

  @Before
  public void setUp() {
    this.subject = new HelloWorldController();
  }

  @Test
  public void testHello() {
    assertThat(this.subject.helloWorld()).isEqualTo("Hello, World!");
  }

}

And then, an integration test:

package io.gaddings.clouddeployment.controller;

import static io.restassured.RestAssured.get;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

import io.gaddings.clouddeployment.CloudDeploymentApplication;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.HttpStatus;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {CloudDeploymentApplication.class},
    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class HelloWorldControllerIT {

  @LocalServerPort
  private int port;

  private String apiEndpoint;

  @Before
  public void setUp() {
    this.apiEndpoint = "http://localhost:" + port + "/hello";
  }

  @Test
  public void testHello() {
    assertThat(get(apiEndpoint).getStatusCode()).isEqualTo(HttpStatus.OK.value());
  }

}

Commit it to Bitbucket

Log into your Bitbucket account and create a project (git, java) there.
Copy the git URL. Open your terminal and follow the instructions.

git init
git add --all
git commit -m "Initial commit"
git remote add origin <your URL here>
git push origin master

After you have pushed your stuff you should see it in the bitbucket UI.

Create a build pipeline script

You can actually do this via Bitbucket itself. Just click on the “pipelines” section and choose the Java template.

Create a pipeline script like this (bitbucket-pipelines.yml):

image: maven:3.6.1

pipelines:
  default:
    - step:
        name: Build and test
        caches:
          - maven
        script:
          - mvn clean verify

This will build and test your project automatically on every push.
Depending on your settings in Bitbucket you’ll receive an e-mail notification when you break the build.

Commit your script and watch your pipeline getting executed, if you want.

Throw your app into the cloud

Log into your Heroku account and create a project there.
In Heroku you can deploy your app using git. You just need to push it there and it will build it and run it. It’s made for cloud-native apps, like the one we build here.

Heroku App
The gaddings-cloud-deployment project will not be available for you 😉

Instead of doing deployment manually (Heroku itself has great documentation and tools for that, if you want to know), we prefer to have it deployed whenever the master branch is built successfully.

For achieving this you need to find your API key in the Heroku settings (it looks like a UUID). And combine it with you repository URL like this:

https://heroku:<API-KEY>@git.heroku.com/gaddings-cloud-deployment.git

(where gaddings-cloud-deployment is your projects/repositories name of course)

This URL can now be entered in bitbucket in the “Settings” – “Repository variables” section.
Choose HEROKU_ADDRESS as the name and the URL as the value.

Bitbucket Repository variables
Repository variable for Heroku deployment

Then extend your pipeline script to match the following:

image: maven:3.6.1

pipelines:
  default:
    - step:
        name: Build and test
        caches:
          - maven
        script:
          - mvn clean verify
  branches:
    master:
      - step:
          name: Build and test
          caches:
            - maven
          script:
            - mvn clean install
      - step:
          name: Release to heroku
          script:
            - git push $HEROKU_ADDRESS HEAD:master

This will result in two steps for the master branch:
The first also builds and tests. The second is executed when the first step was successful and will push it to heroku.

Commit it and watch the “terminal” again.

Second run of the Bitbucket pipeline
Second run of the Bitbucket pipeline (actually the third for me, I misclicked…)

And that’s it. As soon as the build on the heroku side is done, your app is up and running.

Go to https://<your-app-name>.herokuapp.com/hello and enjoy!

Final words

Congratulations! You just deployed your first microservice to the cloud!

Is it as simple as that in your companies environment? It should be. Or even easier, considering that you can create templates for almost everything.
If it’s not you can probably change this now!