每日图片:实验 5 - 删除映像后进行清理

1. 概览

在此代码实验中,您将创建一个新的 Cloud Run 服务(映像垃圾收集器),该服务将由 Eventarc(一种用于在 Cloud Run 中接收事件的新服务)触发。当图片从图片存储分区中删除时,服务会收到来自 Eventarc 的事件。然后,它会从缩略图存储分区中删除该图片,并从 Firestore 图片集合中移除该图片。

d93345bfc235f81e.png

学习内容

  • Cloud Run
  • Cloud Storage
  • Cloud Firestore
  • Eventarc

2. 设置和要求

自定进度的环境设置

  1. 登录 Google Cloud 控制台,然后创建一个新项目或重复使用现有项目。如果您还没有 Gmail 或 Google Workspace 账号,则必须创建一个

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

  • 项目名称是此项目参与者的显示名称。它是 Google API 尚未使用的字符串,您可以随时对其进行更新。
  • 项目 ID 在所有 Google Cloud 项目中必须是唯一的,并且不可变(一经设置便无法更改)。Cloud Console 会自动生成一个唯一字符串;通常情况下,您无需关注该字符串。在大多数 Codelab 中,您都需要引用项目 ID(它通常标识为 PROJECT_ID),因此如果您不喜欢某个 ID,请再生成一个随机 ID,还可以尝试自己创建一个,并确认是否可用。然后,项目创建后,ID 会处于“冻结”状态。
  • 第三个值是一些 API 使用的项目编号。如需详细了解所有这三个值,请参阅文档
  1. 接下来,您需要在 Cloud Console 中启用结算功能,才能使用 Cloud 资源/API。运行此 Codelab 应该不会产生太多的费用(如果有费用的话)。要关闭资源以避免产生超出本教程范围的费用,请按照此 Codelab 末尾提供的任何“清理”说明操作。Google Cloud 的新用户符合参与 $300 USD 免费试用计划的条件。

启动 Cloud Shell

虽然可以通过笔记本电脑对 Google Cloud 进行远程操作,但在此 Codelab 中,您将使用 Google Cloud Shell,这是一个在云端运行的命令行环境。

在 GCP 控制台中,点击右上角工具栏上的 Cloud Shell 图标:

bce75f34b2c53987.png

预配和连接到环境应该只需要片刻时间。完成后,您应该会看到如下内容:

f6ef2b5f13479f3a.png

这个虚拟机已加载了您需要的所有开发工具。它提供了一个持久的 5GB 主目录,并且在 Google Cloud 中运行,大大增强了网络性能和身份验证功能。只需一个浏览器,即可完成本实验中的所有工作。

3. Eventarc 简介

借助 Eventarc,您可以轻松将 Cloud Run 服务与来自各种来源的事件相关联。它会为您处理事件提取、传送、安全、授权和错误处理。

776ed63706ca9683.png

您可以从 Google Cloud 来源和发布到 Cloud Pub/Sub 的自定义应用中提取事件,并将这些事件传递到 Google Cloud Run 接收器。

来自各种 Google Cloud 来源的事件通过 Cloud Audit Logs 传送。来自这些来源的事件传送延迟时间和可用性与 Cloud Audit Logs 的延迟时间和可用性相关。每当触发来自 Google Cloud 来源的事件时,系统都会创建相应的 Cloud Audit Logs 日志条目。

发布到 Cloud Pub/Sub 的自定义应用可以以任何格式将消息发布到其指定的 Pub/Sub 主题。

事件触发器是一种过滤机制,用于指定要将哪些事件传送给哪些接收器。

所有事件均以 CloudEvents v1.0 格式传送,以实现跨服务互操作性。

4. 准备工作

启用 API

您需要 Eventarc 服务来触发 Cloud Run 服务。确保已启用该功能:

gcloud services enable eventarc.googleapis.com

您应该会看到操作已成功完成:

Operation "operations/acf.5c5ef4f6-f734-455d-b2f0-ee70b5a17322" finished successfully.

配置服务账号

触发器将使用默认计算服务账号。将 eventarc.eventReceiver 角色授予默认的 Compute 服务账号:

PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format='value(projectNumber)')

gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
    --member serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com \
    --role roles/eventarc.eventReceiver

