Now available! Red Hat OpenShift Container Platform for Linux on IBM Z and LinuxONE Learn more

Develop a Spring microservice for Kubernetes

This tutorial describes a quick path for a Spring REST services developer to migrate to Kubernetes.

Prerequisites

To complete this tutorial, you will need:

Notable features

The use case

I’m responsible for implementing a component of our storefront shopping application. Our implementation employs a microservices architecture. My job is to implement a microservice using Spring Boot, supporting inventory management. This will require integration with a relational database for managing inventory data, as well as integration with a messaging provider in order to receive notifications of order fulfillment.

My component will need to run in a container in a Kubernetes cluster, and I know that our solution architect has decided that we will use Kubernetes Secrets to acquire service integration credentials from the runtime environment. So, I need to deliver a solution component to our shared code repository that supports acquisition of these credentials at runtime from Kubernetes.

Background

This post is motivated by the IBM Cloud Architectures article “Microservices for fast time to market and improved app quality: Microservices with Kubernetes (Spring).”

Appsody is a component of IBM Cloud Pak for Applications. This tutorial describes a “toe in the water” developer experience. For more information on the enterprise level capabilities of IBM Cloud Pak for Applications, see the IBM Cloud Pak for Applications page on IBM Developer.

For this tutorial, the open source edition of Appsody will work. If you do not have IBM Cloud Pak for Applications, follow these instructions to install Appsody.

Direction

Spring has a Spring Cloud Kubernetes library that takes care of acquiring Kubernetes Secrets as Spring Boot configuration properties. Docker Desktop provides a small Kubernetes cluster that can be used on a development box to test Kubernetes integration. Appsody can help simplify the deployment of a containerized microservice solution component to Kubernetes.

This tutorial describes how to:

  1. Bootstrap a source project as an Appsody starter application
  2. Add your application code
  3. Configure your application for Kubernetes

A complete “inventory microservice” sample is available in GitHub.

Create and deploy an Appsody application

First, create a new Appsody project using the Appsody CLI.

mkdir appsody-one
cd appsody-one
appsody init incubator/java-spring-boot2

Note that you have selected the java-spring-boot2 Appsody stack.

This tutorial assumes that you are using Docker Desktop Kubernetes, but the procedure for any Kubernetes provider will be similar. Simply run appsody deploy from within your new project folder (appsody-one) in order to build a Docker image and run your new application in the Kubernetes cluster.

After the deploy is complete, you will have a new docker image in your docker registry. The image name is derived from your Appsody project name. So, for example, if that directory name is appsody-one then the docker image name will be dev.local/appsody-one.

You’ll also notice a message on the console indicating the exposed endpoint of the running application. For example:

Deployed project running at http://localhost:31758

Note that one effect of the deploy is that Appsody has added a new file to your project: app-deploy.yaml. This is your Kubernetes deployment configuration file. Note that this defines a configuration for a Kubernetes “custom resource” of type AppsodyApplication.

To query the status of your deployed application:

$ kubectl get AppsodyApplication
NAME           IMAGE                    EXPOSED   RECONCILED   AGE
appsody-one    dev.local/appsody-one    true      True         17m

Appsody’s java-spring-boot2 stack

Cloud platforms provide support for resilient, manageable, and observable applications. As an example, consider Kubernetes pod lifecycle management.

Generally, though, this is a collaboration between platform and application. In the example of pod lifecycle management, Kubernetes needs a method for determining whether a pod is “alive” or should be restarted, which is done by way of a REST endpoint implemented by the application — a “liveness probe.”

The starter application provided by the Appsody java-spring-boot2 stack includes a liveness probe implementation and configuration (see: app-deploy.yaml). With the application listening on the mapped port 31758 (see the example above), you can access this liveness probe as:

$ curl http://localhost:31758/actuator/liveness
{"status":"UP"}

This probe is actually implemented by the Spring Boot Actuator library.

