IBM Z Day on Nov. 21: Discover the ideal environment for modern, mission-critical workloads. Learn more

Use Kabanero, Appsody, and Codewind to build a Spring Boot application on Kubernetes

To create a modern, cloud-native application, you have to consider all aspects of the application — from the best way to incorporate business logic in the appropriate places to technical considerations like how to handle resiliency, reliability, and monitoring. Additionally, when running an application on the cloud or in a Kubernetes cluster, you also have to handle creating Dockerfiles and the necessary Kubernetes resource files.

In the era of DevOps where the team is responsible for building and running applications for their entire life cycle, choosing the best tools is crucial to help reduce the work needed for building and deploying cloud-native applications. New open source tools from IBM — Kabanero, Appsody, and Codewind — were created to make it easier for developers to build and deploy cloud-native applications to Kubernetes.

This article introduces you to Kabanero and shows you how to use it, along with Appsody and Codewind, to build a Spring Boot application running in Kubernetes.

Let’s take a quick look at these new open source components before we jump into the steps:

  • Kabanero integrates multiple established open source projects (like Appsody and Codewind) to support DevOps and reduce the required effort from an infrastructure-perspective to support cloud-native development.
  • Appsody offers pre-defined code stacks that minimize the initial effort of creating a project. Appsody currently provides stacks for Eclipse Microprofile, Spring Boot, Quarkus, Node.js, Node.js Express, and Swift applications. More stacks are being developed or you can customize existing stacks or create new ones. In organizations or large development teams, using these stacks sets a minimum standard for application structure.
  • Eclipse Codewind is an IDE extension that can be used to build, test, and deploy applications within containers. Since you’re using an IDE of your choice (right now there’s support for Eclipse, Eclipse Che, and VSCode), you don’t even have to be familiar with container environment.

In this tutorial, I used the following versions:

  • Knative: v0.7
  • Appsody: v0.4.5
  • Codewind: v0.4.0

Prerequisites

To complete the steps in this tutorial, you need to have the following tools installed and running on your system:

Installation

We will use VSCode with the Codewind extension and run the example in a local Kubernetes cluster. You can use the same approach for IBM Cloud Kubernetes Services or an OpenShift cluster.

  • Install the Appsody CLI
  • Install Codewind from the VSCode marketplace — just search for “Codewind” when you’re in the marketplace. This also installs some Docker images and the Appsody Plugin:
eclipse/codewind-initialize-amd64                                                                                            0.4.0                  7f31c5b7db69        6 days ago           206MB
codewind-initialize-amd64                                                                                                    0.4.0                  7f31c5b7db69        6 days ago           206MB
codewind-performance-amd64                                                                                                   0.4.0                  09ac0adfa6b5        6 days ago           86.4MB
eclipse/codewind-performance-amd64                                                                                           0.4.0                  09ac0adfa6b5        6 days ago           86.4MB
codewind-pfe-amd64                                                                                                           0.4.0                  224a9df6df08        6 days ago           706MB
eclipse/codewind-pfe-amd64                                                                                                   0.4.0                  224a9df6df08        6 days ago           706MB

Create a Spring Boot project with Appsody

To create a new Spring Boot project, use the java-spring-boot2 stack from Appsody.

An Appsody stack represents the foundation for a Kubernetes application and consists of a base container image and a project template. The project template uses the base container image as well as provided runtimes and dependencies, so it’s easy to initiate a project.

You can see the current default stack repository here. You can add other repositories as well.

To create a new project, we will use the Spring Boot 2 stack from Appsody. Use the appsody list command to see the available stacks.

$ appsody list
Your default repository is now set to appsodyhub

REPO        ID                VERSION   TEMPLATES         DESCRIPTION
*appsodyhub java-microprofile 0.2.14    *default          Eclipse MicroProfile on Open Liberty & OpenJ9 using Maven
*appsodyhub java-spring-boot2 0.3.14    *default, kotlin  Spring Boot using OpenJ9 and Maven
*appsodyhub nodejs            0.2.5     *simple           Runtime for Node.js applications
*appsodyhub nodejs-express    0.2.6     *simple, skaffold Express web framework for Node.js
*appsodyhub nodejs-loopback   0.1.4     *scaffold         LoopBack 4 API Framework for Node.js
*appsodyhub python-flask      0.1.3     *simple           Flask web Framework for Python
*appsodyhub swift             0.1.4     *simple           Runtime for Swift applications