pubsub.publisher 角色授予 Cloud Storage 服务账号。Eventarc Cloud Storage 触发器需要以下权限:

SERVICE_ACCOUNT=$(gsutil kms serviceaccount -p $PROJECT_NUMBER)

gcloud projects add-iam-policy-binding $PROJECT_NUMBER \
    --member serviceAccount:$SERVICE_ACCOUNT \
    --role roles/pubsub.publisher

如果您在 2021 年 4 月 8 日或之前启用了 Pub/Sub 服务账号,请将 iam.serviceAccountTokenCreator 角色授予 Pub/Sub 服务账号:

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member serviceAccount:service-$PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com \
  --role roles/iam.serviceAccountTokenCreator

5. 克隆代码

如果您在上一个 Codelab 中尚未克隆代码,请克隆代码:

git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop

然后,您可以前往包含该服务的目录:

cd serverless-photosharing-workshop/services/garbage-collector/nodejs

该服务的布局文件如下:

services
 |
 ├── garbage-collector
      |
      ├── nodejs
           |
           ├── index.js
           ├── package.json

该文件夹内有 3 个文件:

  • index.js 包含 Node.js 代码
  • package.json 定义库依赖项

6. 探索代码

依赖项

package.json 文件定义了所需的库依赖项:

{
  "name": "garbage_collector_service",
  "version": "0.0.1",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "dependencies": {
    "cloudevents": "^4.0.1",
    "express": "^4.17.1",
    "@google/events": "^3.1.0",
    "@google-cloud/firestore": "^4.9.9",
    "@google-cloud/storage": "^5.8.3"
  }
}

我们依赖 Cloud Storage 库来删除 Cloud Storage 中的图片。我们声明对 Cloud Firestore 的依赖关系,以便删除之前存储的图片元数据。此外,我们还依赖 CloudEvents SDK 和 Google Events 库来读取 Eventarc 发送的 CloudEvents。Express 是一个 JavaScript / Node Web 框架。Bluebird 用于处理 promise。

index.js

我们来详细了解一下 index.js 代码:

const express = require('express');
const {Storage} = require('@google-cloud/storage');
const Firestore = require('@google-cloud/firestore');
const { HTTP } = require("cloudevents");
const {toStorageObjectData} = require('@google/events/cloud/storage/v1/StorageObjectData');

我们需要程序运行所需的各种依赖项:Express 是我们将要使用的 Node Web 框架,Bluebird 是用于处理 JavaScript Promise 的库,Storage 和 Firestore 分别用于处理 Google Cloud Storage(我们的图片存储分区)和 Cloud Firestore 数据存储区。此外,我们还需要 CloudEvent 读取由 Eventarc StoreObjectData 从 Google Events 库发送的 CloudEvent,以读取 CloudEvent 的 Cloud Storage 事件正文。

const app = express();
app.use(express.json());

app.post('/', async (req, res) => {
    try {
        const cloudEvent = HTTP.toEvent({ headers: req.headers, body: req.body });
        console.log(cloudEvent);


        /* ... */

    } catch (err) {
        console.log(`Error: ${err}`);
        res.status(500).send(err);
    }
});

上例展示了 Node 处理程序的结构:我们的应用会响应 HTTP POST 请求。它从 HTTP 请求中读取 CloudEvent,并进行一些错误处理,以防出现问题。现在,我们来看看此结构中包含的内容。

下一步是检索并解析 CloudEvent 正文,然后检索对象名称:

const storageObjectData = toStorageObjectData(cloudEvent.data);
console.log(storageObjectData);

const objectName = storageObjectData.name;

知道图片名称后,我们就可以从缩略图存储分区中将其删除:

try {
    await storage.bucket(bucketThumbnails).file(objectName).delete();
    console.log(`Deleted '${objectName}' from bucket '${bucketThumbnails}'.`);
}
catch(err) {
    console.log(`Failed to delete '${objectName}' from bucket '${bucketThumbnails}': ${err}.`);
}

最后一步,从 Firestore 集合中删除图片元数据:

try {
    const pictureStore = new Firestore().collection('pictures');
    const docRef = pictureStore.doc(objectName);
    await docRef.delete();

    console.log(`Deleted '${objectName}' from Firestore collection 'pictures'`);
}
catch(err) {
    console.log(`Failed to delete '${objectName}' from Firestore: ${err}.`);
}