If you look at the Maven pom.xml included in your starter application, you’ll see an Appsody parent pom declaration:

<parent>
    <groupId>dev.appsody</groupId>
    <artifactId>spring-boot2-stack</artifactId>

This parent pom for the Appsody Spring Boot stack includes a Maven dependency declaration for the Spring Boot Actuator library:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>

So, every Appsody application using the Appsody Spring Boot stack inherits Spring Boot Actuator capabilities, configured to support Kubernetes pod lifecycle management. No work is required of the Spring REST services developer.

Other application capabilities supporting cloud-native behaviors, inherited with the Appsody Spring Boot stack, include:

  • Micrometer Prometheus metrics
  • Jaeger distributed tracing

Add your application code

The premise of this tutorial is that you are familiar with using Spring Boot to implement REST services that have external service dependencies, like a database and messaging provider. A key concern addressed here, with respect to how you migrate to “cloud-native,” is how you handle service integration credentials in that target environment. The assertion here is that it’s straightforward to extend the Spring REST service you are familiar with to be ready for Kubernetes.

So, once you have created and validated your new Appsody project and its Kubernetes configuration, add your application code to this project. You will likely want to make some minor changes to the Appsody starter code, such as the package name used for the starter main class.

Note that with the Appsody java-spring-boot2 stack, the starter application in your Appsody project will be a Spring Boot application. Moreover, you can run this application in your IDE as you would any other Spring Boot application. After adding your application code to this Appsody project, you should still be able to run it from your IDE as a Spring Boot application.

The strategy described here for migration to Kubernetes preserves your ability to run and test from your IDE, and exploits the use of Spring Boot “profiles” to select a different method of service integration credentials acquisition for Kubernetes.

Specifically, the key elements of this strategy are:

  • Use a dev profile to specify credentials used when testing locally from your IDE
  • Set up the default Spring profile with configuration property placeholders to be set by Spring Cloud Kubernetes

For example, suppose you have a Kubernetes Secret item named inventorydb.password. Then, with Spring Cloud Kubernetes enabled, specify the following in your application.properties file:

spring.datasource.password = ${inventorydb.password}

As an experienced Spring developer, you’ll recognize that there are a number of available alternatives for setting up a Spring configuration, for alternate property value resolution in different runtime scenarios, and there might very well be a different strategy that you prefer for switching between “local” and “Kubernetes.”

Kubernetes enablement

Details can be found in the “inventory microservice” sample and its README file in GitHub. Please refer to that resource for details not found here. The essential concepts are the following:

  1. Create the Kubernetes Secrets for your service integration credentials in your Kubernetes cluster
  2. Add volume mount configurations to your AppsodyApplication configuration to have Kubernetes make these Secrets available in the runtime environment as files on the filesystem
  3. Pull in Spring Cloud Kubernetes and provide Spring Cloud Kubernetes configuration properties

There are two SCK dependencies to be added to your Maven pom.xml:

<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes</artifactId>

<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-kubernetes-config</artifactId>

You also need to provide a configuration (in bootstrap.properties) to enable Spring Cloud Kubernetes’ Kubernetes Secrets awareness, and specify the runtime filesystem paths where Secrets can be found.

Example:

spring.cloud.kubernetes.secrets.enabled = true
spring.cloud.kubernetes.secrets.paths = /etc/secrets/inventorydb

At this point, you are ready to test your Spring Boot application in your local Kubernetes cluster, with appspody deploy.

Next Steps

The activity reviewed in this tutorial is not the full scope of responsibility for our subject solution component developer. At a point, code has to be delivered, and we should mention something about continuous integration and deployment (CI/CD) in the context of the larger solution development team.

IBM Cloud Pak for Applications includes tooling to support the full development workflow, including CI/CD. For an introduction to the full tool suite supporting cloud-native development, see the blog “Codewind + Appsody + Tekton = Easier cloud-native development” and the IBM Cloud Pak for Applications page on IBM Developer.

Richard Trotter