Create a new project using the Spring Boot 2 template in an empty directory. To do that, run the appsody init command with the stack you choose.

$ mkdir kabanero-test-springboot2
$ cd kabanero-test-springboot2
$ appsody init java-spring-boot2

Running appsody init...
Downloading java-spring-boot2 template project from https://github.com/appsody/stacks/releases/download/java-spring-boot2-v0.3.14/incubator.java-spring-boot2.v0.3.14.templates.default.tar.gz
Download complete. Extracting files from java-spring-boot2.tar.gz
Setting up the development environment
Running command: docker pull appsody/java-spring-boot2:0.3
Running command: docker run --rm --entrypoint /bin/bash appsody/java-spring-boot2:0.3 -c find /project -type f -name .appsody-init.sh
Extracting project from development environment
Running command: docker create --name my-project-extract -v /Users/haddouti/codewind-workspace/kabanero-test-springboot2/.:/project/user-app -v /Users/haddouti/.m2/repository:/mvn/repository appsody/java-spring-boot2:0.3
Running command: docker cp my-project-extract:/project /Users/haddouti/.appsody/extract/kabanero-test-springboot2
Running command: docker rm my-project-extract -f
Project extracted to /Users/haddouti/codewind-workspace/kabanero-test-springboot2/.appsody_init
Running command: ./.appsody-init.sh
Successfully initialized Appsody project


$ ls -la
total 24
drwxr-xr-x  7 haddouti  staff   224 Sep 25 22:21 .
drwxr-xr-x  8 haddouti  staff   256 Sep 25 22:20 ..
-rw-r--r--  1 haddouti  staff    37 Sep 25 22:21 .appsody-config.yaml
-rw-r--r--  1 haddouti  staff   288 Sep 25 22:21 .gitignore
drwxr-xr-x  4 haddouti  staff   128 Sep 25 22:21 .vscode
-rw-r--r--  1 haddouti  staff  1189 Sep 25 22:21 pom.xml
drwxr-xr-x  4 haddouti  staff   128 Sep 25 22:21 src

The result is a working skeleton project based on Spring Boot 2 and Maven with Health and Monitoring endpoints. The .appsody-config.yaml contains a reference of the used Appsody stack.

# cat .appsody-config.yaml
stack: appsody/java-spring-boot2:0.3

The Spring Boot application has a dependency to the spring-boot2-stack which manages dependencies and plugins. It also includes Prometheus, OpenTracing, and the Spring Developer Tool for dynamic reloading.

Below you’ll see the pom.xml dependency:

<parent><!--required parent POM-->
    <groupId>dev.appsody</groupId>
    <artifactId>spring-boot2-stack</artifactId>
    <version>[0.3, 0.4)</version>
    <relativePath/>
  </parent>

If you use appsody run in the project directory, it builds and runs the application and is available under http://localhost:8080/

Process diagram

Internally, Appsody creates a Docker image and runs the container to build and test the project. Once it passes the tests, it runs the container afterwards.

$ docker ps
CONTAINER ID        IMAGE                              COMMAND                  CREATED              STATUS              PORTS                                                                                              NAMES
40e448a63904        appsody/java-spring-boot2:0.3      "/appsody/appsody-co…"   About a minute ago   Up About a minute   0.0.0.0:5005->5005/tcp, 0.0.0.0:8080->8080/tcp, 0.0.0.0:8443->8443/tcp, 0.0.0.0:35729->35729/tcp   kabanero-test-springboot2-dev

To stop the application, use ctrl+c or type appsody stop in the project directory:

$ appsody stop

Stopping development environment
Running command: docker[stop kabanero-test-springboot-dev]

