在 VPC 网络中的内部 HTTP 端点上接收 Pub/Sub 事件


本教程介绍如何在 Virtual Private Cloud (VPC) 网络中创建内部 HTTP 端点,该端点使用 Eventarc 接收 Pub/Sub 消息事件。如需详细了解此事件目标,请参阅将事件路由到 VPC 网络中的内部 HTTP 端点

您可以在终端或 Cloud Shell 中使用 Google Cloud CLI 运行以下命令。

目标

在此教程中,您将学习以下操作:

  1. 创建 VPC 网络以为您的云端资源和服务提供网络。VPC 在逻辑上与 Google Cloud 中的其他网络隔离。
  2. 创建子网。 每个 VPC 网络均由一个或多个 IP 地址范围(即“子网”)组成。子网属于区域级资源,并且具有与之关联的 IP 地址范围。
  3. 创建 VPC 防火墙规则,以允许或拒绝流量进出 VPC 网络中的虚拟机 (VM) 实例。
  4. 创建网络连接,以允许提供方 VPC 网络发起与使用方 VPC 网络的连接。
  5. 在 VPC 网络中创建一个 Compute Engine 虚拟机实例。
  6. 在虚拟机实例上将 Web 服务器部署为事件接收器服务。
  7. 创建 Eventarc 触发器,以将 Pub/Sub 事件路由到虚拟机实例上的事件接收器。
  8. 建立连到虚拟机实例的 SSH 连接。
  9. 将消息发布到 Pub/Sub 主题以生成事件,并在 SSH-in-browser 工具中查看事件正文。

费用

在本文档中,您将使用 Google Cloud 的以下收费组件:

您可使用价格计算器根据您的预计使用情况来估算费用。 Google Cloud 新用户可能有资格申请免费试用

完成本文档中描述的任务后,您可以通过删除所创建的资源来避免继续计费。如需了解详情,请参阅清理

准备工作

  1. 登录您的 Google Cloud 账号。如果您是 Google Cloud 新手,请创建一个账号来评估我们的产品在实际场景中的表现。新客户还可获享 $300 赠金,用于运行、测试和部署工作负载。
  2. 安装 Google Cloud CLI。
  3. 如需初始化 gcloud CLI,请运行以下命令:

    gcloud init
  4. 创建或选择 Google Cloud 项目

    • 创建 Google Cloud 项目:

      gcloud projects create PROJECT_ID

      PROJECT_ID 替换为您要创建的 Google Cloud 项目的名称。

    • 选择您创建的 Google Cloud 项目:

      gcloud config set project PROJECT_ID

      PROJECT_ID 替换为您的 Google Cloud 项目 名称。

  5. 确保您的 Google Cloud 项目已启用结算功能

  6. Enable the Compute Engine, Eventarc, and Pub/Sub APIs:

    gcloud services enable compute.googleapis.com eventarc.googleapis.com pubsub.googleapis.com
  7. 安装 Google Cloud CLI。
  8. 如需初始化 gcloud CLI,请运行以下命令:

    gcloud init
  9. 创建或选择 Google Cloud 项目

    • 创建 Google Cloud 项目:

      gcloud projects create PROJECT_ID

      PROJECT_ID 替换为您要创建的 Google Cloud 项目的名称。

    • 选择您创建的 Google Cloud 项目:

      gcloud config set project PROJECT_ID

      PROJECT_ID 替换为您的 Google Cloud 项目 名称。

  10. 确保您的 Google Cloud 项目已启用结算功能

  11. Enable the Compute Engine, Eventarc, and Pub/Sub APIs:

    gcloud services enable compute.googleapis.com eventarc.googleapis.com pubsub.googleapis.com
  12. 更新 Google Cloud CLI 组件:
    gcloud components update
  13. 使用您的账号登录:
    gcloud auth login
  14. 设置本快速入门中使用的配置变量:
    REGION=us-central1
    ZONE=us-central1-a
    
  15. 如果您是项目创建者,则会被授予基本 Owner 角色 (roles/owner)。默认情况下,此 Identity and Access Management (IAM) 角色可提供完全访问大多数 Google Cloud 资源所需的权限,您可以跳过此步骤。

    如果您不是项目创建者,则必须向主账号授予项目的必需权限。例如,主账号可以是 Google 账号(针对最终用户)或服务账号(针对应用和计算工作负载)。如需了解详情,请参阅事件目标位置的角色和权限页面。

    所需权限

    如需获得完成本快速入门所需的权限,请让您的管理员为您授予项目的以下 IAM 角色:

    如需详细了解如何授予角色,请参阅管理访问权限

    您也可以通过自定义角色或其他预定义角色来获取所需的权限。

  16. 如果您在 2021 年 4 月 8 日或之前启用了 Cloud Pub/Sub 服务代理,以支持经过身份验证的 Pub/Sub 推送请求,请向 Google 管理的服务账号授予 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
    替换以下内容:
    • PROJECT_ID:您的 Google Cloud 项目 ID
    • PROJECT_NUMBER:您的 Google Cloud 项目编号。您可以在 Google Cloud 控制台的欢迎页面上或者通过运行以下命令找到项目编号:
      gcloud projects describe PROJECT_ID --format='value(projectNumber)'

