1. 简介
概览
在本实验中,您将构建并部署一个网站,其内容由 Google 的 Gemini 大语言模型即时生成。该网站将是一个简单的“自选冒险”式主题探索导航器,每次点击都会根据您的选择生成一个包含新链接的新页面。您将使用 Node.js 和 Fastify 构建此应用,使用 Vertex AI SDK 调用 Gemini,将其作为可用于生产用途的安全服务部署到 Cloud Run,并使用 Identity-Aware Proxy (IAP) 对其进行保护。
您将执行的操作
- 创建使用 Vertex AI 的 Node.js Fastify 应用。
- 无需 Dockerfile 即可从源代码将应用部署到 Cloud Run。
- 使用 Identity-Aware Proxy (IAP) 保护 Cloud Run 端点。
学习内容
- 如何使用 Vertex AI SDK for Node.js 生成内容。
- 如何将 Node.js 应用部署到 Cloud Run。
- 如何使用 IAP 保护 Cloud Run 应用。
2. 项目设置
- 如果您还没有 Google 账号,则必须先创建一个 Google 账号。
- 请改用个人账号,而非工作账号或学校账号。工作账号和学校账号可能存在限制,导致您无法启用本实验所需的 API。
- 登录 Google Cloud 控制台。
- 在 Cloud 控制台中启用结算功能。
- 完成本实验的 Cloud 资源费用应低于 1 美元。
- 您可以按照本实验末尾的步骤删除资源,以避免产生更多费用。
- 新用户符合参与 $300 USD 免费试用计划的条件。
- 创建新项目或选择重复使用现有项目。
- 如果您看到有关项目配额的错误,请重复使用现有项目或删除现有项目以创建新项目。
3. 打开 Cloud Shell Editor
- 点击此链接可直接前往 Cloud Shell 编辑器
- 如果系统在今天任何时间提示您进行授权,请点击授权继续。

- 如果终端未显示在屏幕底部,请打开它:
- 点击查看
- 点击终端

- 在终端中,使用以下命令设置项目:
- 格式:
gcloud config set project [PROJECT_ID] - 示例:
gcloud config set project lab-project-id-example - 如果您不记得项目 ID,请执行以下操作:
- 您可以使用以下命令列出所有项目 ID:
gcloud projects list | awk '/PROJECT_ID/{print $2}'

