使用 Cloud Run 函数通过事件触发器扩展 Cloud Run
借助 Cloud Run functions,您可以部署代码来处理因 Cloud Run 数据库更改而触发的事件。这样,您就可以在不运行自己的服务器的情况下添加服务器端功能。
本指南介绍了如何从 Firestore 事件为 Cloud Run 函数创建触发器。
您可以从 Firestore 数据库中的事件触发 Cloud Run functions 函数。触发后,您的函数会通过 Firestore API 和客户端库读取和更新 Firestore 数据库,以响应这些事件。
Firestore 事件触发 Cloud Run 函数的过程包括以下步骤:
服务会等待特定文档发生更改。
发生更改时,服务会被触发并执行其任务。
服务会接收包含受影响文档快照的数据对象。对于
write
或update
事件,该数据对象包含代表触发事件前后的文档状态的快照。
准备工作
- 确保您已按照设置页面中的说明为 Cloud Run 设置了新项目。
启用 Artifact Registry API、Cloud Build API、Cloud Run Admin API、Eventarc API、Firestore API、Cloud Logging API 和 Pub/Sub API:
所需的角色
您或您的管理员必须为部署者账号和触发器身份授予以下 IAM 角色。您可以选择为 Pub/Sub 服务代理授予以下 IAM 角色。
部署者账号所需的角色
如需获得从 Firestore 事件触发所需的权限,请让您的管理员为您授予项目的以下 IAM 角色:
-
Cloud Build Editor (
roles/cloudbuild.builds.editor
) -
Cloud Run Admin (
roles/run.admin
) -
Datastore Owner (
roles/datastore.owner
) -
Eventarc Admin (
roles/eventarc.admin
) -
Logs View Accessor (
roles/logging.viewAccessor
) -
Project IAM Admin (
roles/resourcemanager.projectIamAdmin
) -
Service Account Admin (
roles/iam.serviceAccountAdmin
) -
Service Account User (
roles/iam.serviceAccountUser
) -
Service Usage Admin (
roles/serviceusage.serviceUsageAdmin
)
如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限。
触发器身份所需的角色
记下 Compute Engine 默认服务账号,因为您将把它附加到 Eventarc 触发器以代表触发器的身份信息进行测试。启用或使用包含 Compute Engine 的 Google Cloud 服务后,系统会自动创建此服务账号,其电子邮件地址格式如下:
PROJECT_NUMBER-compute@developer.gserviceaccount.com
将
PROJECT_NUMBER
替换为您的 Google Cloud项目编号。您可以在 Google Cloud 控制台的欢迎页面上,或通过运行以下命令来查找项目编号:gcloud projects describe PROJECT_ID --format='value(projectNumber)'
对于生产环境,我们强烈建议创建新的服务账号,并为其授予一个或多个 IAM 角色,这些角色包含所需的最小权限并遵循最小权限原则。
- 默认情况下,只有 Project Owner、Project Editor 以及 Cloud Run Admin 和 Invoker 才能调用 Cloud Run 服务。您可以按服务控制访问权限;但是,出于测试目的,请向 Compute Engine 服务账号授予 Google Cloud 项目的 Cloud Run Invoker 角色 (
run.invoker
)。此操作会授予项目中所有 Cloud Run 服务和作业的角色。gcloud projects add-iam-policy-binding PROJECT_ID \ --member=serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com \ --role=roles/run.invoker
请注意,如果您在未授予 Cloud Run Invoker 角色的情况下为经过身份验证的 Cloud Run 服务创建触发器,则触发器会成功创建且处于活动状态。但是,触发器将无法按预期运行,并且日志中会显示类似于以下内容的消息:
The request was not authenticated. Either allow unauthenticated invocations or set the proper Authorization header.
- 将项目的 Eventarc Event Receiver 角色 (
roles/eventarc.eventReceiver
) 授予 Compute Engine 默认服务账号,以便 Eventarc 触发器可以接收来自事件提供程序的事件。gcloud projects add-iam-policy-binding PROJECT_ID \ --member=serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com \ --role=roles/eventarc.eventReceiver
Pub/Sub 服务代理的可选角色
- 如果您在 2021 年 4 月 8 日或之前启用了 Cloud Pub/Sub 服务代理,以支持经过身份验证的 Pub/Sub 推送请求,请向该服务代理授予 Service Account Token Creator 角色 (
roles/iam.serviceAccountTokenCreator
)。否则,系统会默认授予此角色:gcloud projects add-iam-policy-binding PROJECT_ID \ --member=serviceAccount:service-PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com \ --role=roles/iam.serviceAccountTokenCreator
设置您的 Firestore 数据库
在部署服务之前,您必须先创建 Firestore 数据库:
前往 Firestore 页面。
选择创建 Firestore 数据库。
在为数据库命名字段中,输入数据库 ID,例如
firestore-db
。在配置选项部分中,系统会默认选择 Firestore 原生模式以及适用的安全规则。
在位置类型中,选择区域,然后选择数据库位于的区域。一旦选择便无法更改。
点击创建数据库。
Firestore 数据模型由包含文档的集合组成。每个文档包含一组键值对。
编写 Firestore 触发的函数
如需编写响应 Firestore 事件的函数,请准备在部署期间指定以下内容:
事件类型
Firestore 支持 create
、update
、delete
和 write
事件。write
事件包含对某个文档所做的所有修改。
事件类型 | 触发器 |
---|---|
google.cloud.firestore.document.v1.created (默认) |
首次写入某个文档时触发。 |
google.cloud.firestore.document.v1.updated |
当某文档已存在并且其任何值发生了更改时触发。 |
google.cloud.firestore.document.v1.deleted |
当文档的数据被删除时触发。 |
google.cloud.firestore.document.v1.written |
在创建、更新或删除某个文档时触发。 |
google.cloud.firestore.document.v1.created.withAuthContext |
与 created 相同,但添加了身份验证信息。 |
google.cloud.firestore.document.v1.updated.withAuthContext |
与 updated 相同,但添加了身份验证信息。 |
google.cloud.firestore.document.v1.deleted.withAuthContext |
与 deleted 相同,但添加了身份验证信息。 |
google.cloud.firestore.document.v1.written.withAuthContext |
与 written 相同,但添加了身份验证信息。 |
在触发器中,通配符是使用英文大括号编写的,例如:projects/YOUR_PROJECT_ID/databases/(default)/documents/collection/{document_wildcard}
触发事件过滤条件
如需触发服务,请指定要监听的文档路径。文档路径必须与服务位于同一 Google Cloud 项目中。
以下是一些有效和无效的文档路径示例:
users/marie
:监控单个文档 (/users/marie
)。users/{username}
:监控所有用户文档。通配符用于监控集合中的所有文档。users/{username}/addresses/home
:监控所有用户的家庭住址文档。users/{username}/addresses/{addressId}
:监控所有地址文档。users/{user=**}
:监控所有用户文档以及每个用户文档下子集合中的任何文档,例如/users/userID/address/home
或/users/userID/phone/work
。users/{username}/addresses
:地址路径无效。该路径指向的是子集合addresses
,而不是某个文档。
通配符和参数
如果您不知道要监控的特定文档,请使用 {wildcard}
代替文档 ID:
users/{username}
侦听所有用户文档的更改。
在此示例中,如果 users
中的任何文档的任何字段发生更改,都会与一个名为 {username}
的通配符相匹配。
如果 users
中的某个文档有多个子集合,并且这些子集合中一个文档内的某字段发生了更改,那么不会触发 {username}
通配符。 如果您的目标是同时也响应子集合中的事件,请使用多段通配符 {username=**}
。
通配符匹配项会从文档路径中提取出来。 您可以定义任意多个通配符,以替代明确指定的集合或文档 ID。最多可以使用一个多段通配符,例如 {username=**}
。
函数代码
如需了解如何使用原生模式下的 Firestore 事件来触发 Cloud Run 函数,请参阅示例。
在源代码中添加 proto 依赖项
您必须在函数的源目录中添加 Cloud Run data.proto
文件。此文件会导入以下 proto,您还必须将这些 proto 包含在源目录中:
为依赖项使用相同的目录结构。例如,将 struct.proto
放置在 google/protobuf
内。
这些文件是解码事件数据所必需的。如果函数源代码不包含这些文件,则在运行时会返回错误。
活动属性
每个事件都包含数据属性,其中包含有关事件的信息,例如触发事件的时间。Cloud Run 会添加有关事件所涉及的数据库和文档的其他数据。您可以按如下方式访问这些属性:
Java
logger.info("Function triggered by event on: " + event.getSource()); logger.info("Event type: " + event.getType()); logger.info("Event time " + event.getTime()); logger.info("Event project: " + event.getExtension("project")); logger.info("Event location: " + event.getExtension("location")); logger.info("Database name: " + event.getExtension("database")); logger.info("Database document: " + event.getExtension("document")); // For withAuthContext events logger.info("Auth information: " + event.getExtension("authid")); logger.info("Auth information: " + event.getExtension("authtype"));
Node.js
console.log(`Function triggered by event on: ${cloudEvent.source}`); console.log(`Event type: ${cloudEvent.type}`); console.log(`Event time: ${cloudEvent.time}`); console.log(`Event project: ${cloudEvent.project}`); console.log(`Event location: ${cloudEvent.location}`); console.log(`Database name: ${cloudEvent.database}`); console.log(`Document name: ${cloudEvent.document}`); // For withAuthContext events console.log(`Auth information: ${cloudEvent.authid}`); console.log(`Auth information: ${cloudEvent.authtype}`);
Python
print(f"Function triggered by change to: {cloud_event['source']}") print(f"Event type: {cloud_event['type']}") print(f"Event time: {cloud_event['time']}") print(f"Event project: {cloud_event['project']}") print(f"Location: {cloud_event['location']}") print(f"Database name: {cloud_event['database']}") print(f"Document: {cloud_event['document']}") // For withAuthContext events print(f"Auth information: {cloud_event['authid']}") print(f"Auth information: {cloud_event['authtype']}")
事件结构
当发生如下所示的事件时,此触发器会调用服务:
{ "oldValue": { // Update and Delete operations only A Document object containing a pre-operation document snapshot }, "updateMask": { // Update operations only A DocumentMask object that lists changed fields. }, "value": { // A Document object containing a post-operation document snapshot } }
每个 Document
对象都包含一个或多个 Value
对象。如需查看类型参考信息,请参阅 Value
文档。
为函数创建触发器
点击相应标签页即可获取有关所选工具的使用说明。
控制台
使用 Google Cloud 控制台创建函数时,您还可以向函数添加触发器。请按照以下步骤为函数创建触发器:
在 Google Cloud 控制台中,前往 Cloud Run:
点击编写函数,然后输入函数详细信息。如需详细了解如何在部署期间配置函数,请参阅部署函数。
在触发器部分中,点击添加触发器。
选择 Firestore 触发器。
在 Eventarc 触发器窗格中,修改触发器详细信息,如下所示:
在触发器名称字段中输入触发器的名称,或使用默认名称。
从列表中选择触发器类型:
Google 来源,用于为 Pub/Sub、Cloud Storage、Firestore 和其他 Google 事件提供方指定触发器。
第三方,用于与提供 Eventarc 来源的非 Google 提供方集成。如需了解详情,请参阅 Eventarc 中的第三方事件。
从事件提供方列表中选择 Firestore,以选择提供用于触发函数的事件类型的产品。如需查看事件提供方列表,请参阅事件提供方和目的地。
从事件类型列表中选择 type=google.cloud.firestore.document.v1.created。触发器配置因支持的事件类型而异。如需了解详情,请参阅事件类型。
在“过滤条件”部分,选择数据库、操作和属性值,或使用默认选择内容。
如果区域字段处于启用状态,请为 Eventarc 触发器选择位置。一般来说,Eventarc 触发器所在的位置应与您要监控事件的 Google Cloud 资源所在的位置一致。在大多数情况下,您还应在同一区域部署函数。如需详细了解 Eventarc 触发器位置,请参阅了解 Eventarc 位置。
在服务账号字段中,选择一个服务账号。Eventarc 触发器与调用函数时用作身份的服务账号相关联。Eventarc 触发器的服务账号必须具有调用函数的权限。默认情况下,Cloud Run 使用 Compute Engine 默认服务账号。
(可选)指定要将传入请求发送到的服务网址路径。 这是触发器的事件应该发送到的目的地服务上的相对路径。例如:
/
、/route
、route
和route/subroute
。
填写必填字段后,点击保存触发器。
gcloud
使用 gcloud CLI 创建函数时,您必须先部署函数,然后再创建触发器。请按照以下步骤为函数创建触发器:
在包含示例代码的目录中运行以下命令以部署函数:
gcloud run deploy FUNCTION \ --source . \ --function FUNCTION_ENTRYPOINT \ --base-image BASE_IMAGE_ID \ --region REGION
您需要进行如下替换:
运行以下命令以创建用于过滤事件的触发器:
gcloud eventarc triggers create TRIGGER_NAME \ --location=EVENTARC_TRIGGER_LOCATION \ --destination-run-service=FUNCTION \ --destination-run-region=REGION \ --event-filters="type=google.cloud.firestore.document.v1.created" \ --service-account=PROJECT_NUMBER-compute@developer.gserviceaccount.com
您需要进行如下替换:
将 TRIGGER_NAME 替换为触发器的名称。
将 EVENTARC_TRIGGER_LOCATION 替换为 Eventarc 触发器的位置。一般来说,Eventarc 触发器所在的位置应与您要监控事件的 Google Cloud 资源所在的位置一致。在大多数情况下,您还应在同一区域部署函数。如需了解详情,请参阅 Eventarc 位置。
将 FUNCTION 替换为您要部署的函数的名称。
将 REGION 替换为函数的 Cloud Run 区域。
将 PROJECT_NUMBER 替换为您的 Google Cloud 项目编号。Eventarc 触发器与调用函数时用作身份的服务账号相关联。Eventarc 触发器的服务账号必须具有调用函数的权限。默认情况下,Cloud Run 使用默认计算服务账号。
每个
event-filters
标志都指定了一种事件类型,只有当事件满足其event-filters
标志中指定的所有条件时,函数才会触发。每个触发器都必须具有一个event-filters
标志,用于指定受支持的事件类型,例如写入 Firestore 的新文档或上传到 Cloud Storage 的文件。事件过滤条件类型在创建后便无法更改。 如需更改事件过滤条件类型,您必须创建新触发器并删除旧触发器。您可以酌情使用格式为ATTRIBUTE=VALUE
的受支持过滤条件重复--event-filters
标志来添加更多过滤条件。
Terraform
如需为 Cloud Run 函数创建 Eventarc 触发器,请参阅使用 Terraform 创建触发器。
示例
以下示例介绍了如何使用 Firestore 原生模式事件来触发 Cloud Run 函数。
示例 1:Hello Firestore 函数
以下示例会输出触发 Firestore 事件的字段:
Node.js
Python
Go
Java
C#
部署该函数
如需部署 Hello Firestore
函数,请运行以下命令:
设置 Firestore 数据库(如果您尚未这样做)。
如需部署函数,请参阅为函数创建触发器。
测试函数
如需测试 Hello Firestore
函数,请在 Firestore 数据库中设置一个名为 users
的集合:
在 Google Cloud 控制台中,前往 Firestore 数据库页面:
点击开始使用集合。
指定
users
作为集合 ID。如需开始添加集合的第一个文档,请在为其添加首个文档下接受自动生成的文档 ID。
为文档至少添加一个字段,并指定名称和值。例如,在字段名称中输入
username
,在字段值中输入rowan
。完成之后,点击保存。
此操作会创建一个新文档,从而触发您的函数。
如需确认您的函数已触发,请在 Google Cloud 控制台Cloud Run 概览页面中点击该函数的链接名称,以打开服务详情页面。
选择日志标签页,然后查找此字符串:
Function triggered by change to: //firestore.googleapis.com/projects/your-project-id/databases/(default)'
示例 2:“转换为大写”函数
以下示例会检索用户添加的值,将该位置的字符串转换为大写,然后将相应值替换为该大写字符串:
部署该函数
如需部署 Convert to Uppercase
函数,请运行以下命令:
设置 Firestore 数据库(如果您尚未这样做)。
如需部署函数,请参阅为函数创建触发器。
测试函数
如需测试刚刚部署的 Convert to Uppercase
函数,请在 Firestore 数据库中设置一个名为 messages
的集合:
在 Google Cloud 控制台中,前往 Firestore 数据库页面:
点击开始使用集合。
指定
messages
作为集合 ID。如需开始添加集合的第一个文档,请在为其添加首个文档下接受自动生成的文档 ID。
如需触发已部署的函数,请添加一个文档,其字段名称为
original
且字段值为minka
。保存文档时,您可以看到值字段中的小写字词转换为大写字词。
如果您随后修改字段值以包含小写字母,则会再次触发该函数,并将所有小写字母转换为大写字母。
针对函数的限制
- 无法保证顺序。快速更改可能会以意想不到的顺序触发函数调用。
- 事件至少会被传送一次,但单个事件可能会导致多次调用函数。应该避免依赖“正好一次”机制,并编写幂等函数。
- 一个触发器与单一数据库相关联。您无法创建与多个数据库匹配的触发器。
- 删除数据库不会自动删除该数据库的任何触发器。触发器会停止传送事件,但会继续存在,直到您删除触发器。