创建一个自定义模式 VPC 网络

VPC 网络是物理网络的虚拟版本,在 Google 的生产网络内实现。可为 Compute Engine 虚拟机实例提供连接。

创建自定义模式 VPC 网络时,系统不会自动创建子网。这种类型的网络让您可以完全控制其子网和 IP 范围。

gcloud compute networks create NETWORK_NAME \
    --subnet-mode=custom \
    --bgp-routing-mode=regional \
    --mtu=1460

NETWORK_NAME 替换为 VPC 网络的名称。

请注意以下几点:

  • 您创建的每个新网络在同一项目内必须具有唯一的名称。
  • 边界网关协议 (BGP) 路由模式可控制网络中 Cloud Router 路由器的行为,可以是 globalregional。默认值为 regional
  • 最大传输单元 (MTU) 是该网络的最大数据包大小。可以将 MTU 设置为 13008896 之间的任何值。默认值为 1460。在将 MTU 设置为高于 1460 的值之前,请查看最大传输单元

如需了解详情,请参阅创建和管理 VPC 网络

创建仅限 IPv4 的子网

网络必须至少先具有一个子网,然后才能使用。

在创建子网时,请根据子网规则设置名称、区域和至少一个主要 IPv4 地址范围。请注意,您不能在未定义子网的区域中创建实例。

gcloud compute networks subnets create SUBNET_NAME \
    --region=$REGION \
    --network=NETWORK_NAME \
    --range=10.10.10.0/24

SUBNET_NAME 替换为新子网的名称。

如需了解详情,请参阅子网

创建 VPC 防火墙规则

通过 VPC 防火墙规则,您可以根据端口号、标记或协议在 VPC 网络中的资源之间允许或拒绝流量。

VPC 防火墙规则是在网络级别定义的,仅会应用于在其中创建它们的网络;但是,您为规则选择的名称在项目中必须是唯一的。

  1. 为您的 VPC 网络创建防火墙规则,以允许来自任何 IPv4 地址 (0.0.0.0/0) 的入站流量使用端口 22 流向网络上的任何实例。传送事件不需要此规则。但是,为了实现本教程的目的,请创建规则,以便您可以使用 SSH 连接到虚拟机并确认事件的传送:

    gcloud compute firewall-rules create RULE_NAME_ONE \
        --network=projects/PROJECT_ID/global/networks/NETWORK_NAME \
        --direction=INGRESS \
        --priority=65534 \
        --action=ALLOW \
        --source-ranges=0.0.0.0/0 \
        --rules=tcp:22
  2. 为您的 VPC 网络创建一条防火墙规则,允许使用端口 80 从特定 IP 地址范围到网络上的任何实例的入口流量(因为您将在侦听端口 80 的虚拟机上部署 Web 服务器):

    gcloud compute firewall-rules create RULE_NAME_TWO \
        --network=projects/PROJECT_ID/global/networks/NETWORK_NAME \
        --direction=INGRESS \
        --priority=1000 \
        --action=ALLOW \
        --source-ranges=10.10.10.0/24 \
        --rules=tcp:80

    RULE_NAME_ONERULE_NAME_TWO 替换为您的防火墙规则的唯一名称。

    请注意,使用 --source-ranges 是可选的,它指示允许建立与网络上实例的防火墙规则匹配的入站连接的 IP 地址块列表。在这种情况下,该范围与您之前创建的子网中使用的范围相匹配。

    我们建议您使用此标志,以将防火墙规则专门应用于 Eventarc 流量。如果未指定 --source-ranges--source-tags,则 --source-ranges 默认为 0.0.0.0/0,这意味着该规则适用于来自内部或外部的所有传入 IPv4 连接网络。

