When interviewed at Google Next, Pali Bhat, Google Cloud VP of product and design, said the following:
”Let developers focus on code because that’s what they want to do.” Keeping developers happy, though important, was not the only thing he had in mind.
Code that runs in production must be secure, monitored for health, and capable of dealing with increases in load. But there is no value in these things alone. The added value for any organization is in the code that delivers solutions to business problems. The idea behind FaaS and serverless in general is essentially about enabling developers and organizations to focus on where the value is.
Traditionally, however, elastic scaling, security and monitoring of functions have come at the price of some flexibility. For example, Google Cloud Functions announced beta support for Node.js 6 in 2017, followed by Node.js 8 and Python in 2018, and Go in 2019. This means that C# functions running on Azure can’t be transported to GCP should you feel the need to switch cloud providers. AWS would be a possibility (C# is supported by Lamda) but that said, you can expect to have a hard time anyway as functions are not particularly portable by design.
By contrast, containers — an industry standard with no runtime restrictions — are both flexible and portable. Developers can package up any code they like into a container and have it run on a container host. However, container orchestration is not for the fainthearted. Organizations running the likes of Kubernetes will be well aware of the need deal with all the underlying complexities that come with managing a fleet of containerized applications. This is in stark contrast to the no-ops experience that serverless promises.
Naturally, the question begs: Why not bring containers and serverless together?
This is exactly what Google has done with Cloud Run. By bringing the convenience of managed infrastructure and security to the flexibility and portability of containerized applications, Google hopes to offer the best of both worlds. Developers can now write serverless “container functions” in any language they choose so long as they adhere to the container contract, which amounts to little more than listening to HTTP requests on a specified port.
With the new language possibilities Cloud Run opens up on GCP, let’s see how easy it is to get a simple Java service up and running. Don’t forget, the billing model for FaaS is based on CPU (execution time) and memory usage, so functions should start fast, be fast, and utilize as little memory as possible. To achieve this in the Java world we have a couple of good options in Quarkus and Micronaut. Both offer the startup speed and memory efficiency we want thanks to native image compilation provided by GraalVM.
In the guide that follows, be sure to pay attention to the developer experience. After all, the whole idea of serverless is about getting developers to focus on writing code that delivers value, rather than worrying about how to get it into production and manage it thereafter. Enjoy!
Quick guide: Quarkus on google cloud run
In this guide we'll deploy a natively compiled Quarkus application to Google Cloud Run. Here you will:
Generate a Quarkus application.
Generate all the configuration necessary to make deployment to Google Cloud Run quick and easy.
Set up a Cloud Run service and deploy the application.
Prerequisites
You will need the following:
Setup
Create a simple "greeter" Quarkus application:
mvn io.quarkus:quarkus-maven-plugin:0.13.3:create \ -DprojectGroupId=org.acme \ -DprojectArtifactId=getting-started \ -DclassName="org.acme.quickstart.GreetingResource" \ -Dpath="/hello"
The greeter service looks like so:
@Path("/hello") public class GreetingResource { @GET @Produces(MediaType.TEXT_PLAIN) public String hello() { return "hello"; } }
Feel free to test and run this locally (see the getting started guide for more information). Alternatively, move on to the next step if you just want to get into production fast!
Prepare for cloud run
Cloud Run's container runtime contract states that:
Executables in the container image must be compiled for Linux 64-bit. The container must listen for HTTP requests on 0.0.0.0 on the port defined by the PORT environment variable (8080 by default). To keep billing costs as low as possible, whatever runs inside the container should start fast, execute fast, and utilize as little memory as possible. That's where GraalVM and native image compilation comes in.
At this point then we should be sure to have an installation of GraalVM and Docker to take care of the native image compilation and containerization parts respectively. However, from a pure development perspective, compiling down our Quarkus application to a native image and containerizing it is something we want to avoid. (In addition, GraalVM is not supported on Windows.) Therefore, we're going to delegate this to Google's Cloud Build.
The cloudify-maven-plugin maven plugin will help turn your Quarkus application into a Cloud Run ready application.
Run the plugin like so:
mvn -N team.quad:cloudify-maven-plugin:0.1.0:gcloud-run
It generates the following:
A Docker file. Google cloud configuration file for building and deploying. Scripts to help with the first time setup on Cloud Run.
Deploy to cloud run
The Cloud Run console (web interface) can be used to set up a Cloud Run project and service. Alternatively, at the root of our project is an interactive deploy script, which will guide us through the setup from the command line.
Execute the script and follow the instructions:
./deploy
Or on Windows:
deploy.cmd
The script will take you through the process of creating a project and linking your GCP billing account to it. Other tasks such as enabling various APIs, assigning roles to service accounts (for build and deploy permissions), and pushing the code to the cloud are taken care of automatically. Note that native compilation is not a lightweight task so the build step can take several minutes.
The cloudify-maven-plugin generates a deploy script to make deployment to Cloud Run even simpler. Append /hello to the URL to see the greeter application.
You can also see your function the Cloud Run console.
Conclusion
In this guide we’ve combined a lot of concepts so let’s take a summary:
We’ve attempted to streamline the developer experience as much as possible by taking advantage of Google’s Cloud Run and Cloud Build services. This reduces the number of technologies we have to deal with — no Docker, no GraalVM installations required.
Nonetheless, Quarkus and GraalVM gives us the speed and efficiency we need to run in a serverless environment. Take a look at the numbers:
The inherent flexibility of containers paired with the agility of serverless makes for a powerful combination. There’s been no need to code to a function framework or interface. In fact, thanks to containers we can think beyond functions and more towards fully-fledged web applications run in serverless style.