To get the Docker container, you can explicitly call appsody build which extracts all the artifacts, creates a Dockerfile, and generates the Docker container. All files are placed in $HOME/.appsody/extract/<project-name>/ as the following code shows:

# appsody build

Extracting project from development environment
Running command: docker pull appsody/java-spring-boot2:0.3
Running command: docker create --name kabanero-test-springboot2-extract -v /Users/haddouti/codewind-workspace/kabanero-test-springboot2/.:/project/user-app -v /Users/haddouti/.m2/repository:/mvn/repository appsody/java-spring-boot2:0.3
Running command: docker cp kabanero-test-springboot2-extract:/project /Users/haddouti/.appsody/extract/kabanero-test-springboot2
Running command: docker rm kabanero-test-springboot2-extract -f
Project extracted to /Users/haddouti/.appsody/extract/kabanero-test-springboot2
Running docker command: docker build -t kabanero-test-springboot2 -f /Users/haddouti/.appsody/extract/kabanero-test-springboot2/Dockerfile /Users/haddouti/.appsody/extract/kabanero-test-springboot2
[Docker] Sending build context to Docker daemon  597.5kB
[Docker] Step 1/16 : FROM appsody/java-spring-boot2:0.3 as compile
[Docker]  ---> 4ea7128b4908
[Docker] Step 2/16 : COPY . /project
[Docker]  ---> fba0fb3e1e4d
[Docker] Step 3/16 : WORKDIR /project/user-app
[Docker]  ---> Running in 62b15dd73734
[Docker] Removing intermediate container 62b15dd73734
[Docker]  ---> 83fd7058ad5b
[Docker] Step 4/16 : RUN /project/util/check_version build  && /project/java-spring-boot2-build.sh package
[Docker]  ---> Running in 7e1232e17fb4
[Docker] Installing parent dev.appsody:spring-boot2-stack:0.3.14
[Docker] > mvn install -q -f /project/appsody-boot2-pom.xml
...
[Docker]  ---> Running in 254e0c44af86
[Docker] Removing intermediate container 254e0c44af86
[Docker]  ---> 7b3cf8460bc3
[Docker] Successfully built 7b3cf8460bc3
[Docker] Successfully tagged kabanero-test-springboot2:latest
Built docker image kabanero-test-springboot2

# ll $HOME/.appsody/extract/kabanero-test-springboot2
total 88
-rw-rw-r--  1 haddouti  staff   926B Sep 25 15:20 Dockerfile
-rw-rw-r--  1 haddouti  staff   6.6K Sep 25 15:20 appsody-boot2-pom.xml
-rwxrwxr-x  1 haddouti  staff   4.8K Sep 25 15:19 java-spring-boot2-build.sh
-rw-rw-r--  1 haddouti  staff   628B Sep 25 15:19 mvn-stack-settings.xml
-rwxrwxr-x  1 haddouti  staff   9.8K Sep 25 15:20 mvnw
-rw-rw-r--  1 haddouti  staff   6.5K Sep 25 15:20 mvnw.cmd
drwxr-xr-x  9 haddouti  staff   288B Sep 25 22:25 user-app
drwxrwxr-x  6 haddouti  staff   192B Sep 25 15:20 util

# docker images | grep -i kabanero-test-springboot2
kabanero-test-springboot2                                                                                                    latest                 7b3cf8460bc3        3 minutes ago       400MB

Codewind integration

Codewind has an Appsody plugin, so you can use it to manage Appsody projects. In the Codewind View it is possible to add an existing project (which should already exist within $HOME/codewind-workspace/) or create a new project using the available Appsody templates.

Create new project 1/2: Select template Create new project 2/2: Set project name

The context menu of the project provides various options, such as Open the App in the default browser, restart the app, or open a shell into the Docker container. You can also access the log files from the Docker container.

Codewind Project context menu

Codewind integration also supports a dynamic reloading of the application runtime. So, any modifications you make to the project will rebuild the application.

For example, if you modify the HTML file kabanero-test-springboot2/src/main/resources/public/index.html, it will restart the Spring Boot server, and the change is immediately visible.

