1. 簡介
總覽
在本實驗室中,您將建構及部署網站,其內容是由 Google 的 Gemini 大型語言模型即時生成。這個網站會是簡單的「選擇你的冒險」風格導覽器,可供探索主題,每次點選都會根據你的選擇產生新網頁和新連結。您將使用 Node.js 和 Fastify 建構這項服務,並使用 Vertex AI SDK 呼叫 Gemini,然後在 Cloud Run 上以安全且可供實際使用的服務形式部署,並使用 Identity-Aware Proxy (IAP) 保護服務。
學習內容
- 建立使用 Vertex AI 的 Node.js Fastify 應用程式。
- 從原始碼將應用程式部署至 Cloud Run,不必使用 Dockerfile。
- 使用 Identity-Aware Proxy (IAP) 保護 Cloud Run 端點。
課程內容
- 瞭解如何使用 Node.js 適用的 Vertex AI SDK 生成內容。
- 如何將 Node.js 應用程式部署至 Cloud Run。
- 如何使用 IAP 保護 Cloud Run 應用程式。
2. 專案設定
- 如果沒有 Google 帳戶,請先建立帳戶。
- 請改用個人帳戶,而非公司或學校帳戶。公司和學校帳戶可能設有限制,導致您無法啟用本實驗室所需的 API。
- 登入 Google Cloud 控制台。
- 在 Cloud 控制台中啟用帳單。
- 完成本實驗室的 Cloud 資源費用應不到 $1 美元。
- 您可以按照本實驗室結尾的步驟刪除資源,以免產生後續費用。
- 新使用者可獲得價值 $300 美元的免費試用期。
- 建立新專案,或選擇重複使用現有專案。
- 如果看到專案配額相關錯誤,請重複使用現有專案,或刪除現有專案來建立新專案。
3. 開啟 Cloud Shell 編輯器
- 按一下這個連結,直接前往 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" - 安裝網路伺服器的
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檔案中新增下列生成式 UI 伺服器原始碼: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();
這段程式碼會設定網路伺服器,在根路徑 (/) 上監聽 HTTP GET 要求。收到要求時,程式碼會透過 Vertex AI,使用 nextPageDescription 查詢參數 (或預設值) 做為 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)") - 在 Cloud Run 服務中,為 IAP 服務代理程式授予
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 生成新頁面!
你做到了!您已成功將生成式 UI 網站部署至 Cloud Run,並使用 IAP 保護網站安全。
11. 結語
恭喜!您已成功使用 Cloud Run、Vertex AI 和 IAP,部署及保護生成式 UI 網站。
(選用) 清除
如要清除您建立的項目,可以刪除 Cloud 專案,以免產生額外費用。
不使用服務時,Cloud Run 不會收費,但您可能仍須支付已建立建構構件的儲存費用。刪除 Cloud 專案後,系統就會停止對專案使用的所有資源收取費用。
如要刪除專案,請按照下列步驟操作:
gcloud projects delete $GOOGLE_CLOUD_PROJECT
您也可以從 Cloud Shell 磁碟刪除不必要的資源。您可以:
- 刪除 Codelab 專案目錄:
rm -rf ~/gen-ui-on-cloudrun - 警告!這項操作無法復原,如要刪除 Cloud Shell 中的所有內容來釋出空間,可以刪除整個主目錄。請務必將要保留的內容另存到其他位置。
sudo rm -rf $HOME