本地函数开发

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

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

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

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

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

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

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

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

安装依赖项

在函数的目录中,安装您所用语言对应的 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 functions 支持的两种类型的函数。所有语言运行时都支持 http 和 cloudevent 签名类型。

函数类型 签名类型 说明 支持运行时
HTTP 触发的函数 http 接收和响应 HTTP 请求的函数。 所有运行时
事件驱动的函数 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.xml 或 build.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 Functions 框架,您可以将环境变量指定为命令行参数。

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

"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 值。以下命令展示了如何使用值为 8080 的 PORT 运行函数。

使用命令行实参:

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 命令以触发您的函数,并显示未格式化的响应。

事件驱动的函数

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

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"
      }'
    

后续步骤