关于此 Codelab
1. 概览
在此 Codelab 中,您将创建一个新的 Cloud Run 服务,即映像垃圾回收器,它将由 Eventarc(一项用于在 Cloud Run 中接收事件的新服务)触发。从图片存储分区中删除图片时,服务会收到来自 Eventarc 的事件。然后,它会从缩略图存储分区中删除该图片,并将其从 Firestore 图片集合中移除。
学习内容
- Cloud Run
- Cloud Storage
- Cloud Firestore
- Eventarc
2. 设置和要求
自定进度的环境设置
- 登录 Google Cloud 控制台,然后创建一个新项目或重复使用现有项目。如果您还没有 Gmail 或 Google Workspace 账号,则必须创建一个。
- 项目名称是此项目参与者的显示名称。它是 Google API 尚未使用的字符串,您可以随时对其进行更新。
- 项目 ID 在所有 Google Cloud 项目中必须是唯一的,并且不可变(一经设置便无法更改)。Cloud Console 会自动生成一个唯一字符串;通常情况下,您无需关注该字符串。在大多数 Codelab 中,您都需要引用项目 ID(它通常标识为
PROJECT_ID
),因此如果您不喜欢某个 ID,请再生成一个随机 ID,还可以尝试自己创建一个,并确认是否可用。然后,项目创建后,ID 会处于“冻结”状态。 - 第三个值是一些 API 使用的项目编号。如需详细了解所有这三个值,请参阅文档。
- 接下来,您需要在 Cloud Console 中启用结算功能,才能使用 Cloud 资源/API。运行此 Codelab 应该不会产生太多的费用(如果有费用的话)。要关闭资源以避免产生超出本教程范围的费用,请按照此 Codelab 末尾提供的任何“清理”说明操作。Google Cloud 的新用户符合参与 $300 USD 免费试用计划的条件。
启动 Cloud Shell
虽然可以通过笔记本电脑对 Google Cloud 进行远程操作,但在此 Codelab 中,您将使用 Google Cloud Shell,这是一个在云端运行的命令行环境。
在 GCP 控制台中,点击右上角工具栏上的 Cloud Shell 图标:
预配和连接到环境应该只需要片刻时间。完成后,您应该会看到如下内容:
这个虚拟机已加载了您需要的所有开发工具。它提供了一个持久的 5GB 主目录,并且在 Google Cloud 中运行,大大增强了网络性能和身份验证功能。只需一个浏览器,即可完成本实验中的所有工作。
3. Eventarc 简介
Eventarc 让您可以轻松地将 Cloud Run 服务与各种来源的事件连接起来。它会为您处理事件提取、传递、安全、授权和错误处理。
您可以从 Google Cloud 来源和发布到 Cloud Pub/Sub 的自定义应用提取事件,并将其传递给 Google Cloud Run 接收器。
来自各种 Google Cloud 来源的事件通过 Cloud Audit Logs 传送。从这些来源传送事件时的延迟时间和可用性都与 Cloud Audit Logs 相关。每当来自 Google Cloud 来源的事件被触发时,系统都会创建相应的 Cloud Audit Log 条目。
发布到 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
角色授予默认计算服务账号:
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 事件库来读取 Eventarc 发送的 CloudEvents。Express 是一种 JavaScript / 节点 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 是我们将使用的节点 Web 框架,Bluebird 是一个用于处理 JavaScript promise 的库,Storage 和 Firestore 分别用于 Google Cloud Storage(我们的映像存储分区)和 Cloud Firestore 数据存储区。此外,我们要求 CloudEvent 从 Google 事件库读取 Eventarc StoreObjectData 发送的 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);
}
});
上面,我们有了节点处理程序的结构:我们的应用会响应 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 Run 使用 Google Cloud Buildpack 为您构建容器映像,而无需使用 Cloud Build 手动构建和发布容器映像。
运行以下命令以使用 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 以在没有 Dockerfile.
的情况下使用 Google Cloud Buildpack 构建容器映像。--no-allow-unauthenticated
标志使 Cloud Run 服务成为仅由特定服务账号触发的内部服务。稍后,您将使用具有 run.invoker
角色的默认计算服务账号创建一个触发器,以调用内部 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 集合中删除了其文档。
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 中接收事件的新服务)触发的 Cloud Run 服务(映像垃圾回收器)。从图片存储分区中删除图片时,服务会收到来自 Eventarc 的事件。然后,它会从缩略图存储分区中删除该图片,并将其从 Firestore 图片集合中移除。
所学内容
- Cloud Run
- Cloud Storage
- Cloud Firestore
- Eventarc