- 您可以使用以下命令列出所有项目 ID:
- 格式:
- 您应会看到以下消息:
如果您看到Updated property [core/project].
WARNING并被问到Do you want to continue (Y/n)?,则很可能是您输入的项目 ID 有误。按n,按Enter,然后尝试再次运行gcloud config set project命令。
- 设置
GOOGLE_CLOUD_PROJECT环境变量export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)
4. 启用 API
在终端中,启用以下 API:
gcloud services enable \
run.googleapis.com \
aiplatform.googleapis.com \
cloudresourcemanager.googleapis.com \
iap.googleapis.com
如果系统提示您进行授权,请点击授权以继续。
此命令可能需要几分钟时间才能完成,但最终应会生成类似如下所示的成功消息:
Operation "operations/acf.p2-73d90d00-47ee-447a-b600" finished successfully.
5. 准备 Node.js 项目
- 创建一个名为
gen-ui-on-cloudrun的文件夹,用于存储要部署的源代码:mkdir gen-ui-on-cloudrun && cd gen-ui-on-cloudrun - 初始化 Node.js 项目:
npm init -y - 运行以下命令,将项目配置为使用 ES 模块并定义启动脚本:
npm pkg set type="module" - 为 Web 服务器安装
fastify,为 Vertex AI SDK 安装@google/genai:npm install fastify @google/genai
6. 创建应用代码
- 创建并打开一个新的
index.ts文件,用于存放应用源代码:cloudshell edit ~/gen-ui-on-cloudrun/index.tscloudshell edit命令会在终端上方的编辑器中打开index.ts文件。 - 在
index.ts文件中添加以下生成式界面服务器源代码:import fastifyLib from 'fastify'; import { GoogleGenAI } from '@google/genai'; const fastify = fastifyLib({ logger: true }); const ai = new GoogleGenAI({ vertexai: true, project: process.env.GOOGLE_CLOUD_PROJECT, location: process.env.GOOGLE_CLOUD_LOCATION || 'europe-west1', }); const SYSTEM_INSTRUCTION = `The user should have submitted an html page and the id of the element just clicked. Given the next page description, create a new webpage with a link back to "Start Over" (the / route), a brief overview of the topic, and a list of clickable link elements related to the page. When an element is clicked, the webpage should link to the base route / with the nextPageDescription as a query string parameter. All information needed to generate the next page should be included in the nextPageDescription without additional context. Each nextPageDescription should be less than 1500 characters. Example: If the current HTML page is for a small pet store, it might include a link to an "About" page. The href for the about page link should be /?nextPageDescription=about%20page%20for%20small%20pet%20store%20website All responses should be valid HTML without markdown backticks.`; interface QueryParams { nextPageDescription?: string; } fastify.get<{ Querystring: QueryParams }>('/', async (request, reply) => { const { nextPageDescription = 'A web page with interesting fun facts where I can select a fact to learn more about that topic.' } = request.query; try { const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: nextPageDescription, config: { systemInstruction: SYSTEM_INSTRUCTION, temperature: 0.9, } }); reply.type('text/html; charset=utf-8').send(response.text); } catch (error: any) { request.log.error(error); reply.status(500).send('An error occurred calling the AI.'); } }); const start = async () => { try { await fastify.listen({ port: Number(process.env.PORT) || 8080, host: '0.0.0.0' }); } catch (err) { fastify.log.error(err); process.exit(1); } }; start();
此代码设置了一个 Web 服务器,用于监听根路径 (/) 上的 HTTP GET 请求。当收到请求时,它会使用 nextPageDescription 查询参数(或默认值)作为通过 Vertex AI 向 Gemini 2.5 Flash 模型发出的提示。该模型由 SYSTEM_INSTRUCTION 指示返回包含链接的 HTML 页面,其中每个链接都包含用于生成后续页面的 nextPageDescription。
7. 创建服务账号
您需要为 Cloud Run 服务创建一个服务账号,以便向 Vertex AI API 进行身份验证。
- 创建名为
gen-navigator-sa的服务账号:gcloud iam service-accounts create gen-navigator-sa --display-name="Generative Navigator Service Account" - 向服务账号授予使用 Vertex AI 的权限:
gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \ --member="serviceAccount:gen-navigator-sa@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com" \ --role="roles/aiplatform.user"
8. 部署到 Cloud Run
现在,您可以直接从源代码将应用部署到 Cloud Run,而无需 Dockerfile。
- 运行
gcloud命令以部署应用: 我们在此处使用了一些重要标志:cd ~/gen-ui-on-cloudrun gcloud beta run deploy generative-web-navigator \ --source . \ --no-build \ --base-image=nodejs24 \ --command="node" \ --args="index.ts" \ --region=europe-west1 \ --no-allow-unauthenticated \ --iap \ --service-account="gen-navigator-sa@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com" \ --set-env-vars GOOGLE_CLOUD_PROJECT="$GOOGLE_CLOUD_PROJECT",GOOGLE_CLOUD_LOCATION="europe-west1"--source . --no-build --base-image=nodejs24:此标志会指示 Cloud Run 部署当前目录中的源代码,跳过构建阶段,并使用预构建的 Node.js 24 基本映像运行应用。--no-allow-unauthenticated:这样可确保只有经过身份验证的用户才能访问该服务。--iap:此权限可让 Identity-Aware Proxy (IAP) 管理对应用的访问权限。借助 IAP,您可以根据用户身份和情境来控制访问权限,而不仅仅是根据 IP 地址。
- 几分钟后,您会看到类似以下内容的消息:
Service [generative-web-navigator] revision [generative-web-navigator-12345-abc] has been deployed and is serving 100 percent of traffic.
您已部署应用,但仍需配置 IAP 以允许访问。
9. 配置 IAP 访问权限
在 Cloud Run 上启用 IAP 后,IAP 会拦截所有请求,并要求用户先通过身份验证并获得授权,然后才能访问您的服务。为此,您需要授予两项权限:
- 允许 IAP 服务本身调用您的 Cloud Run 服务。
- 允许您(或其他用户/群组)通过 IAP 访问应用。
- 获取您的项目编号,这是标识 IAP 服务代理所需的:
export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)") - 向 IAP 服务代理授予 Cloud Run 服务的
roles/run.invoker角色。这样,IAP 就可以在对用户进行身份验证和授权后调用您的服务。gcloud run services add-iam-policy-binding generative-web-navigator \ --region=europe-west1 \ --member="serviceAccount:service-$PROJECT_NUMBER@gcp-sa-iap.iam.gserviceaccount.com" \ --role="roles/run.invoker" - 为您的用户账号授予
roles/iap.httpsResourceAccessor角色。这样一来,您就可以访问受 IAP 保护的 HTTPS 资源。gcloud beta iap web add-iam-policy-binding \ --resource-type=cloud-run \ --region=europe-west1 \ --service=generative-web-navigator \ --member="user:$(gcloud config get-value account)" \ --role="roles/iap.httpsResourceAccessor"
10. 测试应用
- 获取已部署服务的网址:
gcloud run services describe generative-web-navigator --format='value(status.url)' --region=europe-west1 - 复制该网址,然后在网络浏览器中打开。由于该服务受 IAP 保护,如果您尚未登录,系统会提示您使用 Google 账号登录。通过身份验证后,您应该会看到第一个自动生成的页面。
- 点击任意链接即可前往新页面,该页面将由 AI 根据您点击的链接生成!
您已完成!您已成功将生成式界面网站部署到 Cloud Run,并使用 IAP 对其进行了保护。
11. 总结
恭喜!您已使用 Cloud Run、Vertex AI 和 IAP 成功部署并保护了生成式界面网站。
(可选)清理
如果您想清理已创建的内容,可以删除云项目,以免产生额外费用。
虽然 Cloud Run 不会对未使用的服务收费,但您仍然可能需要为您创建的 build 工件支付存储费用。删除 Cloud 项目后,系统即会停止对该项目中使用的所有资源计费。
如果您愿意,可以删除项目:
gcloud projects delete $GOOGLE_CLOUD_PROJECT
您可能还需要从 Cloud Shell 磁盘中删除不必要的资源。您可以:
- 删除 Codelab 项目目录:
rm -rf ~/gen-ui-on-cloudrun - 警告!接下来执行的操作无法撤消!如果您想删除 Cloud Shell 中的所有内容以释放空间,可以删除整个主目录。请务必将要保留的所有内容保存到其他位置。
sudo rm -rf $HOME