GSP315

简介
在实验室挑战赛中,我们会为您提供一个场景和一系列任务。您将使用从课程的各个实验中学到的技能自行确定如何完成这些任务,而不是按照分步说明进行操作。自动评分系统(显示在本页面中)会提供有关您是否已正确完成任务的反馈。
在您参加实验室挑战赛期间,我们不会再教授新的 Google Cloud 概念知识。您需要拓展所学的技能,例如通过更改默认值和查看并研究错误消息来更正您自己所犯的错误。
要想获得满分,您必须在该时间段内成功完成所有任务!
我们建议已报名参加在 Google Cloud 上设置应用开发环境技能徽章课程的学员参加此实验室挑战赛。准备好接受挑战了吗?
设置
点击“开始实验”按钮前的注意事项
请阅读以下说明。实验是计时的,并且您无法暂停实验。计时器在您点击开始实验后即开始计时,显示 Google Cloud 资源可供您使用多长时间。
此实操实验可让您在真实的云环境中开展实验活动,免受模拟或演示环境的局限。为此,我们会向您提供新的临时凭据,您可以在该实验的规定时间内通过此凭据登录和访问 Google Cloud。
为完成此实验,您需要:
- 能够使用标准的互联网浏览器(建议使用 Chrome 浏览器)。
注意:请使用无痕模式(推荐)或无痕浏览器窗口运行此实验。这可以避免您的个人账号与学生账号之间发生冲突,这种冲突可能导致您的个人账号产生额外费用。
注意:请仅使用学生账号完成本实验。如果您使用其他 Google Cloud 账号,则可能会向该账号收取费用。
挑战场景
您刚开始在一家名为 Jooli Inc. 的公司担任初级云工程师。到目前为止,您一直在帮助团队创建和管理 Google Cloud 资源。
您应该掌握了完成这些任务所需的技能和知识,所以我们不会提供分步指南。
您的挑战
您需要帮助新组建的开发团队完成一个新项目的一些初始工作。这个名为 Memories 的项目主要用于照片存储和整理。您的任务是协助 Memories 团队初步配置他们的应用开发环境。
您收到请求,要完成下列任务:
- 创建一个存储桶来存储照片。
- 创建一个 Pub/Sub 主题,供您创建的 Cloud Run 函数使用。
- 创建一个 Cloud Run 函数。
- 移除 Memories 项目前任云工程师的访问权限。
您应遵循的一些 Jooli Inc. 标准:
- 在 区域和 可用区中创建所有资源(如无特别指示)。
- 使用项目 VPC。
- 命名通常采用“team-resource”格式,例如,实例可以命名为 kraken-webserver1。
- 分配经济实惠的资源容量。各个项目会受到监控,过度使用资源会导致其所属的项目终止(可能包括您的项目),因此请务必仔细规划。这是监控团队分享的指南:如无特别指示,小型 Linux 虚拟机建议使用 e2-micro,Windows 或其他应用(例如 Kubernetes 节点)建议使用 e2-medium。
下文详细说明了您的每项任务,祝您好运!
任务 1. 创建存储桶
您需要创建一个名为 的存储桶来存储照片。
确保在 区域和 可用区中创建资源。
点击检查我的进度以验证是否完成了以下目标:
创建名为 的存储桶
任务 2. 创建 Pub/Sub 主题
创建名为 的 Pub/Sub 主题,供 Cloud Run 函数发送消息。
点击“检查我的进度”以验证是否完成了以下目标:
创建名为 的 Pub/Sub 主题
任务 3. 创建缩略图 Cloud Run 函数
创建函数
创建一个 Cloud Run 函数 ,以便为添加到 存储桶中的图片创建缩略图。
确保 Cloud Run 函数使用 Cloud Run functions 环境(第 2 代)。
确保在 区域和 可用区中创建资源。
- 使用
Node.js 22
创建名为 的 Cloud Run 函数(第 2 代)。
注意:
每次在任务 1 的存储桶中创建对象时,都需要执行此 Cloud Run 函数。
在此过程中,Cloud Run 函数可能会请求权限以启用 API,或者请求权限以向服务账号授予角色。
请按请求启用所有必要的 API 并授予角色。
-
请确保将入口点(要执行的 Cloud Functions 函数)设为 ,并将触发器设为 Cloud Storage
。
-
将以下代码添加到 index.js
文件中:
const functions = require('@google-cloud/functions-framework');
const { Storage } = require('@google-cloud/storage');
const { PubSub } = require('@google-cloud/pubsub');
const sharp = require('sharp');
functions.cloudEvent('{{{ project_0.startup_script.function }}}', async cloudEvent => {
const event = cloudEvent.data;
console.log(`Event: ${JSON.stringify(event)}`);
console.log(`Hello ${event.bucket}`);
const fileName = event.name;
const bucketName = event.bucket;
const size = "64x64";
const bucket = new Storage().bucket(bucketName);
const topicName = "{{{ project_0.startup_script.topic }}}";
const pubsub = new PubSub();
if (fileName.search("64x64_thumbnail") === -1) {
// 没有缩略图,请获取文件扩展名
const filename_split = fileName.split('.');
const filename_ext = filename_split[filename_split.length - 1].toLowerCase();
const filename_without_ext = fileName.substring(0, fileName.length - filename_ext.length - 1); // 修正子字符串以移除句点
if (filename_ext === 'png' || filename_ext === 'jpg' || filename_ext === 'jpeg') {
// 当前仅支持 png 和 jpg
console.log(`Processing Original: gs://${bucketName}/${fileName}`);
const gcsObject = bucket.file(fileName);
const newFilename = `${filename_without_ext}_64x64_thumbnail.${filename_ext}`;
const gcsNewObject = bucket.file(newFilename);
try {
const [buffer] = await gcsObject.download();
const resizedBuffer = await sharp(buffer)
.resize(64, 64, {
fit: 'inside',
withoutEnlargement: true,
})
.toFormat(filename_ext)
.toBuffer();
await gcsNewObject.save(resizedBuffer, {
metadata: {
contentType: `image/${filename_ext}`,
},
});
console.log(`Success: ${fileName} → ${newFilename}`);
await pubsub
.topic(topicName)
.publishMessage({ data: Buffer.from(newFilename) });
console.log(`Message published to ${topicName}`);
} catch (err) {
console.error(`Error: ${err}`);
}
} else {
console.log(`gs://${bucketName}/${fileName} is not an image I can handle`);
}
} else {
console.log(`gs://${bucketName}/${fileName} already has a thumbnail`);
}
});
- 将以下代码添加到
package.json
文件中:
{
"name": "thumbnails",
"version": "1.0.0",
"description": "Create Thumbnail of uploaded image",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"@google-cloud/functions-framework": "^3.0.0",
"@google-cloud/pubsub": "^2.0.0",
"@google-cloud/storage": "^6.11.0",
"sharp": "^0.32.1"
},
"devDependencies": {},
"engines": {
"node": ">=4.3.2"
}
}
注意:如果出现权限遭拒的错误消息,提示可能要等待几分钟以便所有必要的权限传播给服务代理,请等待几分钟,然后重试。确保您向正确的服务账号分配了适当的角色(Eventarc Service Agent、Eventarc Event Receiver、Service Account Token Creator 和 Pub/Sub Publisher)。
测试函数
- 将您选择的 PNG 或 JPG 图片上传到 存储桶。
注意:您也可以先将此图片 (https://storage.googleapis.com/cloud-training/gsp315/map.jpg
) 下载到自己的机器上,然后再上传到存储桶中。
您很快就会看到一张缩略图(请使用存储桶详情页面中的刷新,进行手动更新)。
上传图片文件后,您可以点击下方链接查看进度。您无需等待系统创建缩略图。
可选:如果函数已成功部署,但您未在存储桶中看到缩略图,可以检查触发器标签页中是否显示了您之前为该函数提供的触发器信息。如果您之前遇到错误,该信息可能未正确保存。
如果您在函数的触发器标签页中未看到 Cloud Storage 触发器,可以重新创建该触发器(请参阅标题为为服务创建触发器的文档页面),然后重新上传新文件,再次进行测试(在添加新文件后刷新页面)。
点击“检查我的进度”以验证是否完成了以下目标:
验证 Cloud Run 函数
任务 4. 移除前任云工程师
您会看到项目中定义了两个用户。
- 一个是您的账号(,角色为“Owner”)。
- 另一个是前任云工程师的账号(,角色为“Viewer”)。
- 从项目中移除前任云工程师的访问权限。
点击检查我的进度以验证是否完成了以下目标:
移除前任云工程师
恭喜!

后续步骤/了解详情
此技能徽章课程是 Google 的在 Google Cloud 中执行基本的基础设施任务和 Cloud Architect 学习路线的组成部分。如果您已完成学习路线中的其他技能徽章课程,可在 Google Cloud Skills Boost 目录中搜索您可以报名参加的其他技能徽章课程。
Google Cloud 培训和认证
…可帮助您充分利用 Google Cloud 技术。我们的课程会讲解各项技能与最佳实践,可帮助您迅速上手使用并继续学习更深入的知识。我们提供从基础到高级的全方位培训,并有点播、直播和虚拟三种方式选择,让您可以按照自己的日程安排学习时间。各项认证可以帮助您核实并证明您在 Google Cloud 技术方面的技能与专业知识。
本手册的最后更新时间:2025 年 3 月 8 日
本实验的最后测试时间:2025 年 3 月 8 日
版权所有 2025 Google LLC 保留所有权利。Google 和 Google 徽标是 Google LLC 的商标。其他所有公司名和产品名可能是其各自相关公司的商标。