Using Spring Cloud Functions with OpenShift Serverless

Using Spring Cloud Functions with OpenShift Serverless

Spring Cloud Functions are yet another interesting option for Java developers when building serverless applications. You have already seen how to build and run applications for Red Hat OpenShift Serverless using Quarkus, but in this article, we talk about how to use Spring Cloud Functions and walk you through those steps. These steps are similar to running any other Spring Boot application with OpenShift Serverless. One of the benefits of building an open hybrid serverless platform is giving developers a choice of programming languages, tools, frameworks, and portability across any environment to run serverless applications. Beyond that, you want to ensure that the developer experience and overall workflow is intuitive and practical, which is what you will learn here.

If you are interested in just watching the steps performed in this article you can watch the recording on YouTube.

Requirements

Everything you need to grow your career.

With your free Red Hat Developer program membership, unlock our library of cheat sheets and ebooks on next-generation application development.

SIGN UP

Generate the Spring Cloud Functions project

One of the easiest ways to generate a Spring project is using curl to access start.spring.io and that’s exactly how we will start our project:

This will generate and download a project inside the my-function-project folder.

Implement your first function

We will implement a quick and dirty Google Translator wrapper. In order to create functions using Spring Cloud Functions, you need a method with the @Bean annotation that can follow any of the functional interfaces from java.util.function such as ConsumerSupplier, or Function. For more details about how Spring Cloud Functions work please read the documentation, but for this example just copy and paste the following method to your DemoApplication.java file:

Test your function locally

Since Spring Cloud Functions are just Spring Boot apps, you can implement unit tests just like any other Java application using JUnit, Mockito, or whatever you would like.  You can also run the application locally, using gradle bootRun or mvn spring-boot:run, which is useful for validating the application iteratively before running inside a container.  Make sure you have fixed all Java imports and then start the application locally using:

Every function will be mapped to an endpoint that can be accessed as follows:

http://localhost:8080/<functionName>

Concretely, for our translate function, you can access the endpoint using the following:

Using curl we post a word or a phrase and it gets translated to Spanish. You can parse the output and format it properly, but to keep this short I’ll leave that as an exercise for the reader.  May Jackson and JSON be your friends.

Building a container using Jib

So far we have built a Spring application and executed it locally but it’s time to containerize the application. There are many ways to execute this step but I’ve decided to stick to well-known tools used by the Java community, so I’ll use Jib and add it as a plugin to my Gradle project.

Edit the build.gradle file and append this line id 'com.google.cloud.tools.jib' version "2.4.0" to your plugins section. It should look like this:

With Jib as part of your project, Gradle can build your container and push it to your container registry of choice. Quay or DockerHub are well-known choices.

After you have the jib plugin on your Gradle project, build a container for the project using the following command: gradle build jib --image=<your_container_registry>/demo-app:v1

On my machine this is what it looks like:

This generated a container for your project and automatically pushed it to the container registry.  If you are new to Linux containers and container registries please read this post to get a practical introduction to the topic.

Deploy to OpenShift Serverless

With the container built you can now deploy the application using the Knative CLI, kn:

OpenShift Serverless will do the heavy lifting of creating a Kubernetes deployment, a route, SSL configuration (using your cluster’s configuration), and auto-scaling configuration based on the number of requests. For more details about OpenShift Serverless, please check out the product documentation.

The above code will auto-scale the application down (to zero) after six seconds without a new request.

Try it again using the URL from the service running in OpenShift:

Adding a new function that can handle a JSON document

When creating REST APIs it is very common to send and receive JSON documents and you can very easily add a function that takes a JSON message instead of a String.

The data model

Create a new UserReview.java file with the following content:

We will use this class to marshal and unmarshal the JSON objects being sent or received by our API. Create a review.json file with the content below. This will be the input of our new translateReview function.

The function code

This will be very similar to the previous function we created, it’s just another method with the @Bean annotation and using our POJO class as input and output.

Posting a JSON file

We will continue using curl as our client here and specify a path to the review.json file created in the previous step.  Start the application again using gradle bootRunthen post a json file to the API:

As you can see, the function now accepts a JSON document and translates the user comment to Spanish.  You can experiment with a declarative function composition way to implement this if that’s your cup of tea, but I’m keeping this simple for now.

Building your new container

Same steps as before but using a v2 tag, build a new version of the container:

$ gradle jib --image=<your_container_registry>/demo-app:v2

Updating the deployed application to include the new function

Now we are going to use another interesting feature of OpenShift Serverless, we will deploy a new version of the application but with a different URL, that way current clients of this API won’t even know about this new functionality until we decide to send traffic to it:

This can be achieved by using tags. In this example, I’m tagging a particular revision @latest with a preview value that will be appended to the service URL. Also note, that I’m setting 100% of traffic to the previous revision translator-v1, which means no traffic will be sent to the new version being deployed. This is also called a “dark launch,” where a new version of my application is available in a production environment but not necessarily receiving any requests unless someone knows which URL to use.

After validation is complete you can decide to gradually send traffic using canary or blue/green deployment models. There is a step-by-step lab about how to implement those models on https://learn.openshift.com/developing-on-openshift/serverless/

Testing

Now you can execute the same curl command as before but this time adding the preview prefix:

Conclusion

You can easily build and deploy a Spring Cloud Functions application using OpenShift Serverless. The workflow feels natural for a Java developer and you can even build the container using a Gradle (or Maven) plugin such as Jib.

A Spring Cloud Function in Red Hat OpenShift

Using OpenShift Serverless you can also deploy multiple versions of the application and perform a dark launch, blue/green, or canary deployment with no sweat.  The OpenShift developer console makes it even easier to visualize traffic route information and the overall topology of your application.

For more details, check the OpenShift Serverless page.

Share