Continuous Deployment of Spring Boot Applications using Developer Cloud and Application Container Cloud

After my post on continuous deployment using Dropwizard a colleague asked me if the same could be achieved with Spring Boot. Absolutely. The steps are virtually identical. Any Java, Node or PHP application can be continuously deployed using these developer tools. However, the proof is in the pudding, so let’s examine how this would work for a Spring Boot application.

As a starting point, I’ve decided to use the Spring Boot Getting Started application.

Step 1: Clone the Getting Started Repository

Clone the Spring Boot Getting Started guide to your local workstation:

$ git clone https://github.com/spring-guides/gs-spring-boot
Cloning into 'gs-spring-boot'...
remote: Counting objects: 943, done.
remote: Total 943 (delta 0), reused 0 (delta 0), pack-reused 943R
Receiving objects: 100% (943/943), 417.57 KiB | 428.00 KiB/s, done.
Resolving deltas: 100% (599/599), done.
Checking connectivity... done.

Since this isn’t an exercise in Spring Boot, we will jump directly to the completed application.

Step 2: Create a New Git Repository

The Developer Cloud Service deployment server polls a Git repository for changes, hence, we need to store our source in a new repository. The Developer Cloud Service provides a Git repository, but for this example I’m going to use an external GitHub repository:

https://github.com/wbleonard/accs-spring-boot.git

Step 3: Push the Getting Started Application

Return to the command prompt, switch to the completed application directory and initialize Git:

bbleonar_us@DELL-M4700 /c/GitProjects
$ cd gs-spring-boot/complete/

bbleonar_us@DELL-M4700 /c/GitProjects/gs-spring-boot/complete (master)
$ git init
Initialized empty Git repository in c:/GitProjects/gs-spring-boot/complete/.git/

bbleonar_us@DELL-M4700 /c/GitProjects/gs-spring-boot/complete (master)
$ git add .

bbleonar_us@DELL-M4700 /c/GitProjects/gs-spring-boot/complete (master)
$ git commit -m "first commit"
[master (root-commit) 2055653] first commit
 14 files changed, 850 insertions(+)
 create mode 100644 .mvn/wrapper/maven-wrapper.jar
 create mode 100644 .mvn/wrapper/maven-wrapper.properties
 create mode 100644 build.gradle
 create mode 100644 gradle/wrapper/gradle-wrapper.jar
 create mode 100644 gradle/wrapper/gradle-wrapper.properties
 create mode 100644 gradlew
 create mode 100644 gradlew.bat
 create mode 100644 mvnw
 create mode 100644 mvnw.cmd
 create mode 100644 pom.xml
 create mode 100644 src/main/java/hello/Application.java
 create mode 100644 src/main/java/hello/HelloController.java
 create mode 100644 src/test/java/hello/HelloControllerIT.java
 create mode 100644 src/test/java/hello/HelloControllerTest.java

bbleonar_us@DELL-M4700 /c/GitProjects/gs-spring-boot/complete (master)
$ git remote add origin https://github.com/wbleonard/accs-spring-boot.git

bbleonar_us@DELL-M4700 /c/GitProjects/gs-spring-boot/complete (master)
$ git push -u origin master
Username for 'https://github.com': wbleonard
Password for 'https://wbleonard@github.com':
Counting objects: 27, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (21/21), done.
Writing objects: 100% (27/27), 99.87 KiB | 0 bytes/s, done.
Total 27 (delta 0), reused 0 (delta 0)
To https://github.com/wbleonard/accs-spring-boot.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.

 Step 4: Configure for Deployment to the Application Container Cloud Service (ACCS)

manifest.json

At a minimum, we need to inform ACCS how to start the service, as well as the version of Java we want to use. This is specified in a metadata file called manifest.json. For other optional settings, see Creating Metadata Files.

Create a new manifest.json with the following contents. The command is exactly the same as if you were going to run the application locally:

{
 "runtime": {
 "majorVersion": "8"
 },
 "command": "java -jar target/gs-spring-boot-0.1.0.jar"
}

Deployment Archive

The application JAR file and the manifest.json file need to be packaged into a zip file for deployment to ACCS. We will use the Maven Assembly Plugin to accomplish this task. See the Guide to creating assemblies for more details.

Create a new folder named assembly in the src folder.

Create a new file named accs.xml in assembly folder. The name of this file is arbitrary as it will be referenced later when we configure the assembly plugin:

<?xml version="1.0" encoding="UTF-8"?>
<assembly>
    <id>ACCS</id>
    <formats>
        <format>zip</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <files>
        <file>
            <source>manifest.json</source>
            <outputDirectory>/</outputDirectory>
        </file>
    </files>
    <fileSets>
        <fileSet>
            <directory>target</directory>
            <outputDirectory>target</outputDirectory>
            <includes>
                <include>*.jar</include>
            </includes>
        </fileSet>
    </fileSets>
</assembly>

Add the Maven Assembly build plugin to pom.xml:

            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                  <descriptor>src/assembly/accs.xml</descriptor>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>                
            </plugin>

If you run the build package you would now have a gs-spring-boot-0.1.0-ACCS.zip file. This artifact is what gets deployed to ACCS.

Step 5: Commit and Push the Changes

