Portable code migrating across Google Cloud's serverless platforms

grayside

Adam Ross

Posted on December 5, 2019

Portable code migrating across Google Cloud's serverless platforms

Google Cloud has a number of options to run your code. We'll focus on three serverless platforms: Cloud Functions, App Engine, and Cloud Run, all of which automatically scale by traffic and bill by usage. The biggest difference between these platforms is the level of abstraction. We can deploy a function to Cloud Functions, an app to App Engine, or an app with a custom runtime (a Docker container) to Cloud Run.

The most abstract serverless hosting option is a function. It has no code except the core business logic of a specialized service. Two challenges in working with serverless functions include:

  • Developing locally without a platform to convert requests to function calls
  • Finding hosting alternatives when the infrastructure, runtime, or cost constraints of your platform are reached

Using a "Hello World" function with an international twist: "Hello Translate", we'll explore a new way to mitigate these challenges on Google Cloud.

Standalone Functions with the Functions Framework

Like all Google Cloud Functions runtimes, the Node.js v10 runtime supports direct HTTP triggers while removing the overhead of HTTP routing from developers. Under the hood this magic is done by the open source Node.js functions framework. The framework installs as a normal dependency for your function and encapsulates express.js to provide clean and standardized HTTP request handling.

Because it provides an HTTP server you can run your function as a localhost web service, or deploy it to any web hosting platform.

  1. Write business logic
  2. Add a Function Framework
  3. Deploy to a web host

Let's get to the code for "Hello Translate".

Writing a Function

Create a new npm package and install the functions framework and the translate library:

npm init
npm install @google-cloud/functions-framework@1 @google-cloud/translate@5
Enter fullscreen mode Exit fullscreen mode

(The @1 and @5 bits instruct npm to retrieve specific major versions of the libraries. It makes the code in this post less timeless, but more likely to work as long as these versions are compatible with Google Cloud.)

Cook up the code for "Hello Translate!":

Before we're ready to deploy HelloTranslate, let's modify the package.json to define a start script:

 "scripts": {
    "start": "functions-framework --target=helloTranslate"
 }
Enter fullscreen mode Exit fullscreen mode

When npm start is run, the Node process will start a web server in the function framework package which is configured to use the target function above. This enables local development with no other special dependencies. The same mechanism will be used in Cloud Functions, App Engine, and Cloud Run.

Getting setup to work with Google Cloud

Set up a development environment and configure your project to support the "Hello Translate" function:

  • Create or select a Google Cloud Project. Add it to your shell environment with export PROJECT=[Your Project ID] to streamline the commands below.
  • Install and authenticate with the Cloud SDK
  • Enable the the Translate API: gcloud services enable translate.googleapis.com

Testing on Cloud Functions

Start by confirming this is works as a Cloud Function, let's deploy it!

gcloud functions deploy helloTranslate \
    --runtime=nodejs10 --region=us-central1 --trigger-http
Enter fullscreen mode Exit fullscreen mode

Wait a couple minutes and we're ready to make a request. Use curl to ask for "Hello World!" in the default Spanish language:

curl https://us-central1-${PROJECT}.cloudfunctions.net/helloTranslate
Hola Mundo!
Enter fullscreen mode Exit fullscreen mode

To learn more about how to use Cloud Functions, check out the HTTP Functions how-to.

Deploying a Function to App Engine

Now that we've confirmed the code works with Cloud Functions, let's see it work as an app on App Engine. App Engine allows more control over the instance scaling and behavior, and the requirement to deploy an HTTP server is met by the function framework. This means we can deploy code to App Engine without stopping for code changes.

Adapt Hello Translate to App Engine by following these steps:

1) Add an app.yaml configuration file to declare the runtime:

runtime: nodejs10
Enter fullscreen mode Exit fullscreen mode

2) Deploy the code

gcloud app deploy
Enter fullscreen mode Exit fullscreen mode

3) Ask our production service for the latest translation of "Hello World!" in Yoruba:

curl https://${PROJECT}.appspot.com?lang=yo
Mo ki O Ile Aiye!
Enter fullscreen mode Exit fullscreen mode

To learn more about how to use App Engine Standard, check out the Building an App Quickstart.

Deploying a Function to Cloud Run

Cloud Run is similar to App Engine in expecting a full HTTP app to be deployed. Unlike App Engine, Cloud Run is driven by containers. Cloud Run does not know if you are using javascript, java, or a web server written in BASH. Containers allow the developer to customize the runtime environment.

Adapt Hello Translate to Cloud Run by following these steps:

1) Add a Dockerfile. Copy the Node.js Dockerfile from the Cloud Run quickstart. Here's a streamlined copy for quick reading:

2) Build the Container.

gcloud builds submit --tag=gcr.io/${PROJECT}/hello-translate
Enter fullscreen mode Exit fullscreen mode

3) Deploy the service.

gcloud run deploy hello-translate \
    --image=gcr.io/${PROJECT}/hello-translate
Enter fullscreen mode Exit fullscreen mode

4) Ask our production service for the latest translation of "Hello World!" in Japanese:

curl https://hello-translate-j6jxwetqdq-uc.a.run.app?lang=ja
"こんにちは世界"
Enter fullscreen mode Exit fullscreen mode

To learn more about how to use Cloud Run, check out the Build and Deploy Quickstart.

Helpful Abstraction!

The function framework is a good case of an abstraction. Code that makes sense to deploy as a function doesn't need much customization in HTTP handling, so why include the boilerplate anywhere that code is hosted? With an open source package, your functions-that-are-services code is more portable across compute platforms.

If your function is chafing at the runtime or concurrency limitations of Cloud Functions, consider using a Functions Framework to migrate your service to another hosting option such as Cloud Run. With a little more work, you can even bring over event-driven functions by configuring Pub/Sub push subscriptions.

Read Onward

For an example application using a Functions Framework to be simultaneously deployable to Cloud Functions and Cloud Run, check out Grant Timmerman's Pizza Map sample.

💖 💪 🙅 🚩
grayside
Adam Ross

Posted on December 5, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related