Getting started with Cloud Run functions

Getting started with Cloud Run functions

About this codelab

subjectLast updated May 7, 2025
account_circleWritten by Mete Atamel

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, like nodejs22, python312, go123, java21, dotnet8, ruby33, or php83. 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:

36ca0c5f39cc89cf.png

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:

391286a08ad3cdde.png

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:

36ca0c5f39cc89cf.png 391286a08ad3cdde.png

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.