The [serverless Java][2] journey started out with functions—small snippets of code running on demand. This phase didn't last long. Although functions based on virtual machine architecture in the 1.0 phase made this paradigm very popular, as the graphic below shows, there were limits around execution time, protocols, and poor local-development experience.
Developers then realized that they could apply the same serverless traits and benefits to microservices and Linux containers. This launched the 1.5 phase, where some serverless containers completely abstracted[Kubernetes][3], delivering the serverless experience through [Knative][4] or another abstraction layer that sits on top of it.
In the 2.0 phase, serverless starts to handle more complex orchestration and integration patterns combined with some level of state management. More importantly, developers want to keep using a familiar application runtime, Java, to run a combination of serverless and non-serverless workloads in legacy systems.
![The serverless Java journey][5]
Before Java developers can start developing new serverless functions, their first task is to choose a new cloud-native Java framework that allows them to run Java functions quicker with a smaller memory footprint than traditional monolithic applications. This can be applied to various infrastructure environments, from physical servers to virtual machines to containers in multi- and hybrid-cloud environments.
Developers might consider an opinionated Spring framework that uses the `java.util.function` package in [Spring Cloud Function][6] to support the development of imperative and reactive functions. Spring also enables developers to deploy Java functions to installable serverless platforms such as [Kubeless][7], [Apache OpenWhisk][8], [Fission][9], and [Project Riff][10]. However, there are concernsabout slow startup and response times and heavy memory-consuming processes with Spring. This problem can be worse when running Java functions on scalable container environments such as Kubernetes.
[Quarkus][11] is a new open source cloud-native Java framework that can help solve these problems. It aims to design serverless applications and write cloud-native microservices for running on cloud infrastructures (e.g., Kubernetes).
Quarkus rethinks Java, using a closed-world approach to building and running it. It has turned Java into a runtime that's comparable to Go. Quarkus also includes more than 100 extensions that integrate enterprise capabilities, including database access, serverless integration, messaging, security, observability, and business automation.
Here is a quick example of how developers can scaffold a Java serverless function project with Quarkus.
Developers have multiple options to install a local Kubernetes cluster, including [Minikube][12] and [OKD][13] (OpenShift Kubernetes Distribution). This tutorial uses an OKD cluster for a developer's local environment because of the easy setup of serverless functionality on Knative and DevOps toolings. These guides for [OKD installation][14] and [Knative operator installation][15] offer more information about setting them up.
The following command generates a Quarkus project (e.g., `quarkus-serverless-restapi` ) to expose a simple REST API and download a `quarkus-openshift` extension for Knative service deployment:
INFO [io.quarkus] (Quarkus Main Thread) quarkus-serverless-restapi 1.0.0-SNAPSHOT on JVM (powered by Quarkus xx.xx.xx.) started in 2.386s. Listening on: http://localhost:8080
INFO [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
INFO [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, kubernetes, resteasy]
```
> **Note**: Keep your Quarkus application running to use Live Coding. This allows you to avoid having to rebuild, redeploy the application, and restart the runtime whenever the code changes.
You will see new output when you reinvoke the REST API:
```
$ curl localhost:8080/hello
Quarkus Function on Kubernetes
```
There's not been a big difference between normal microservices and serverless functions. A benefit of Quarkus is that it enables developers to use any microservice to deploy Kubernetes as a serverless function.
If you haven't already, [create a namespace][16] (e.g., `quarkus-serverless-restapi` ) on your OKD (Kubernetes) cluster to deploy this Java serverless function.
Quarkus enables developers to generate Knative and Kubernetes resources by adding the following variables in `src/main/resources/application.properties` :
Then access the OKD web console to go to the [Topology view in the Developer perspective][17]. You might see that your pod (serverless function) is already scaled down to zero (white-line circle).
This Knative service pod will go down to zero again in 30 seconds because of Knative serving's default setting.
### What's next?
The serverless journey has evolved, starting with functions on virtual machines to serverless containers and integration with enterprise legacy systems. Along this journey, enterprise developers can still use familiar technologies like Java for developing serverless functions by using Quarkus to create a project then build and deploy it to Kubernetes with a Knative service.
The next article in this series will guide you on optimizing Java serverless functions in Kubernetes for faster startup time and small memory footprints at scale.