Codewind lets you handle cloud-native applications without having to touch the underlying Docker containers.

Move it to the cloud

To deploy the app into a Kubernetes cluster, you can reuse the created Docker image, or you can transfer the responsibility to an Appsody Operator or Knative Serving. In this case, use only appsody deploy which extracts the artifacts and deploys the Docker image into a Kubernetes cluster.

Depending on the stack used, Knative Serving or Appsody Operator will be used for the deployment management. In general, Knative Serving is the fallback, and can be forced with the flag --knative.

The preferred Appsody Operator is responsible for the deployment of the application and performs activities for handling routing, high availability, and persistence volume management.

Appsody creates a manifest file that’s ready for deployment, like the one below, for example:

apiVersion: appsody.dev/v1beta1
kind: AppsodyApplication
metadata:
  name: kabanero-test-springboot2
spec:
  # Add fields here
  version: 1.0.0
  applicationImage: dev.local/kabanero-test-springboot2
  stack: java-spring-boot2
  service:
    type: NodePort
    port: 8080
    annotations:
      prometheus.io/scrape: 'true'
      prometheus.io/path: '/actuator/prometheus'
  readinessProbe:
    failureThreshold: 12
    httpGet:
      path: /actuator/health
      port: 8080
    initialDelaySeconds: 5
    periodSeconds: 2
  livenessProbe:
    failureThreshold: 12
    httpGet:
      path: /actuator/liveness
      port: 8080
    initialDelaySeconds: 5
    periodSeconds: 2
  expose: true
  # In case Knative is used, is the next line enabled
  #createKnativeService: true

This produces a running pod with our application:

# kubect get pods
NAME                                          READY   STATUS    RESTARTS   AGE
appsody-operator-859b97bb98-kwpz4             1/1     Running   0          2m41s
kabanero-test-springboot-595c4cc494-rwh5z     1/1     Running   0          64s

If you used Knative Serving for the deployment, the following resources will be created:

  • Service, deployment, and ReplicaSet
  • Knative Service (service.serving.knative.dev): General management of the entire lifecycle and resource object creation
  • Knative Revision (revision.serving.knative.dev): Snapshot of code and configuration
  • Knative Route (route.serving.knative.dev): Maps network endpoint to revision
  • Knative Configuration (configuration.serving.knative.dev): Maintain the desired state of the deployment
  • and multiple other internal Knative resources for PodAutoscaling, Image Caching.
# kubectl get serving
NAME                                                  URL                                                         LATESTCREATED                   LATESTREADY                     READY   REASON
service.serving.knative.dev/kabanero-test-springboot  http://kabanero-test-springboot.default.9.145.41.194.nip.io kabanero-test-springboot-4mvb4  kabanero-test-springboot-4mvb4  True

NAME                                                  URL                                                         READY   REASON
route.serving.knative.dev/kabanero-test-springboot    http://kabanero-test-springboot.default.9.145.41.194.nip.io True

NAME                                                          SERVICE NAME                    GENERATION   READY   REASON
revision.serving.knative.dev/kabanero-test-springboot-4mvb4   kabanero-test-springboot-4mvb4  1            True

NAME                                                        LATESTCREATED                   LATESTREADY                     READY   REASON
configuration.serving.knative.dev/kabanero-test-springboot  kabanero-test-springboot-4mvb4  kabanero-test-springboot-4mvb4  True

For more details, read the Knative Serving documentation.

To delete the application and all the Kubernetes resources, use the following command: appsody deploy delete.

Summary

Kabanero is a new tool in the young and rapidly changing cloud-native environment. In this article, you saw how Kabanero can integrate with other popular open source projects (Knative, Istio, Tekton etc.) and how out of the box it can handle the configuration, installation, and other infrastructure activities. It allows a better decoupling of the application logic from the used infrastructure with the offered abstraction.

With the growing supported Appsody stacks is it possible to create and manage more and more uniform cloud-native applications.

Learn more about Kabanero Enterpirse, an enterprise-ready and fully supported implementation of Kabanero.

Hafid Haddouti