如需了解详情,请参阅使用 VPC 防火墙规则

创建网络连接

网络连接是一种资源,允许提供方 VPC 网络通过 Private Service Connect 接口启动与使用方 VPC 网络的连接。

为了发布事件,Eventarc 使用网络连接与 VPC 网络中托管的内部 HTTP 端点建立连接。

您可以创建一个网络连接,以自动接受与该网络连接关联的任何 Private Service Connect 接口发出的连接。在包含 HTTP 目标服务的同一网络和区域中创建网络连接。

gcloud compute network-attachments create ATTACHMENT_NAME \
    --region=$REGION \
    --subnets=SUBNET_NAME \
    --connection-preference=ACCEPT_AUTOMATIC

ATTACHMENT_NAME 替换为网络连接的名称。

如需了解详情,请参阅关于网络连接

在指定子网中创建虚拟机实例

Compute Engine 虚拟机实例是托管在 Google 基础架构上的虚拟机。术语 Compute Engine 实例、虚拟机实例和虚拟机是同义词,可互换使用。虚拟机实例包括 Google Kubernetes Engine (GKE) 集群、App Engine 柔性环境实例,以及 Compute Engine 虚拟机上构建的其他 Google Cloud 产品。

在 VPC 网络中创建一个 Compute Engine 虚拟机实例,您可以在其中部署事件接收器服务。

gcloud compute instances create INSTANCE_NAME \
      --zone=$ZONE \
      --machine-type=e2-medium \
      --subnet=SUBNET_NAME

INSTANCE_NAME 替换为虚拟机名称。

如需了解详情,请参阅创建并启动虚拟机实例

在虚拟机上部署事件接收器

在虚拟机上部署 Web 服务器,该服务器侦听端口 80,并接收并记录事件。

  1. 使用 Google Cloud 控制台中的 SSH 按钮连接到虚拟机,以建立与虚拟机实例的 SSH 连接。

    与 SSH 服务器建立连接后,使用 SSH-in-browser 终端在虚拟机实例上运行命令。

  2. 在 SSH-in-browser 终端中,创建一个文件名为 server.py 且包含以下 Python 代码的文本文件:

    #!/usr/bin/env python3
    from http.server import BaseHTTPRequestHandler, HTTPServer
    import logging
    
    class S(BaseHTTPRequestHandler):
        def _set_response(self):
            self.send_response(200)
            self.send_header('Content-type', 'text/html')
            self.end_headers()
    
        def do_GET(self):
            logging.info("GET request,\nPath: %s\nHeaders:\n%s\n", str(self.path), str(self.headers))
            self._set_response()
            self.wfile.write("GET request for {}".format(self.path).encode('utf-8'))
    
        def do_POST(self):
            content_length = int(self.headers['Content-Length'])
            post_data = self.rfile.read(content_length)
            logging.info("POST request,\nPath: %s\nHeaders:\n%s\n\nBody:\n%s\n",
                    str(self.path), str(self.headers), post_data.decode('utf-8'))
    
            self._set_response()
            self.wfile.write("POST request for {}".format(self.path).encode('utf-8'))
    
    def run(server_class=HTTPServer, handler_class=S, port=80):
        logging.basicConfig(level=logging.INFO)
        server_address = ('', port)
        http_server = server_class(server_address, handler_class)
        logging.info('Starting HTTP Server at port %d...\n', port)
        try:
            http_server.serve_forever()
        except KeyboardInterrupt:
            pass
        http_server.server_close()
        logging.info('Stopping HTTP Server...\n')
    
    if __name__ == '__main__':
        from sys import argv
    
        if len(argv) == 2:
            run(port=int(argv[1]))
        else:
            run()
  3. 启动服务器,并在本教程的其余步骤中让服务器保持运行:

    sudo python3 server.py
    