bbleonar_us@DELL-M4700 /c/GitProjects/gs-spring-boot/complete (master)
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   pom.xml

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        manifest.json
        src/assembly/

no changes added to commit (use "git add" and/or "git commit -a")

bbleonar_us@DELL-M4700 /c/GitProjects/gs-spring-boot/complete (master)
$ git add pom.xml manifest.json src/assembly/accs.xml

bbleonar_us@DELL-M4700 /c/GitProjects/gs-spring-boot/complete (master)
$ git commit -m "Configured application for deployment to ACCS"
[master 9d1003b] Configured application for deployment to ACCS
 3 files changed, 44 insertions(+)
 create mode 100644 manifest.json
 create mode 100644 src/assembly/accs.xml

bbleonar_us@DELL-M4700 /c/GitProjects/gs-spring-boot/complete (master)
$ git push
Username for 'https://github.com': wbleonard
Password for 'https://wbleonard@github.com':
Counting objects: 10, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (7/7), 1.00 KiB | 0 bytes/s, done.
Total 7 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To https://github.com/wbleonard/accs-spring-boot.git
   2055653..9d1003b  master -> master

Step 6: Configure for Continuous Delivery

Create a Build Job

Log into the Developer Cloud Service and create a new Build job as follows:

Create a new free-style Build Job named something like Spring Boot GS:

sb01_new-job

Set the JDK to JDK 8:

sb02_jdk

Switch to the Source Control tab and set the URL to your Git repository:

sb03_repo

Switch to the Triggers tab and and select Based on SCM Polling schedule and set the Schedule to * * * * *, which will poll for changes every minute. See Configuring Build Triggers for details on how to adjust this expression to suite your needs.

sb04_triggers

Switch to the Build Steps tab and add a Maven 3 build step. Set the Goals to package. Everything else can remain as is:

sb05_build-step

Switch to the Post Build tab select Archive the Artifacts. Set the Files to Archive to **/target/*.zip:

sb06_archive

Save the configuration and click Build Now. Wait while the build is queued and picked up by the build server:

sb07_build

Once the build build begins you can monitor the console output. It should take about 1 1/2 minutes to complete.

Create a Deploy Configuration

Switch to the Deploy tab and create a New Configuration. For the Deployment Target, either select and existing or create a New Application Container Cloud:

sb08_target

Set the remaining values as follows:

Configuration Name: BootStrapGS
Application Name: BootStrapGS

Verify the Runtime is Java.

Be sure to set the Type to  Automatic and select Deploy stable builds only.

Set the Job to Spring Boot GS and set the Artifact to target/gs-spring-boot-0.1.0-ACCS.zip.

sb09_depoy

Click Save and then Start the deployment:

sb10_start

Wait for the deployment to complete, which should only take about a minute:

sb11_started

Use

Switch to the Application Contain Cloud Service to see your deployed application:

sb12_accs

And click the link provided to launch your application. Here’s mine:

https://springbootgs-gse00001975.apaas.em2.oraclecloud.com/

sb13_run

Notice you have all the mapping goodness that comes with Spring Boot, such as:

Continuous Deployment

Now let’s make a change to the application and watch it propagate through to deployment.

Return to the local copy of the application and edit the text returned from HelloController.java. For example:

package hello;

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

@RestController
public class HelloController {
    
    @RequestMapping("/")
    public String index() {
        return "Greetings from Spring Boot running on ACCS!";
    }
    
}

Then commit and push the change to GitHub:

bbleonar_us@DELL-M4700 /c/GitProjects/gs-spring-boot/complete (master)
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   src/main/java/hello/HelloController.java

no changes added to commit (use "git add" and/or "git commit -a")

bbleonar_us@DELL-M4700 /c/GitProjects/gs-spring-boot/complete (master)
$ git add src/main/java/hello/HelloController.java

bbleonar_us@DELL-M4700 /c/GitProjects/gs-spring-boot/complete (master)
$ git commit -m "Updated the greeting"
[master 5245eec] Updated the greeting
 1 file changed, 1 insertion(+), 1 deletion(-)

bbleonar_us@DELL-M4700 /c/GitProjects/gs-spring-boot/complete (master)
$ git push
Username for 'https://github.com': wbleonard
Password for 'https://wbleonard@github.com':
Counting objects: 13, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (7/7), 557 bytes | 0 bytes/s, done.
Total 7 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), completed with 3 local objects.
To https://github.com/wbleonard/accs-spring-boot.git
   9d1003b..5245eec  master -> master

This will trigger a build and if the build is successful, a deploy. However, our change caused the build to fail a test:

sb14_failed-test

We also need to update the test with our new greeting.

public class HelloControllerTest {

    @Autowired
    private MockMvc mvc;

    @Test
    public void getHello() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().string(equalTo("Greetings from Spring Boot running on ACCS!")));
    }
}

Once we commit and push that change, the build will trigger again, successfully complete and trigger a deploy. After a few minutes, our updated application will be running:
https://springbootgs-gse00001975.apaas.em2.oraclecloud.com/.

 

Advertisements

One thought on “Continuous Deployment of Spring Boot Applications using Developer Cloud and Application Container Cloud

  1. Pingback: Building Developer Cloud Applications Using Gradle | W Brian Leonard

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s