res.status(200).send(`Processed '${objectName}'.`);

现在,我们需要让 Node 脚本监听传入的请求。另请检查是否已设置必需的环境变量:

app.listen(PORT, () => {
    if (!bucketThumbnails) throw new Error("BUCKET_THUMBNAILS not set");
    console.log(`Started service on port ${PORT}`);
});

7. 在本地测试

在部署到云端之前,请先在本地测试代码,确保其正常运行。

garbage-collector/nodejs 文件夹中,安装 npm 依赖项并启动服务器:

export BUCKET_THUMBNAILS=thumbnails-$GOOGLE_CLOUD_PROJECT

npm install; npm start

如果一切顺利,它应该会在端口 8080 上启动服务器:

Started service on port 8080

使用 CTRL-C 退出。

8. 构建并部署到 Cloud Run

在部署到 Cloud Run 之前,请将 Cloud Run 区域设置为某个受支持的区域,并将平台设置为 managed

REGION=europe-west1
gcloud config set run/region $REGION
gcloud config set run/platform managed

您可以检查配置是否已设置:

gcloud config list

...
[run]
platform = managed
region = europe-west1

除了使用 Cloud Build 手动构建和发布容器映像之外,您还可以依靠 Cloud Run 使用 Google Cloud Buildpack 为您构建容器映像。

运行以下命令,使用 Google Cloud Buildpack 构建容器映像,然后将容器映像部署到 Cloud Run:

SERVICE_NAME=garbage-collector-service

gcloud run deploy $SERVICE_NAME \
    --source . \
    --no-allow-unauthenticated \
    --update-env-vars BUCKET_THUMBNAILS=$BUCKET_THUMBNAILS

请注意 –-source 标志。此标志会指示 Cloud Run 使用 Google Cloud Buildpack 构建容器映像,而无需 Dockerfile.--no-allow-unauthenticated 标志会将 Cloud Run 服务设为仅由特定服务账号触发的内部服务。稍后,您将创建一个具有 run.invoker 角色的默认 Compute Engine 服务账号,以调用内部 Cloud Run 服务。

9. 创建触发器

在 Eventarc 中,触发器用于定义哪个服务应接收哪种事件。在这种情况下,您希望服务在存储分区中的文件被删除时收到事件。

将触发器的位置设置为与上传的照片存储分区位于同一区域:

gcloud config set eventarc/location eu

创建 AuditLog 触发器以过滤 storage.objects.delete 事件并将其发送到 Cloud Run 服务:

BUCKET_IMAGES=uploaded-pictures-$GOOGLE_CLOUD_PROJECT

gcloud eventarc triggers create trigger-$SERVICE_NAME \
  --destination-run-service=$SERVICE_NAME \
  --destination-run-region=$REGION \
  --event-filters="type=google.cloud.storage.object.v1.deleted" \
  --event-filters="bucket=$BUCKET_IMAGES" \
  --service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com

您可以使用以下命令仔细检查触发器是否已创建:

gcloud eventarc triggers list

10. 测试服务

如需测试该服务是否正常运行,请前往 uploaded-pictures 存储分区并删除其中一张图片。您应该会在服务的日志中看到,该服务已删除 thumbnails 存储分区中的相关图片,并且还从 pictures Firestore 集合中删除了相应文档。

519abf90e7ea4d12.png

11. 清理(可选)

如果您不打算继续学习本系列中的其他实验,可以清理资源,以节省费用,并践行良好的云资源管理实践。您可以按如下方式逐个清理资源。

删除服务:

gcloud run services delete $SERVICE_NAME -q

删除 Eventarc 触发器:

gcloud eventarc triggers delete trigger-$SERVICE_NAME -q

或者,您也可以删除整个项目:

gcloud projects delete $GOOGLE_CLOUD_PROJECT

12. 恭喜!

恭喜!您创建了一个由 Eventarc 触发的 Cloud Run 服务(映像垃圾收集器),Eventarc 是一项用于在 Cloud Run 中接收事件的新服务。当图片从图片存储分区中删除时,服务会收到来自 Eventarc 的事件。然后,它会从缩略图存储分区中删除该图片,并从 Firestore 图片集合中移除该图片。

所学内容

  • Cloud Run
  • Cloud Storage
  • Cloud Firestore
  • Eventarc