# Run your OpenFaaS Functions on Google Cloud Run for free

## Yesterday Google announced a new serverless SaaS product named Cloud Run, learn how to deploy your OpenFaaS Functions without modifications in the free tier

April 09, 2019
Cloud

---

In this post I’ll introduce Google’s new Cloud Run product which like OpenFaaS allows any HTTP Server packaged in a Docker or OCI image format to be deployed and scaled.

## Serverless 2.0 - it’s about containers

In my conference talk at [goto Copenhagen](https://www.youtube.com/watch?v=yOpYYYRuDQ0) last fall I coined the term _Serverless 2.0_. Serverless 2.0 builds upon the learnings of the first-generation of proprietary SaaS products from major cloud vendors by using containers for portability and to avoid lock-in. Your deployments for Serverless and the rest of your applications no-longer have to be orthogonal managed by two sets of tools. This approach has been core to the OpenFaaS community from day 1.

Yesterday we saw Google [launch a new product](https://news.ycombinator.com/item?id=19610830) named [Cloud Run](https://cloud.google.com/run/docs/). This is a proprietary serverless add-on for Google Cloud Platform (GCP) built around the [11-year old AppEngine product](https://cloud.google.com/appengine/). You may be wondering where [Knative](https://cloud.google.com/knative/) and the flagship product [Istio](https://istio.io/) come into it? Knative is apparently only being used [as an API interface](https://twitter.com/alexellisuk/status/1116247440829681664) so that workloads can be deployed to either AppEngine or Knative & Istio on Kubernetes.

> What does that mean for you and me?

It means that we can deploy functions in containers to GCP and run them [up to certain limits](https://cloud.google.com/run/pricing) without incurring costs. I thought it would be worth kicking the tires by deploying one of the OpenFaaS functions I developed in my latest introductory post on [OpenFaaS Cloud & GitLab](/content/blog/openfaas-cloud-gitlab/index.html).

You may already be familiar with OpenFaaS - Serverless Functions Made Simple. I started the project in December 2016 out of a desire to run serverless-style workloads on any cloud without fear of getting locked-in. For that reason OpenFaaS builds Docker or OCI-format container images.

Has a simple HTTP contract on port 8080  
Is packaged in containers  
Runs functions OR microservices  
Can use any 64-bit Linux binary or HTTP server  
Auto-scales on QPS, even to zero  
Started over 2.5 years ago

Name this [#serverless](https://x.com/hashtag/serverless?src=hashtag_click) framework?

[8:22 AM · Apr 9, 2019](https://x.com/alexellisuk/status/1115530479598473216?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1115530479598473216%7Ctwgr%5Eeab090cb07ec084ed564e8396cb0400705471fea%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fwww.openfaas.com%2Fblog%2Fopenfaas-cloudrun%2F)

The traits and characteristics of Cloud Run (hosted Knative) closely follow [what I outlined for OpenFaaS over two and a half years ago](https://blog.alexellis.io/functions-as-a-service/). This validates the design and [future of OpenFaaS into 2019 and beyond](https://blog.alexellis.io/openfaas-bright-2019/).

| Trait | OpenFaaS | Cloud Run | Knative |
| --- | --- | --- | --- |
| License | Open Source (MIT) | Proprietary | Open Source (Apache 2) |
| Workload | Container | Container | Container |
| Platform runtime | Kubernetes | AppEngine | Istio & Kubernetes |
| TCP Port | HTTP 8080 | HTTP 8080 | HTTP 8080 |
| Auto-scaling on QPS | Yes | Yes | Yes |
| Scale to zero | Yes | Yes | Yes |
| Stateless microservices | Yes | Yes | Yes |
| Functions | Yes | No | No |
| Run any binary as a service | Yes | No | No |
| SaaS offering | [OpenFaaS Cloud](https://docs.openfaas.com/openfaas-cloud/intro/) | Cloud Run | 3rd-party offerings |

There’s an undeniable level of similarity between the work we’ve done in the OpenFaaS community and what we’re seeing today in Google’s Knative project.

### Tutorial

Let’s get started with the tutorial. We’ll be taking a function I built to shift the timezone of a meeting from UTC to the Bay Area. I currently have my GitHub repository linked to the [OpenFaaS Cloud Community Cluster](https://docs.openfaas.com/openfaas-cloud/intro/#community-cluster) which builds and deploys my functions automatically with its built-in CI/CD process.

> To link our GitHub repository to Cloud Run, we will have to provision additional infrastructure to carry out CI and CD tasks. Google’s chosen tool is Cloud Build which will mean adding specific `cloudbuild.yaml` files to each repository. In contrast, OpenFaaS cloud enables automatic CI/CD for each repository without the need for separate infrastructure or managing many different CI/CD configs.

This is how the function works:

If you send no argument and use HTTP GET, the function returns the current time shifted:

```
curl -SLs https://alexellis.o6s.io/timezone-shift

{"meeting":"2019-04-09T14:05:58Z","adjusted":"2019-04-09T06:05:58Z"}
```

Let’s plan a meeting with our colleagues in the Bay Area starting at 5pm UTC:

```
echo -n '{"meeting": "2019-02-18 17:00:00"}' | \n curl -SLs https://alexellis.o6s.io/timezone-shift -H "Content-type: application/json" --data-binary @- ; \n echo

{"meeting":"2019-02-18T17:00:00Z","adjusted":"2019-02-18T09:00:00Z"}
```

Here’s the function code:

```
"use strict"

const moment = require('moment');

module.exports = (event, context) => {
    let meeting = moment.utc(event.body.meeting)
    let adjusted = meeting.clone().utc().add(-8, 'hours');

context
        .status(200)
        .succeed({ meeting: meeting.format(), adjusted: adjusted.format() });
}
```

See also: [handler.js](https://github.com/alexellis/openfaas-cloud-test/blob/master/timezone-shift/handler.js)

### Sign-up for GCP

If you’re a customer of GCP then you can continue, otherwise [sign-up here](https://cloud.google.com/free/)

### Enable GCP APIs and services

You’ll need to enable billing through a Linked Account which means it’s time to go and grab your credit-card.

- Cloud Build - this is to enable automated linking to your GitHub repo
- Container Registry - Google won’t allow you to deploy to Cloud Run unless you first push your images into a `gcr.io` registry/account.
- Cloud Run - Google’s SaaS platform for deploying serverless containers

> Note: If you need to run on-premises, you can already deploy OpenFaaS on any [Kubernetes or OpenShift cluster](https://docs.openfaas.com/deployment/kubernetes/).

### Download the `gcloud` SDK/CLI

Grab the `gcloud` SDK (CLI) and authenticate to your chosen project.

- [Download here](https://cloud.google.com/sdk/)

```
gcloud auth login
```

### Fork the example project

Now fork my example project to your GitHub account.

[https://github.com/alexellis/openfaas-cloud-test](https://github.com/alexellis/openfaas-cloud-test)

### Configure Cloud Build

Since Google Cloud Build doesn’t appear to allow the use of images not within a `gcr.io` account, we cannot use the official OpenFaaS CLI image which is published to quay.io and the Docker Hub. This means pulling the image to our local machine, then tagging it and pushing it up to the GCR project.

```
# Check "gcloud projects list" to find your project ID

export PROJECT_ID="alexellis"
docker pull openfaas/faas-cli:0.8.8
docker tag openfaas/faas-cli:0.8.8 gcr.io/$PROJECT_ID/faas-cli:0.8.8
docker push gcr.io/$PROJECT_ID/faas-cli:0.8.8
```

You’ve now created a mirror of the faas-cli Docker image to be used in the Cloud Build.

In the GCP Console find “Cloud Build” and “Triggers”.

Now create a build for your forked repository. Accept all of the defaults.

```
steps:
## Shinkwrap
- name: 'gcr.io/$PROJECT_ID/faas-cli:0.8.8'
  args: ['faas-cli', 'template', 'store', 'pull', 'node8-express']
- name: 'gcr.io/$PROJECT_ID/faas-cli:0.8.8'
  args: ['faas-cli', 'build', '--shrinkwrap']
## Build Docker image
- name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'gcr.io/$PROJECT_ID/timezone-shift:$REVISION_ID', '-t', 'gcr.io/$PROJECT_ID/timezone-shift:latest', '-f' ,'./build/timezone-shift/Dockerfile', './build/timezone-shift/']

## Deploy to "Cloud Run"
- name: 'gcr.io/cloud-builders/gcloud'
  args: ['beta', 'run', 'deploy', 'timezone-shift', '--image', 'gcr.io/$PROJECT_ID/timezone-shift:$REVISION_ID', '--region', 'us-central-1']

images:
- 'gcr.io/$PROJECT_ID/timezone-shift'
```

We have a chicken-and-egg situation right now. The `cloudbuild.yaml` file does a build and then a deploy to an existing Cloud Run Service, but our Cloud Run Service does not yet exist and cannot be deployed without a valid YAML file.

Comment out the lines for the step named `## Deploy to "Cloud Run"` and then do a commit. This will push a container image into our `gcr.io` registry.

Each time your CI build finishes a new Revision will be created and deployed which is attached to the Cloud Run Service.

### Create a Cloud Run Service

Now that we have CI configured (and CD temporarily disabled) it’s time to create a _Service_.

Go to Cloud Run in the GCP console and enter the following:

Make sure you click _Allow unauthenticated invocations_ so that anyone can invoke the function.

Now click _Create_.

Unfortunately it seems like the Cloud Run service is only available in the `us-central-1` region which means that you may incur significant latency if you live in Europe like myself. I expect this to be extended over time to cover additional regions.

### Enable CD

Now go over to your fork of my GitHub repo and edit your `cloudbuild.yaml` file. Un-comment the lines for the step: `## Deploy to "Cloud Run"`. This will trigger a new build and we can watch it progress in the Google Cloud Build console.

When complete it will deploy a second revision to the Cloud Run Service and we’ll get a URL on the Cloud Run dashboard.

> Don’t like managing a `cloudbuild.yaml` file for every one of your GitHub repositories? No problem - checkout [OpenFaaS Cloud](https://docs.openfaas.com/openfaas-cloud/intro/) which uses your existing stack.yaml file to automate CI/CD for any linked repository on GitHub or self-hosted GitLab.

### Monitor the function

The Cloud Run UI has a somewhat spartan feel with many details hidden away or not yet available.

### Cold starts

There appears to be some work-in-progress on [cold starts](https://github.com/knative/serving/issues/1297) in Knative. It’s still early, but I would hope to see some improvements over time. As the linked issue explains, part of the additional latency is due to the decision to tightly couple to a service mesh (Istio). Istio can deliver some interesting features such as traffic-splitting and mutual TLS, but does not come for free.

## Wrapping up

We took an OpenFaaS function and without making any code or configuration changes to it we were able to deploy it to a brand new container SaaS platform built by a third-party. I think this is testament to the portability and ubiquity of the Docker / OCI-image format which I decided to use with OpenFaaS back in December 2016 when the project began.
