4. Eventarc触发器与事件路由

Eventarc 是 Google Cloud 上把“事件源”与“事件消费者”解耦连接的核心服务。它并不生产事件,而是订阅来自各类事件提供者的事件,按触发器上定义的条件进行过滤,再把符合条件的事件以 CloudEvents 格式投递到目标(Cloud Run、Cloud Functions、GKE、Workflows 等)。理解 Eventarc,本质上要理解四件事:事件从哪来、如何被筛选、以什么格式送达、以及跨项目与审计日志如何参与路由。

事件提供者:事件的来源分类

Eventarc 的事件提供者大致分为三类。第一类是直接事件提供者,例如 Cloud Storage、Pub/Sub、Firestore、Cloud Build、Cloud Scheduler 等,它们原生支持向 Eventarc 推送事件,通常只需在触发器上指定 --event-filters 即可。第二类是审计日志事件提供者,即通过 Cloud Audit Logs 捕获的 Google Cloud 服务 API 调用事件,例如 compute.instances.insert、iam.serviceAccounts.create,这类事件覆盖面最广,几乎所有 Google Cloud 服务的写操作都能被捕获。第三类是自定义事件提供者,通过 Pub/Sub 或第三方渠道把外部系统事件注入 Eventarc。

选择提供者时,关键判断是:目标服务是否原生支持 Eventarc 直连?如果支持,优先用直接事件,延迟更低、字段更稳定;如果不支持,则退回到审计日志事件,用 serviceName 与 methodName 过滤出所需操作。

事件过滤器:把“所有事件”收敛为“我要的事件”

触发器上的过滤器是 Eventarc 最需要精细设计的部分。过滤器以属性键值对形式表达,常见属性包括 type、serviceName、methodName、resourceName、subject 等。多个过滤器之间是逻辑与关系,只有全部匹配的事件才会被投递。

例如,要捕获“某个特定存储桶中对象创建”的事件,可以这样定义:

gcloud eventarc triggers create storage-object-created \
  --location=us-central1 \
  --destination-run-service=event-handler \
  --destination-run-region=us-central1 \
  --event-filters="type=google.cloud.storage.object.v1.finalized" \
  --event-filters="bucket=my-ingest-bucket" \
  --service-account=eventarc-sa@my-project.iam.gserviceaccount.com

这里 type 锁定事件类型,bucket 锁定资源范围。若改用审计日志事件,则过滤器会变成 type=google.cloud.audit.log.v1.written、serviceName=storage.googleapis.com、methodName=storage.objects.create。过滤越精确,下游函数被无关事件唤醒的次数越少,成本与噪声也越低。

事件格式:CloudEvents 统一封装

Eventarc 投递的事件遵循 CloudEvents 1.0 规范,分为上下文属性与数据负载两部分。上下文属性包括 id、source、specversion、type、time、subject 等,用于路由与去重;数据负载则是具体事件内容,例如存储对象的 bucket、name、size、generation。

在 Cloud Run 接收端,事件通常以 HTTP POST 到达,请求头中携带 ce-* 前缀的 CloudEvents 属性,请求体为 JSON 数据。处理函数应优先读取 ce-id 做幂等判断,读取 ce-type 做分支,再解析 body 中的业务字段。由于 Eventarc 至少投递一次,重复事件是正常现象,幂等设计不可省略。

Eventarc 事件路由链路:提供者 → 过滤器 → CloudEvents → 目标 事件提供者 直接提供者 Storage / Pub/Sub / Firestore 审计日志提供者 Audit Logs → 全服务覆盖 自定义提供者 Pub/Sub 注入外部事件 事件过滤器(逻辑与) type = google.cloud.storage... bucket = my-ingest-bucket serviceName / methodName 全部匹配才投递 CloudEvents 1.0 上下文属性 id / source / type / time subject / specversion 数据负载 bucket / name / size generation / contentType 目标 Cloud Run 跨项目事件路由 项目 A(事件源)→ 项目 B(触发器 + 目标) 需在项目 B 授予 Eventarc 服务账号对项目 A 的权限 审计日志事件跨项目时,需确保日志接收器与路由一致 审计日志集成要点 • 审计日志事件类型:google.cloud.audit.log.v1.written • 用 serviceName + methodName 精确定位操作 • 日志路由与 Eventarc 触发器需在同一区域或兼容配置 接收端处理原则 读取 ce-id 做幂等去重 → 读取 ce-type 做分支 → 解析 body 业务字段 → 返回 2xx 确认消费 Eventarc 至少投递一次,重复事件属正常现象

跨项目事件路由

默认情况下,Eventarc 触发器与事件源在同一项目内。但实际架构中,事件源(如集中式日志桶、共享存储桶)常位于一个项目,而处理逻辑部署在另一个项目。跨项目路由需要解决两个问题:权限与可见性。

权限方面,Eventarc 使用一个服务账号代表触发器去订阅事件。若事件源在项目 A,触发器在项目 B,则需要在项目 A 上给项目 B 的 Eventarc 服务账号授予相应角色,例如 roles/eventarc.eventReceiver 或针对具体服务的查看权限。可见性方面,审计日志事件跨项目时,要确认项目 A 的审计日志确实被记录且未被排除,同时 Eventarc 触发器所在区域与日志路由配置兼容。

一个常见的跨项目场景是:项目 A 是“日志汇聚项目”,所有业务项目的审计日志通过日志接收器汇聚到项目 A 的日志桶;项目 B 部署统一的事件处理服务。此时 Eventarc 触发器建在项目 B,过滤器指向项目 A 的日志桶或特定 serviceName,并通过服务账号授权完成跨项目订阅。

审计日志集成与排障

审计日志事件是 Eventarc 覆盖面最广的来源,但也是最容易“过滤不到”的来源。排障时按以下顺序检查:第一,确认目标操作确实产生了审计日志——管理活动日志默认开启,数据访问日志需显式启用;第二,确认 serviceName 与 methodName 拼写与官方文档一致,例如 Compute 实例创建是 compute.instances.insert,而不是 instances.create;第三,确认触发器区域与日志位置匹配;第四,查看 Eventarc 触发器状态与 Cloud Logging 中的 eventarc 日志,确认是否有权限拒绝或过滤不匹配的记录。

审计日志事件通常有数十秒到数分钟的延迟,不适合对实时性要求极高的场景。若需要秒级响应,优先选择直接事件提供者(如 Cloud Storage 的 object.v1.finalized)。

一个可复用的触发器设计检查清单

检查项判断依据常见错误
事件提供者类型目标服务是否原生支持 Eventarc 直连对不支持的服务硬用直接事件
过滤器精确度type + 资源属性是否收敛到最小集合只写 type,导致全桶事件都触发
服务账号权限是否授予 eventReceiver 及源服务读取权限跨项目时漏授源项目权限
区域一致性触发器区域与事件源/日志位置是否兼容跨区域订阅导致事件不可见
接收端幂等是否用 ce-id 去重重复事件导致重复业务操作
审计日志启用数据访问日志是否已开启默认只开管理日志,数据事件收不到

把以上环节串起来,Eventarc 的路由逻辑就清晰了:提供者决定事件从哪来,过滤器决定哪些事件通过,CloudEvents 决定事件长什么样,跨项目权限决定事件能否跨边界到达,审计日志集成决定覆盖面与排障路径。实际工程中,建议先用最小过滤器跑通一条链路,再逐步收紧条件,同时用 Cloud Logging 观察投递记录,确认无误后再扩展到生产流量。