如何在 Cloud Run 部署 Generative UI 網站

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. 專案設定

  1. 如果沒有 Google 帳戶,請先建立帳戶
    • 請改用個人帳戶,而非公司或學校帳戶。公司和學校帳戶可能設有限制,導致您無法啟用本實驗室所需的 API。
  2. 登入 Google Cloud 控制台
  3. 在 Cloud 控制台中啟用帳單
    • 完成本實驗室的 Cloud 資源費用應不到 $1 美元。
    • 您可以按照本實驗室結尾的步驟刪除資源,以免產生後續費用。
    • 新使用者可獲得價值 $300 美元的免費試用期
  4. 建立新專案,或選擇重複使用現有專案。
    • 如果看到專案配額相關錯誤,請重複使用現有專案,或刪除現有專案來建立新專案。

3. 開啟 Cloud Shell 編輯器

  1. 按一下這個連結,直接前往 Cloud Shell 編輯器
  2. 如果系統在今天任何時間提示您授權,請點選「授權」繼續操作。按一下即可授權 Cloud Shell
  3. 如果畫面底部未顯示終端機,請開啟終端機:
    • 按一下「查看」
    • 按一下「終端機」在 Cloud Shell 編輯器中開啟新終端機
  4. 在終端機中,使用下列指令設定專案:
    • 格式:
      gcloud config set project [PROJECT_ID]
      
    • 範例:
      gcloud config set project lab-project-id-example
      
    • 如果忘記專案 ID,請按照下列步驟操作:
      • 您可以使用下列指令列出所有專案 ID:
        gcloud projects list | awk '/PROJECT_ID/{print $2}'
        
      在 Cloud Shell 編輯器終端機中設定專案 ID
  5. 您應會看到下列訊息:
    Updated property [core/project].
    
    如果看到 WARNING 並收到 Do you want to continue (Y/n)? 提示,可能是輸入的專案 ID 有誤。按下 nEnter,然後再次嘗試執行 gcloud config set project 指令。
  1. 設定 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

如果系統提示您授權,請點選「授權」繼續操作。按一下即可授權 Cloud Shell

這個指令可能需要幾分鐘才能完成,但最終應該會產生類似以下的成功訊息:

Operation "operations/acf.p2-73d90d00-47ee-447a-b600" finished successfully.

5. 準備 Node.js 專案

  1. 建立名為 gen-ui-on-cloudrun 的資料夾,用來儲存部署作業的原始碼:
    mkdir gen-ui-on-cloudrun && cd gen-ui-on-cloudrun
    
  2. 初始化 Node.js 專案:
    npm init -y
    
  3. 執行下列指令,將專案設定為使用 ES 模組,並定義啟動指令碼:
    npm pkg set type="module"
    
  4. 安裝網路伺服器的 fastify 和 Vertex AI SDK 的 @google/genai
    npm install fastify @google/genai
    

6. 建立應用程式程式碼

  1. 建立及開啟新的 index.ts 檔案,做為應用程式原始碼:
    cloudshell edit ~/gen-ui-on-cloudrun/index.ts
    
    cloudshell edit 指令會在終端機上方的編輯器中開啟 index.ts 檔案。
  2. 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 進行驗證。

  1. 建立名為 gen-navigator-sa 的服務帳戶:
    gcloud iam service-accounts create gen-navigator-sa --display-name="Generative Navigator Service Account"
    
  2. 將使用 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。

  1. 執行 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 位址。
  2. 幾分鐘後,您會看到類似下列的訊息:
    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 存取應用程式。
  1. 取得專案編號,這是識別 IAP 服務代理程式的必要資訊:
    export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)")
    
  2. 在 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"
    
  3. 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. 測試應用程式

  1. 取得已部署服務的網址:
    gcloud run services describe generative-web-navigator --format='value(status.url)' --region=europe-west1
    
  2. 複製網址並在網路瀏覽器中開啟。由於這項服務受到 IAP 保護,如果尚未登入,系統會提示您登入 Google 帳戶。驗證完成後,您應該會看到第一個自動產生的頁面。
  3. 按一下任一連結即可前往新頁面,系統會根據您點選的連結,以 AI 生成新頁面!

你做到了!您已成功將生成式 UI 網站部署至 Cloud Run,並使用 IAP 保護網站安全。

11. 結語

恭喜!您已成功使用 Cloud Run、Vertex AI 和 IAP,部署及保護生成式 UI 網站。

(選用) 清除

如要清除您建立的項目,可以刪除 Cloud 專案,以免產生額外費用。

不使用服務時,Cloud Run 不會收費,但您可能仍須支付已建立建構構件的儲存費用。刪除 Cloud 專案後,系統就會停止對專案使用的所有資源收取費用。

如要刪除專案,請按照下列步驟操作:

gcloud projects delete $GOOGLE_CLOUD_PROJECT

您也可以從 Cloud Shell 磁碟刪除不必要的資源。您可以:

  1. 刪除 Codelab 專案目錄:
    rm -rf ~/gen-ui-on-cloudrun
    
  2. 警告!這項操作無法復原,如要刪除 Cloud Shell 中的所有內容來釋出空間,可以刪除整個主目錄。請務必將要保留的內容另存到其他位置。
    sudo rm -rf $HOME