About this codelab
1. Introduction
Overview
Cloud Run functions is Google Cloud's Functions-as-a-Service offering powered by Cloud Run and Eventarc, giving you more advanced control over performance and scalability, and more control around the functions runtime and triggers from over 90+ event sources.
This codelab will walk you through creating Cloud Run functions that respond to HTTP calls, and get triggered by Pub/Sub messages and Cloud Audit Logs.
This codelab also uses automatic base image updates for function deployments by specifying a base image using the --base-image
flag. Automatic base image updates for Cloud Run enables Google to make security patches to the operating system and language runtime components of the base image automatically. You don't have to rebuild or redeploy your service for the base image to be updated. For more information, check out the automatic base image updates
If you prefer not to use automatic base image updates, you can remove the --base-image
flag from the examples shown in this codelab.
What you'll learn
- Overview of Cloud Run functions and how to use automatic base image updates.
- How to write a function that responds to HTTP calls.
- How to write a function that responds to Pub/Sub messages.
- How to write a function that responds to Cloud Storage events.
- How to split traffic between two revisions.
- How to get rid of cold starts with minimum instances.
2. Setup and Requirements
Create a root folder
Create a root folder for all the examples.
mkdir crf-codelab cd crf-codelab
Set up environment variables
Set environment variables that will be used throughout this codelab/
gcloud config set project <YOUR-PROJECT-ID> REGION=<YOUR_REGION> PROJECT_ID=$(gcloud config get-value project)
Enable APIs
Enable all necessary services:
gcloud services enable \ artifactregistry.googleapis.com \ cloudbuild.googleapis.com \ eventarc.googleapis.com \ run.googleapis.com \ logging.googleapis.com \ pubsub.googleapis.com
3. HTTP Function
For the first function, let's create an authenticated Node.js function that responds to HTTP requests. Let's also use a 10 minute timeout to showcase how a function can have more time to respond to HTTP requests.
Create
Create a folder for the app and navigate to the folder:
mkdir hello-http cd hello-http
Create an index.js
file that responds to HTTP requests:
const functions = require('@google-cloud/functions-framework'); functions.http('helloWorld', (req, res) => { res.status(200).send('HTTP with Node.js in Cloud Run functions!'); });
Create a package.json
file to specify the dependencies:
{ "name": "nodejs-run-functions-codelab", "version": "0.0.1", "main": "index.js", "dependencies": { "@google-cloud/functions-framework": "^2.0.0" } }
Deploy
Deploy the function:
gcloud run deploy nodejs-run-function \ --source . \ --function helloWorld \ --base-image nodejs22 \ --region $REGION \ --timeout 600 \ --no-allow-unauthenticated
This command uses buildpacks to transform your function source code into a production-ready container image.
Please note the following:
- the
--source
flag is used to tell Cloud Run to build the function into a runnable container based service - the
--function
flag (new) is used to set the entrypoint of the new service to be the function signature you want to be invoked - the
--base-image
flag (new) specifies the base image environment for your function, likenodejs22
,python312
,go123
,java21
,dotnet8
,ruby33
, orphp83
. For more details about base images and the packages included in each image, see Runtimes base images. - (optional) the
--timeout
flag allows the function to have a longer timeout to respond to HTTP requests. In this example, 600 seconds is used to demonstrate a 10 minute response time. - (optional) the
--no-allow-unauthenticated
to prevent your function from being publicly invokable
Test
Test the function with the following commands:
# get the Service URL SERVICE_URL="$(gcloud run services describe nodejs-run-function --region $REGION --format 'value(status.url)')" # invoke the service curl -H "Authorization: bearer $(gcloud auth print-identity-token)" -X GET $SERVICE_URL
You should see the message HTTP with Node.js in Cloud Run functions!
as a response.
4. Pub/Sub Function
For the second function, let's create a Python function triggered by a Pub/Sub message published to a specific topic.
Set up Pub/Sub auth tokens
If you enabled the Pub/Sub service account on or before April 8, 2021, grant the iam.serviceAccountTokenCreator
role to the Pub/Sub service account:
PROJECT_NUMBER=$(gcloud projects list --filter="project_id:$PROJECT_ID" --format='value(project_number)') gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:service-$PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com \ --role roles/iam.serviceAccountTokenCreator
Create
Create a Pub/Sub topic to use for the sample:
TOPIC=cloud-run-functions-pubsub-topic gcloud pubsub topics create $TOPIC
Create a folder for the app and navigate to the folder:
mkdir ../hello-pubsub cd ../hello-pubsub
Create a main.py
file that logs a message containing the CloudEvent ID:
import functions_framework @functions_framework.cloud_event def hello_pubsub(cloud_event): print('Pub/Sub with Python in Cloud Run functions! Id: ' + cloud_event['id'])
Create a requirements.txt
file with the following contents to specify the dependencies:
functions-framework==3.*
Deploy
Deploy the function:
gcloud run deploy python-pubsub-function \ --source . \ --function hello_pubsub \ --base-image python313 \ --region $REGION \ --no-allow-unauthenticated
Retrieve the project number to be used for the service account identity.
PROJECT_NUMBER=$(gcloud projects list --filter="project_id:$PROJECT_ID" --format='value(project_number)')
Create the trigger
gcloud eventarc triggers create python-pubsub-function-trigger \ --location=$REGION \ --destination-run-service=python-pubsub-function \ --destination-run-region=$REGION \ --event-filters="type=google.cloud.pubsub.topic.v1.messagePublished" \ --transport-topic=projects/$PROJECT_ID/topics/$TOPIC \ --service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com
Test
Test the function by sending a message to the topic:
gcloud pubsub topics publish $TOPIC --message="Hello World"
You should see the received CloudEvent in the logs:
gcloud run services logs read python-pubsub-function --region $REGION --limit=10
5. Cloud Storage Function
For the next function, let's create a Node.js function that responds to events from a Cloud Storage bucket.
Set up
To use Cloud Storage functions, grant the pubsub.publisher
IAM role to the Cloud Storage service account:
SERVICE_ACCOUNT=$(gsutil kms serviceaccount -p $PROJECT_NUMBER) gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:$SERVICE_ACCOUNT \ --role roles/pubsub.publisher
Create
Create a folder for the app and navigate to the folder:
mkdir ../hello-storage cd ../hello-storage
Create an index.js
file that simply responds to Cloud Storage events:
const functions = require('@google-cloud/functions-framework'); functions.cloudEvent('helloStorage', (cloudevent) => { console.log('Cloud Storage event with Node.js in Cloud Run functions!'); console.log(cloudevent); });
Create a package.json
file to specify the dependencies:
{ "name": "nodejs-crf-cloud-storage", "version": "0.0.1", "main": "index.js", "dependencies": { "@google-cloud/functions-framework": "^2.0.0" } }
Deploy
First, create a Cloud Storage bucket (or use an existing bucket you already have):
export BUCKET_NAME="gcf-storage-$PROJECT_ID" export BUCKET="gs://gcf-storage-$PROJECT_ID" gsutil mb -l $REGION $BUCKET
Deploy the function:
gcloud run deploy nodejs-crf-cloud-storage \ --source . \ --base-image nodejs22 \ --function helloStorage \ --region $REGION \ --no-allow-unauthenticated
Once the function is deployed, you can see it under the Cloud Run section of the Cloud Console.
Now create the Eventarc trigger.
BUCKET_REGION=$REGION gcloud eventarc triggers create nodejs-crf-cloud-storage-trigger \ --location=$BUCKET_REGION \ --destination-run-service=nodejs-crf-cloud-storage \ --destination-run-region=$REGION \ --event-filters="type=google.cloud.storage.object.v1.finalized" \ --event-filters="bucket=$BUCKET_NAME" \ --service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com
Test
Test the function by uploading a file to the bucket:
echo "Hello World" > random.txt gsutil cp random.txt $BUCKET/random.txt
You should see the received CloudEvent in the logs:
gcloud run services logs read nodejs-crf-cloud-storage --region $REGION --limit=10
6. Traffic splitting
Cloud Run functions supports multiple revisions of your functions, splitting traffic between different revisions and rolling your function back to a prior version.
In this step, you will deploy 2 revisions of a function and then split the traffic between them 50-50.
Create
Create a folder for the app and navigate to the folder:
mkdir ../traffic-splitting cd ../traffic-splitting
Create a main.py
file with a Python function that reads a color environment variable and responds back with Hello World
in that background color:
import os color = os.environ.get('COLOR') def hello_world(request): return f'<body style="background-color:{color}"><h1>Hello World!</h1></body>'
Create a requirements.txt
file with the following contents to specify the dependencies:
functions-framework==3.*
Deploy
Deploy the first revision of the function with an orange background:
COLOR=orange gcloud run deploy hello-world-colors \ --source . \ --base-image python313 \ --function hello_world \ --region $REGION \ --allow-unauthenticated \ --update-env-vars COLOR=$COLOR
At this point, if you test the function by viewing the HTTP trigger (the URI output of the above deployment command) in your browser, you should see Hello World
with an orange background:
Deploy the second revision with a yellow background:
COLOR=yellow gcloud run deploy hello-world-colors \ --source . \ --base-image python313 \ --function hello_world \ --region $REGION \ --allow-unauthenticated \ --update-env-vars COLOR=$COLOR
Since this is the latest revision, if you test the function, you should see Hello World
with a yellow background:
Split the traffic 50-50
To split the traffic between the orange and yellow revisions, you need to find the revision IDs of the Cloud Run services. This is the command to see the revision IDs:
gcloud run revisions list --service hello-world-colors \ --region $REGION --format 'value(REVISION)'
The output should be similar to the following:
hello-world-colors-00001-man hello-world-colors-00002-wok
Now, split the traffic between these two revisions as follows (update the X-XXX
according to your revision names):
gcloud run services update-traffic hello-world-colors \ --region $REGION \ --to-revisions hello-world-colors-0000X-XXX=50,hello-world-colors-0000X-XXX=50
Test
Test the function by visiting its public URL. Half of the time, you should see the orange revision and, the other half, the yellow revision:
See rollbacks, gradual rollouts, and traffic migration for more information.
7. Minimum instances
In Cloud Run functions, you can specify a minimum number of function instances to be kept warm and ready to serve requests. This is useful in limiting the number of cold starts.
In this step, you will deploy a function with slow initialization. You'll observe the cold start problem. Then, you will deploy the function with the minimum instance value set to 1 to get rid of the cold start.
Create
Create a folder for the app and navigate to it:
mkdir ../min-instances cd ../min-instances
Create a main.go
file. This Go service has an init
function that sleeps for 10 seconds to simulate a long initialization. It also has a HelloWorld
function that responds to HTTP calls:
package p import ( "fmt" "net/http" "time" ) func init() { time.Sleep(10 * time.Second) } func HelloWorld(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "Slow HTTP Go in Cloud Run functions!") }
Deploy
Deploy the first revision of the function with the default minimum instance value of zero:
gcloud run deploy go-slow-function \ --source . \ --base-image go123 \ --function HelloWorld \ --region $REGION \ --no-allow-unauthenticated
Test the function with this command:
# get the Service URL SERVICE_URL="$(gcloud run services describe go-slow-function --region $REGION --format 'value(status.url)')" # invoke the service curl -H "Authorization: bearer $(gcloud auth print-identity-token)" -X GET $SERVICE_URL
You will observe a 10 second delay (cold start) on the first call and then see the message. Subsequent calls should return immediately.
Set minimum instances
To get rid of the cold start on the first request, redeploy the function with the --min-instances
flag set to 1 as follows:
gcloud run deploy go-slow-function \ --source . \ --base-image go123 \ --function HelloWorld \ --region $REGION \ --no-allow-unauthenticated \ --min-instances 1
Test
Test the function again:
curl -H "Authorization: bearer $(gcloud auth print-identity-token)" -X GET $SERVICE_URL
You should not see the 10 second delay anymore in the first request. The cold start problem for the first invocation (after a long time without) is gone, thanks to minimum instances!
See using minimum instances for more information.
8. Congratulations!
Congratulations for completing the codelab!
What we've covered
- Overview of Cloud Run functions and how to use automatic base image updates.
- How to write a function that responds to HTTP calls.
- How to write a function that responds to Pub/Sub messages.
- How to write a function that responds to Cloud Storage events.
- How to split traffic between two revisions.
- How to get rid of cold starts with minimum instances.