创建 Eventarc 触发器

创建一个 Eventarc 触发器,用于创建新的 Pub/Sub 主题,并在消息发布到 Pub/Sub 主题时将事件路由到虚拟机上部署的事件接收器。

启用 Compute Engine API 后,默认服务账号是 Compute Engine 默认服务账号 (PROJECT_NUMBER-compute@developer.gserviceaccount.com)。对于测试,触发器会使用默认服务账号的身份。

gcloud eventarc triggers create TRIGGER_NAME \
    --location=$REGION \
    --destination-http-endpoint-uri=http://INSTANCE_NAME.$ZONE.c.PROJECT_ID.internal \
    --network-attachment="projects/PROJECT_ID/regions/$REGION/networkAttachments/ATTACHMENT_NAME" \
    --event-filters="type=google.cloud.pubsub.topic.v1.messagePublished" \
    --service-account=PROJECT_NUMBER-compute@developer.gserviceaccount.com

PROJECT_NUMBER 替换为您的 Google Cloud 项目编号。您可以在 Google Cloud 控制台的欢迎页面上或者通过运行以下命令找到项目编号:

gcloud projects describe PROJECT_ID --format='value(projectNumber)'

如需详细了解如何配置触发器,请参阅将事件路由到 VPC 网络中的内部 HTTP 端点

生成并查看 Pub/Sub 主题事件

您可以通过向 Pub/Sub 主题发布消息来生成事件。

  1. 查找 Pub/Sub 主题并将其设置为环境变量:

    export MY_TOPIC=$(gcloud eventarc triggers describe TRIGGER_NAME \
        --location=$REGION \
        --format='value(transport.pubsub.topic)')
  2. 向 Pub/Sub 主题发布消息以生成事件:

    gcloud pubsub topics publish $MY_TOPIC --message "Hello World"

    Eventarc 触发器会将事件路由到 VPC 网络中的内部 HTTP 端点。在 SSH-in-browser 终端中,输出事件正文。修改后应如下所示:

    Body:
    {
        "message": {
            "data": "SGVsbG8gV29ybGQ=",
            "messageId": "8795720366614192",
            "publishTime": "2023-08-26T13:09:48Z"
        }
    }
    
    10.10.10.3 - - [26/Aug/2023 13:09:49] "POST / HTTP/1.1" 200 -
    

    请注意,如果您从 Base64 格式对 SGVsbG8gV29ybGQ=data 值进行解码,则返回“Hello World”。

您已成功将事件接收器服务部署到 VPC 网络中的内部 HTTP 端点,创建 Eventarc 触发器,从 Pub/Sub 生成事件,并确认事件按预期方式进行路由目标端点的触发器。

清理

为避免因本教程中使用的资源导致您的 Google Cloud 账号产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。

删除项目

    删除 Google Cloud 项目:

    gcloud projects delete PROJECT_ID

删除各个资源

  1. 删除 Eventarc 触发器:
    gcloud eventarc triggers delete TRIGGER_NAME --location=$REGION
  2. 删除实例:
    gcloud compute instances delete INSTANCE_NAME
  3. 删除网络连接:
    gcloud compute network-attachments delete ATTACHMENT_NAME --region=$REGION
  4. 删除防火墙规则:
    gcloud compute firewall-rules delete RULE_NAME_ONE
    gcloud compute firewall-rules delete RULE_NAME_TWO
  5. 删除子网:
    gcloud compute networks subnets delete SUBNET_NAME --region=$REGION
  6. 删除 VPC 网络:
    gcloud compute networks delete NETWORK_NAME

后续步骤