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 アプリケーションを作成します。
  • Dockerfile なしでソースから Cloud Run にアプリケーションをデプロイします。
  • Identity-Aware Proxy(IAP)を使用して Cloud Run エンドポイントを保護します。

学習内容

  • Vertex AI SDK for Node.js を使用してコンテンツを生成する方法。
  • Node.js アプリケーションを Cloud Run にデプロイする方法。
  • IAP で Cloud Run アプリケーションを保護する方法。

2. プロジェクトの設定

  1. Google アカウントをまだお持ちでない場合は、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 が正しく入力されていない可能性があります。n を押して Enter を押し、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 を介して Gemini 2.5 Flash モデルのプロンプトとして nextPageDescription クエリ パラメータ(またはデフォルト値)を使用します。モデルは 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 にデプロイする

これで、Dockerfile を必要とせずに、ソースコードからアプリケーションを Cloud Run に直接デプロイできます。

  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 アドレスだけでなく、ユーザー ID とコンテキストに基づいてアクセスを制御できます。
  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 はすべてのリクエストを傍受し、ユーザーがサービスにアクセスする前に認証と承認を要求します。この機能を有効にするには、次の 2 つの権限を付与する必要があります。

  • 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. デプロイされたサービスの URL を取得します。
    gcloud run services describe generative-web-navigator --format='value(status.url)' --region=europe-west1
    
  2. URL をコピーして、ウェブブラウザで開きます。このサービスは 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