Developing functions in Functions Framework and deploying them in Yandex Serverless Containers
- Getting started
- Create a service account
- Create a registry in Container Registry
- Create a function
- Create a Docker image and push it to the registry in Container Registry
- Create a container in Serverless Containers from the uploaded Docker image
- Test the function in the container
- How to delete the resources you created
The Google Cloud Functions Framework
With the Functions Framework, you can write and run functions in Yandex Serverless Containers containers without using Yandex Cloud Functions. Functions written this way can be migrated across different platforms, such as Cloud Run
This tutorial presents a use case where you will locally create a function using the Functions Framework. You will then build a Docker image from this function and upload it to a registry in Yandex Container Registry. Using the Docker image stored in the registry, you will create a container in Serverless Containers that will run your function code when invoked.
This solution enables you to:
- Build and distribute functions as OCI-compatible
Docker images and deploy them on various cloud and on-premises platforms, such as Kubernetes , Cloud Run, Knative, etc. - Develop, run locally, debug, and test functions as standard web applications using modern IDEs
. - Migrate your functions from Cloud Run functions or Knative while maintaining compatibility with these platforms.
- Create functions in Dart
, C++ , or Ruby , which are currently not supported in Cloud Functions.
In this tutorial, you will create a test function. For the complete list of supported programming languages, see the Functions Framework GitHub repository
To deploy a function in Serverless Containers:
- Get your cloud ready.
- Create a service account.
- Create a registry in Container Registry.
- Create a function.
- Create a Docker image and push it to the registry in Container Registry.
- Create a container in Serverless Containers from the uploaded Docker image.
- Test the function in the container.
If you no longer need the resources you created, delete them.
Getting started
Sign up for Yandex Cloud and create a billing account:
- Go to the management console
and log in to Yandex Cloud or create an account if you do not have one yet. - On the Yandex Cloud Billing
page, make sure you have a billing account linked and it has theACTIVE
orTRIAL_ACTIVE
status. If you do not have a billing account, create one.
If you have an active billing account, you can go to the cloud page
Learn more about clouds and folders.
Required paid resources
The cost of the web service infrastructure support includes:
- Fee for using the storage, amount of outgoing traffic, and using the Container Registry vulnerability scanner (see the Yandex Container Registry pricing).
- Fee for using Serverless Containers (see Yandex Serverless Containers pricing).
Set up your environment
-
Install cURL
. -
Install and configure the Yandex Cloud CLI.
-
Install and configure Docker.
-
Get authenticated in Container Registry.
-
Install Pack
. To do this, run these commands in the terminal and wait for the installation to complete:sudo add-apt-repository ppa:cncf-buildpacks/pack-cli -y sudo apt install pack-cli -y
Here we provide the Pack
installation guide for Linux Ubuntu. If you are using a different OS, see the Pack tutorials with installation instructions.
Create a service account
- In the management console
, select the folder where you are going to create your infrastructure. - From the list of services, select Identity and Access Management.
- Click Create service account, and in the window that opens:
- Enter a name for the service account:
serverless-containers-sa
. - Click
Add role and select thecontainer-registry.images.puller
role. - Click Create.
- Enter a name for the service account:
The folder specified in the CLI profile is used by default. You can specify a different folder using the --folder-name
or --folder-id
parameters.
-
Create a service account named
serverless-containers-sa
:yc iam service-account create \ --name serverless-containers-sa
Result:
done (1s) id: aje7tnmd885t******** folder_id: b1gt6g8ht345******** created_at: "2025-02-14T11:09:54.376880905Z" name: serverless-containers-sa
Save the service account ID (the
id
field value) and the folder ID (thefolder_id
field value), you will need them in the next step.For more information about the
yc iam service-account create
command, see the CLI reference. -
Assign the
container-registry.images.puller
role for the folder to the created service account by specifying the folder and service account IDs you saved in the previous step:yc resource-manager folder add-access-binding <folder_ID> \ --role container-registry.images.puller \ --subject serviceAccount:<service_account_ID>
Result:
done (2s) effective_deltas: - action: ADD access_binding: role_id: container-registry.images.puller subject: id: aje7tnmd885t******** type: serviceAccount
For more information about the
yc resource-manager folder add-access-binding
command, see the CLI reference.
To create a service account, use the create REST API method for the ServiceAccount resource or the ServiceAccountService/Create gRPC API call.
To assign the service account a role for the folder, use the updateAccessBindings REST API method for the Folder resource or the FolderService/UpdateAccessBindings gRPC API call.
Create a registry in Container Registry
- In the management console
, select the folder you used to create the service account in. - From the list of services, select Container Registry.
- Click Create registry.
- In the Name field, enter the registry name:
functions-framework-registry
. - Click Create registry.
- On the page that opens, copy the ID of the created registry, you will need it later.
Create the functions-framework-registry
registry:
yc container registry create \
--name functions-framework-registry
Result:
done (1s)
id: crpfn9p374a3********
folder_id: b1gt6g8ht345********
name: functions-framework-registry
status: ACTIVE
created_at: "2025-02-14T11:44:23.698Z"
Save the ID (the id
field value) of the created registry, you will need it later.
For more information about the yc container registry create
command, see the CLI reference.
To create a registry, use the create method for the Registry resource or the RegistryService/Create gRPC API call.
Create a function
At this stage, you will locally create a function using the Functions Framework. Here we provide the package installation commands for Linux Ubuntu. If you are using a different OS, see the relevant tutorials for installation instructions.
To create a function in Node.js
-
Install the npm
package manager:sudo apt update && \ sudo apt install npm -y
-
Create a directory for the new project:
mkdir my-first-function && \ cd my-first-function
-
Initialize your project:
npm init
During initialization, leave all requested values at their defaults by pressing ENTER. At the end, when you get the
Is this OK?
promt, typeyes
and press Enter. This will create thepackage.json
project file in your project directory.{ "name": "my-first-function", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" }
-
Create a new
index.js
file by opening it in the text editor:nano index.js
-
Add this code to the
index.js
file:const functions = require('@google-cloud/functions-framework'); functions.http('helloWorld', (req, res) => { res.send('Hello, World!'); });
-
Install the Functions Framework in your project:
npm install @google-cloud/functions-framework
-
Add this code to the
package.json
file:"scripts": { "start": "functions-framework --target=helloWorld" }
Example of the final
package.json
contents:{ "name": "my-first-function", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "dependencies": { "@google-cloud/functions-framework": "^3.4.5" }, "scripts": { "start": "functions-framework --target=helloWorld" } }
-
Run your function locally to make sure everything works correctly:
-
Run the function:
npm start
Result:
> my-first-function@1.0.0 start > functions-framework --target=helloWorld Serving function... Function: helloWorld Signature type: http URL: http://localhost:8080/
-
Open an additional terminal window and run the following command in it:
curl http://localhost:8080/
Result:
Hello, World!
This way, you can also run a function in debug mode and use breakpoints
with modern IDEs. -
To create a function in Python
-
Install Python and pip
:sudo apt update && \ sudo apt install python3 python3-pip -y
-
Create a directory for the new project:
mkdir my-first-function && \ cd my-first-function
-
Install the Functions Framework:
sudo pip install functions-framework
-
Create the
main.py
file with the function code by opening it in the text editor:nano main.py
-
Add this code to the
main.py
file:import flask import functions_framework @functions_framework.http def helloWorld(request: flask.Request) -> flask.typing.ResponseReturnValue: return "Hello, World!"
-
Run your function locally to make sure everything works correctly:
-
Run the function:
functions-framework --target helloWorld --debug
Result:
* Serving Flask app 'hello' * Debug mode: on WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on all addresses (0.0.0.0) * Running on http://127.0.0.1:8080 * Running on http://192.168.1.15:8080 Press CTRL+C to quit * Restarting with watchdog (inotify) * Debugger is active! * Debugger PIN: 817-187-***
-
Open an additional terminal window and run the following command in it:
curl http://localhost:8080/
Result:
Hello, World!
This way, you can also run a function in debug mode and use breakpoints
with modern IDEs. -
To create a function in Go
-
Install
Go1.18
or higher. -
Create a directory for the new project:
mkdir my-first-function && \ cd my-first-function
-
Create a new module:
go mod init example.com/helloWorld
-
Create the
function.go
file with the function code by opening it in the text editor:nano function.go
-
Add this code to the
function.go
file:package function import ( "fmt" "net/http" "github.com/GoogleCloudPlatform/functions-framework-go/functions" ) func init() { functions.HTTP("helloWorld", helloWorld) } // helloWorld writes "Hello, World!" to the HTTP response. func helloWorld(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Hello, World!") }
-
Run your function locally to make sure everything works correctly:
-
Create a directory named
cmd
:mkdir cmd
-
In the
cmd
directory, create a file namedmain.go
:nano cmd/main.go
-
Add this code to the
main.go
file:package main import ( "log" "os" // Blank-import the function package so the init() runs _ "example.com/helloWorld" "github.com/GoogleCloudPlatform/functions-framework-go/funcframework" ) func main() { // Use PORT environment variable, or default to 8080. port := "8080" if envPort := os.Getenv("PORT"); envPort != "" { port = envPort } // By default, listen on all interfaces. If testing locally, run with // LOCAL_ONLY=true to avoid triggering firewall warnings and // exposing the server outside of your own machine. hostname := "" if localOnly := os.Getenv("LOCAL_ONLY"); localOnly == "true" { hostname = "127.0.0.1" } if err := funcframework.StartHostPort(hostname, port); err != nil { log.Fatalf("funcframework.StartHostPort: %v\n", err) } }
-
Update the dependencies:
go mod tidy
-
Start your local server:
FUNCTION_TARGET=helloWorld \ LOCAL_ONLY=true \ go run cmd/main.go
-
Open an additional terminal window and run the following command in it:
curl http://localhost:8080/
Result:
Hello, World!
This way, you can also run a function in debug mode and use breakpoints
with modern IDEs. -
Create a Docker image and push it to the registry in Container Registry
The function is built using Buildpacks
-
Use Pack, which you installed earlier, to build a Docker image with your app:
sudo pack build \ --builder gcr.io/buildpacks/builder:google-22 \ --env GOOGLE\_FUNCTION\_SIGNATURE\_TYPE=http \ --env GOOGLE\_FUNCTION\_TARGET=helloWorld \ my-first-function
To additionally configure the container build, e.g., add other packages or dependencies, use this guide
.Result:
... Successfully built image my-first-function
You can use the above build command for functions written in different programming languages. The builder will automatically detect the project's language and runtime environment and then build the application into an OCI-compatible Docker image. This way, developers do not need to create a Dockerfile manually.
-
Run the container locally from the Docker image to make sure everything works correctly:
-
Run this command:
docker run --rm -p 8080:8080 my-first-function
-
Open an additional terminal window and run the following command in it:
curl http://localhost:8080/
Result:
Hello, World!
The function code is running in the locally launched Docker container.
-
Close the additional terminal window. Stop the running Docker container from the main terminal window by pressing Ctrl + C.
-
-
Assign an URL to the Docker image in the
cr.yandex/<registry_ID>/<Docker_image_name>:<tag>
format and specify the previously saved ID of the registry from Container Registry.docker tag my-first-function \ cr.yandex/<registry_ID>/my-first-function:some-tag
Note
To push Docker images to Container Registry, you need to assign them URLs in this format:
cr.yandex/<registry_ID>/<Docker_image_name>:<tag>
. -
Push the Docker image to the registry:
docker push \ cr.yandex/<registry_ID>/my-first-function:some-tag
Result:
The push refers to repository [cr.yandex/crpfn9p374a3********/my-first-function] ... 14f9fd9947d2: Pushed 2573e0d81582: Pushed some-tag: digest: sha256:1b8bac8da5e64dd4359f81d71a7803f212af385f9718a7a4f9a40bca******** size: 2830
Create a container in Serverless Containers from the uploaded Docker image
Use the Docker image uploaded to Container Registry to create a Serverless Containers container revision.
-
In the management console
, select the folder containing the resources you created previously. -
From the list of services, select Serverless Containers.
-
Click Create container.
-
In the Name field, specify the container name:
my-first-function
. -
Click Create.
-
Under Image settings, in the Image URL field, select the previously uploaded Docker image,
cr.yandex/<registry_ID>/my-first-function:some-tag
. -
Under Settings, in the Service account field, select the previously created service account.
serverless-containers-sa
. -
Under Logging, disable Write logs to opt out of writing logs to the log group.
You can leave this option enabled if you prefer to write container execution logs. You will be charged for writing and storing logs.
-
Click Create revision.
-
In the window that opens, under General information, copy the Link to invoke value; you will need this URL to test function in the container.
-
Create a
my-first-function
container:yc serverless container create \ --name my-first-function
Result:
done (1s) id: bba0tc5nv6j0******** folder_id: b1gt6g8ht345******** created_at: "2025-02-14T15:26:04.744Z" name: my-first-function url: https://bba0tc5nv6j0********.containers.yandexcloud.net/ status: ACTIVE
Save the container invocation
url
, you will need it to test function in the container.For more information about the
yc serverless container create
command, see the CLI reference. -
Create a revision of the container you created previously:
yc serverless container revision deploy \ --container-name my-first-function \ --image "cr.yandex/<registry_ID>/my-first-function:some-tag" \ --service-account-id <service_account_ID> \ --no-logging
Where:
<registry_ID>
: ID of the Container Registry registry you saved in the previous step.<service_account_ID>
: ID of theserverless-containers-sa
service account you saved in the previous step.--no-logging
: Disables writing logs to the log group. Remove this parameter from the command to write container execution logs. You will be charged for writing and storing logs.
Result:
done (16s) id: bba6f1jllc3t******** container_id: bbakbil5lg7j******** created_at: "2025-02-14T20:48:06.424Z" image: image_url: cr.yandex/crpfn9p374a3********/my-first-function:some-tag image_digest: sha256:1b8bac8da5e64dd4359f81d71a7803f212af385f9718a7a4f9a40bca******** resources: memory: "134217728" cores: "1" core_fraction: "100" execution_timeout: 3s concurrency: "1" service_account_id: aje7tnmd885t******** status: ACTIVE log_options: disabled: true folder_id: b1gt6g8ht345******** runtime: http: {}
For more information about the
yc serverless container revision deploy
command, see the CLI reference.
To create a container, use the create REST API method for the Container resource or the ContainerService/Create gRPC API call.
To create a container revision, use the deployRevision REST API method for the Container resource or the ContainerService/DeployRevision gRPC API call.
Test the function in the container
After creating the container, you got the invocation link. To test the function in the container, use this link in the following request:
curl \
--request GET \
--header "Authorization: Bearer $(yc iam create-token)" \
<container_invocation_link>
Result:
Hello, World%
By invoking the container, you ran the code of my-first-function
you created earlier with the Functions Framework.
How to delete the resources you created
To stop paying for the resources you created: