本地函数开发

Cloud Run functions 支持多种在标准部署环境之外运行函数的方法。这尤其适用于迭代开发,以及您希望在部署之前测试函数的情况。

无需部署函数即可运行函数的能力可以简化本地测试、数据存放区域限制合规性以及多云部署:

  • 数据存放区域限制:在本地测试函数,而无需访问生产数据,以免违反贵组织的数据存放区域规则。

  • 多云部署:多云函数部署是既定模式,可缓解可靠性关键环境中的停机风险。将函数部署到 Cloud Run 函数本身之外的环境,可以降低应用发生计划外停机的风险。

使用 Functions 框架在本地开发函数

您可以使用 Functions 框架在本地开发和测试函数。在本地开发函数有助于您测试代码,而无需重新构建函数容器。这样可以节省时间,并更轻松地测试函数。

Cloud Run 使用开源 Functions 框架库将已部署的函数封装在永久性 HTTP 应用中。

Functions 框架还可以在支持语言本身的任何其他平台(包括本地机器、本地服务器和 Compute Engine)上运行。

安装依赖项

在函数的目录中,安装您所用语言的 Cloud Functions 框架库:

Node.js

npm install --save-dev @google-cloud/functions-framework

Python

pip3 install functions-framework

Go

go install github.com/GoogleCloudPlatform/functions-framework-go/funcframework

Java

Maven

如果您使用的是 Maven,请将以下代码添加到您的 pom.xml 文件中:

<dependency>
  <groupId>com.google.cloud.functions</groupId>
  <artifactId>functions-framework-api</artifactId>
  <version>1.1.0</version>
  <scope>provided</scope>
</dependency>

Gradle

如果您使用的是 Gradle,请将以下代码添加到您的 build.gradle 文件中:

dependencies {
  // Every function needs this dependency to get the Functions Framework API.
  compileOnly 'com.google.cloud.functions:functions-framework-api:1.1.0'

  // To run function locally using Functions Framework's local invoker
  invoker 'com.google.cloud.functions.invoker:java-function-invoker:1.3.1'
}

如需了解详情,请参阅 Java Functions 框架库

C#

以下命令使用 .NET 模板以 .NET Functions 框架库作为依赖项创建新的.NET 函数代码库:

# HTTP functions
dotnet new gcf-http

# CloudEvent functions
dotnet new gcf-event

Ruby

在 Ruby 中,Functions 框架必须添加到函数的依赖项中,以便将其部署到 Cloud Run:

bundle add functions_framework

PHP

composer require google/cloud-functions-framework

配置 Functions 框架

在使用 Functions 框架运行函数之前,您需要先指定要运行的函数的类型和名称。这些特性可指定为命令行界面 (CLI) 标志或环境变量。

支持的函数类型

Functions 框架支持 Cloud Run 函数支持的两种类型的函数。所有语言运行时都支持 httpcloudevent 签名类型。

函数类型 签名类型 说明 支持运行时
HTTP 触发的函数 http 接收和响应 HTTP 请求的函数。 所有运行时
CloudEvent 函数 cloudevent 业界标准的事件格式。 所有运行时

指定要运行的函数

在使用 Functions 框架运行函数之前,您必须先指定要运行的代码中的函数。对于大多数语言,您可以如下表所示指定目标函数的方法名称来执行此操作。请注意,对于 Java.NET 运行时,此规则存在例外情况。

针对每种语言的说明

如需查看每种语言所支持的配置选项列表,请参阅下表。

Node.js

CLI 参数 环境变量 说明
--port PORT 要侦听请求的端口。(默认值:8080
--target FUNCTION_TARGET 要调用的 export 函数的名称。(默认值:function
--signature-type FUNCTION_SIGNATURE_TYPE 函数使用的签名类型。可以是 http(默认值)或 cloudevent

Python

CLI 参数 环境变量 说明
--port PORT 要侦听请求的端口。(默认值:8080
--target FUNCTION_TARGET 要调用的 export 函数的名称。(默认值:function
--signature-type FUNCTION_SIGNATURE_TYPE 函数使用的签名类型。可以是 http(默认值)或 cloudevent

Go

环境变量 说明
PORT 要侦听请求的端口。(默认值:8080

Java

参数名称 环境变量 说明
run.port PORT 要侦听请求的端口。(默认值:8080
run.functionTarget FUNCTION_TARGET 要调用的 export 函数的名称。(默认值:function

C#

CLI 参数 环境变量 说明
--port PORT 要侦听请求的端口。(默认值:8080
--target(或仅参数) FUNCTION_TARGET 要调用的函数的类名称。(默认值:function

Ruby

CLI 参数 环境变量 说明
--port PORT 要侦听请求的端口。(默认值:8080
--target FUNCTION_TARGET 要调用的 export 函数的名称。(默认值:function

PHP

环境变量 说明
FUNCTION_TARGET 要调用的函数的名称。(默认值:function
FUNCTION_SIGNATURE_TYPE 函数使用的签名类型。可以是 http(默认值)或 cloudevent

请按照以下说明配置并运行 Functions 框架:

Node.js

借助 Node.js Functions 框架,您可以将函数的名称和签名类型指定为命令行参数或环境变量

您还可以通过添加带有必需 CLI 参数的 start 脚本,在 package.json 构建文件中指定这些值,如以下示例所示。

"scripts": {
"start": "npx functions-framework --target=YOUR_FUNCTION_NAME [--signature-type=YOUR_SIGNATURE_TYPE]"
}

您也可以使用环境变量执行相同的操作:

"scripts": {
"start": "FUNCTION_TARGET=YOUR_FUNCTION_NAME FUNCTION_SIGNATURE_TYPE=YOUR_SIGNATURE_TYPE npx functions-framework"
}

YOUR_FUNCTION_NAME 替换为函数的方法名称,并将 YOUR_SIGNATURE_TYPE(如果适用)替换为函数的签名类型,如支持的函数类型所示。

Python

借助 Python Functions 框架,您可以将函数的名称和签名类型指定为命令行参数或环境变量。在运行框架时必须指定命令行参数。

Go

Go Functions 框架使用 funcframework.RegisterHTTPFunctionContext 指定函数目标和签名类型。

Java

Java Functions 框架按以下优先级顺序(从最具体到最宽泛)接受来自三种不同来源的配置数据:

  • 命令行参数
  • 构建文件
  • 环境变量

命令行参数

Maven

您可以通过向 mvn 命令添加以下命令行界面 (CLI) 标志来指定要运行的函数:

-Drun.functionTarget=YOUR_FUNCTION_NAME

您还可以通过类似方式添加以下 CLI 标志来指定目标端口:

-Drun.port=12345

Gradle

Gradle 的 CLI 标志与 Maven 的 CLI 标志几乎完全相同。Gradle 唯一所做的更改是将每个标志中的前导 -D 替换为 -P,如以下示例所示:

# Maven version

-Drun.functionTarget=...

# Gradle version

-Prun.functionTarget=...

构建文件

您还可以指定要在项目的构建文件中运行的函数。虽然 Maven 和 Gradle 的 CLI 标志类似,但其构建文件子句有显著的区别。

Maven

Maven 构建文件命名为 pom.xml。将以下子句添加到该文件可指定目标函数:

<plugin>
  <groupId>com.google.cloud.functions</groupId>
  <artifactId>function-maven-plugin</artifactId>
  <version>0.11.0</version>
  <configuration>
    <functionTarget>functions.HelloWorld</functionTarget>
  </configuration>
</plugin>

<functionTarget> 替换为函数的类名称。例如,functions 包中类名称为 HelloCloudFunctions 的函数将有一个类名称 functions.HelloCloudFunctions。它相对于父级 build 文件 - pom.xmlbuild.gradle

Gradle

Gradle 构建文件命名为 build.gradle。将以下子句添加到该文件可指定目标函数:

// Register a "runFunction" task to run the function locally
tasks.register("runFunction", JavaExec) {
  main = 'com.google.cloud.functions.invoker.runner.Invoker'
  classpath(configurations.invoker)
  inputs.files(configurations.runtimeClasspath, sourceSets.main.output)
  args(
    '--target', project.findProperty('run.functionTarget') ?: '',
    '--port', project.findProperty('run.port') ?: 8080
  )
  doFirst {
    args('--classpath', files(configurations.runtimeClasspath, sourceSets.main.output).asPath)
  }
}

C#

如果您使用 dotnet new 和前面指定的模板之一创建项目,则 .NET Functions 框架将自动检测函数。

如果您的项目包含多个函数,请参阅运行框架部分,了解如何运行特定函数。

Ruby

借助 Ruby Functions 框架,您可以将函数的名称和签名类型指定为命令行参数或环境变量。在运行框架时必须指定命令行参数。

PHP

PHP Cloud Functions 框架允许您将环境变量指定为命令行参数。

您还可以通过添加 start 脚本在 composer.json 构建文件中指定这些值,如以下示例所示。

"scripts": {
 "start": [
     "Composer\\Config::disableProcessTimeout",
     "FUNCTION_TARGET=YOUR_FUNCTION_NAME php -S localhost:${PORT:-8080} vendor/bin/router.php"
].
}

YOUR_FUNCTION_NAME 替换为函数的名称,并将 YOUR_SIGNATURE_TYPE(如果适用;此示例中未包含)替换为函数的签名类型。

运行函数

使用以下命令可以通过 Functions 框架运行函数。默认情况下,除非您明确指定 PORT 值,否则可通过 localhost:8080 访问函数。

Node.js

npm start

Python

使用命令行参数:

functions-framework --target=YOUR_FUNCTION_NAME

使用环境变量

FUNCTION_TARGET=YOUR_FUNCTION_NAME functions-framework

YOUR_FUNCTION_NAME 替换为函数的方法名称。

Go

请先按照 Go 版 Functions 框架网站中的说明创建 cmd/main.go 文件。

cd cmd
go build
./cmd

使用环境变量:

cd cmd
go build
PORT=8080 ./cmd

Java

Maven

使用以下命令可运行 pom.xml 中指定的函数:

mvn function:run

使用以下命令可运行命令行参数中指定的函数:

mvn function:run -Drun.functionTarget=YOUR_FUNCTION_NAME

使用以下命令可运行指定为环境变量的函数:

FUNCTION_TARGET=YOUR_FUNCTION_NAME mvn function:run

YOUR_FUNCTION_NAME 替换为函数的类名称。

Gradle

使用以下命令可运行 build.gradle 中指定的函数:

./gradlew runFunction

使用以下命令可运行命令行参数中指定的函数:

./gradlew runFunction -Prun.functionTarget=YOUR_FUNCTION_NAME

使用以下命令可运行指定为环境变量的函数:

FUNCTION_TARGET=YOUR_FUNCTION_NAME ./gradlew runFunction

YOUR_FUNCTION_NAME 替换为函数的类名称。

C#

如果当前 .NET 项目中只存在一个函数,则使用以下命令可运行函数。请注意,这是使用模板创建的项目的默认结构。

dotnet run

如果 .NET 项目包含多个函数,请使用以下命令运行特定函数。将 YOUR_FUNCTION_CLASSNAME 替换为函数的类名称,包括命名空间。

dotnet run YOUR_FUNCTION_CLASSNAME

如果您要同时运行多个函数,则需要运行多个 Functions 框架实例。为避免正在运行的框架实例之间发生冲突,每个实例应使用不同的 PORT 值。以下命令展示了如何使用值为 8080PORT 运行函数。

使用命令行参数:

dotnet run --target YOUR_FUNCTION_CLASSNAME --port 8080

使用环境变量:

FUNCTION_TARGET=YOUR_FUNCTION_CLASSNAME PORT=8080 dotnet run

Ruby

使用命令行参数:

bundle exec functions-framework-ruby --target YOUR_FUNCTION_NAME

使用环境变量

FUNCTION_TARGET=YOUR_FUNCTION_NAME bundle exec functions-framework-ruby

YOUR_FUNCTION_NAME 替换为函数的方法名称。

PHP

export FUNCTION_TARGET=YOUR_FUNCTION_NAME
php -S localhost:8080 vendor/bin/router.php

YOUR_FUNCTION_NAME 替换为函数的名称。

调用本地运行的函数

本部分中的练习假定您已在 localhost 上使用 Functions 框架设置本地运行的函数。

如需触发本地运行的函数,您可以向其发送使用本地服务进程路由的 HTTP 请求。

HTTP 函数

从开发环境中测试 HTTP 函数时,它通常会监听 localhost:8080 上的请求。此接口只能从运行函数的机器或虚拟机访问,从任何其他系统发送的请求都无法访问此接口。因此,您必须从运行函数的同一系统发出 HTTP 请求。在以下示例中,如果您的函数监听的是 8080 以外的端口,请将示例中的 8080 替换为您函数的端口号。

使用 Cloud Shell 测试 HTTP 函数

如果您使用 Cloud Shell 构建和测试函数,请在 Cloud Shell 终端窗口中本地启动函数,然后从浏览器或 curl 实例发出 HTTP 触发器请求,如下所示:

浏览器

点击 Cloud Shell 工具栏上的 网页预览按钮 图标,然后选择“端口 8080”,或选择“更改端口”以选择其他端口。此操作会在正确的系统上打开浏览器窗口,并向指定的端口发出 GET 请求。

Curl

如需控制 HTTP 请求的格式或查看未格式化的回复,请使用 curl

  1. 点击 Cloud Shell 菜单栏上的 + 图标,在运行函数的系统上打开新的终端窗口。
  2. 在该窗口中,运行 curl 命令以触发您的函数。例如:

    curl localhost:8080
    

在桌面服务器上测试 HTTP 函数

如果您要在本地桌面系统上构建和运行函数,请先在本地启动函数,然后从浏览器或 curl 实例发出 HTTP 触发器请求,如下所示:

浏览器

打开新的浏览器窗口或标签页,然后在浏览器地址栏中输入 http://localhost:8080。这会在桌面服务器上打开一个前往 localhost:8080 的浏览器窗口以触发您的函数。

Curl

在本地桌面上打开一个新的终端窗口,然后在该窗口中运行 curl 命令以触发您的函数。例如:

 curl localhost:8080

这将运行指定的 curl 命令以触发您的函数,并显示未格式化的响应。

CloudEvent 函数

您可以使用 curl 将示例事件发送给 CloudEvent 函数。以下 curl 请求展示了如何将 Cloud Pub/SubCloud Storage 示例事件发送给 localhost:8080 上运行的 CloudEvent 函数。

Pub/Sub

curl localhost:8080 \
  -X POST \
  -H "Content-Type: application/json" \
  -H "ce-id: 123451234512345" \
  -H "ce-specversion: 1.0" \
  -H "ce-time: 2020-01-02T12:34:56.789Z" \
  -H "ce-type: google.cloud.pubsub.topic.v1.messagePublished" \
  -H "ce-source: //pubsub.googleapis.com/projects/MY-PROJECT/topics/MY-TOPIC" \
  -d '{
        "message": {
          "data": "d29ybGQ=",
          "attributes": {
             "attr1":"attr1-value"
          }
        },
        "subscription": "projects/MY-PROJECT/subscriptions/MY-SUB"
      }'
    

Cloud Storage

curl localhost:8080 \
  -X POST \
  -H "Content-Type: application/json" \
  -H "ce-id: 123451234512345" \
  -H "ce-specversion: 1.0" \
  -H "ce-time: 2020-01-02T12:34:56.789Z" \
  -H "ce-type: google.cloud.storage.object.v1.finalized" \
  -H "ce-source: //storage.googleapis.com/projects/_/buckets/MY-BUCKET-NAME" \
  -H "ce-subject: objects/MY_FILE.txt" \
  -d '{
        "bucket": "MY_BUCKET",
        "contentType": "text/plain",
        "kind": "storage#object",
        "md5Hash": "...",
        "metageneration": "1",
        "name": "MY_FILE.txt",
        "size": "352",
        "storageClass": "MULTI_REGIONAL",
        "timeCreated": "2020-04-23T07:38:57.230Z",
        "timeStorageClassUpdated": "2020-04-23T07:38:57.230Z",
        "updated": "2020-04-23T07:38:57.230Z"
      }'
    

后续步骤