自动将生成式 AI Angular Web 应用从版本控制部署到 Cloud Run

1. 概览

首次部署 Web 应用可能会令人望而生畏。即使在首次部署后,如果该流程过于繁琐,您也可能会避免部署应用的新版本。借助持续部署,您可以轻松自动部署应用更改。

在本实验中,您将编写一个 Web 应用,并配置 Cloud Run,以便在应用的源代码发生更改时自动部署应用。然后,您修改应用并再次部署。

学习内容

  • 使用 Cloud Shell 编辑器编写 Web 应用
  • 将应用代码存储在 GitHub 中
  • 自动将应用部署到 Cloud Run
  • 使用 Vertex AI 将生成式 AI 添加到您的应用

2. 前提条件

  1. 如果您还没有 Google 账号,则必须先创建一个 Google 账号
    • 请改用个人账号,而非工作账号或学校账号。工作账号和学校账号可能存在限制,导致您无法启用本实验所需的 API。
  2. 如果您还没有 GitHub 账号,则必须创建 GitHub 账号

3. 项目设置

  1. 登录 Google Cloud 控制台
  2. 在 Cloud 控制台中启用结算功能
    • 完成本实验的 Cloud 资源费用应不到 1 美元。
    • 您可以按照本实验结束时的步骤删除资源,以避免产生更多费用。
    • 新用户符合参与 300 美元免费试用计划的条件。
    • 要参加 Gen AI for Devs 活动?您或许可以获得 1 美元抵用金
  3. 创建新项目或选择重复使用现有项目。
  4. 确认 Cloud 结算中的我的项目已启用结算功能
    • 如果新项目的 Billing account 列中显示 Billing is disabled,请执行以下操作:
      1. 点击 Actions 列中的三点状图标
      2. 点击更改结算信息
      3. 选择您要使用的结算账号
    • 如果您参加的是 Gen AI for Devs 活动,则该账号的名称很可能是 Google Cloud Platform 试用结算账号

4. 打开 Cloud Shell Editor

  1. 前往 Cloud Shell 编辑器
  2. 如果终端未显示在屏幕底部,请打开它:
    • 点击汉堡式菜单 汉堡式菜单图标
    • 点击终端
    • 点击 New Terminal在 Cloud Shell 编辑器中打开新终端
  3. 在终端中,使用以下命令设置项目:
    • 格式:
      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
  4. 如果系统提示您进行授权,请点击授权以继续。点击以授权 Cloud Shell
  5. 您应会看到以下消息:
    Updated property [core/project].
    
    如果您看到 WARNING 并被问到 Do you want to continue (Y/N)?,则很可能是您输入的项目 ID 有误。按 N,按 Enter,然后尝试再次运行 gcloud config set project 命令。

5. 启用 API

在终端中,启用以下 API:

gcloud services enable \
  run.googleapis.com \
  cloudbuild.googleapis.com \
  aiplatform.googleapis.com

此命令可能需要几分钟时间才能完成,但最终应会生成类似如下所示的成功消息:

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

6. 配置 Git

  1. 设置全局 git 用户电子邮件地址:
    git config --global user.email "you@example.com"
    
  2. 设置全局 git 用户名:
    git config --global user.name "Your Name"
    
  3. 将全局 Git 默认分支设置为 main
    git config --global init.defaultBranch main
    

7. 编写代码

如需使用 Node.js 编写应用,请执行以下操作:

  1. 导航到主目录:
    cd ~
    
  2. 创建新的 codelab-genai Angular 应用:
    npx @angular/cli new codelab-genai \
        --minimal \
        --inline-template \
        --inline-style \
        --ssr \
        --defaults
    
  3. 如果系统要求安装 @angular/cli,请按 Enter 继续:
    Need to install the following packages:
    @angular/cli@18.2.4
    Ok to proceed? (y)
    
  4. 导航到 codelab-genai 目录:
    cd codelab-genai
    
  5. 在 Cloud Shell 编辑器中打开 app.component.ts 文件:
    cloudshell edit src/app/app.component.ts
    
    屏幕顶部现在应会显示一个空文件。您可以在此处修改此 app.component.ts 文件。显示代码位于屏幕顶部部分
  6. 复制以下代码并将其粘贴到打开的 app.component.ts 文件中:
    import { Component } from '@angular/core';
    import { RouterOutlet } from '@angular/router';
    
    @Component({
        selector: 'app-root',
        standalone: true,
        imports: [RouterOutlet],
        template: `
            <h1>Hello world!</h1>
    
            <router-outlet />
        `,
        styles: [],
    })
    export class AppComponent { }
    
    几秒钟后,Cloud Shell 编辑器会自动保存您的代码。此代码使用我们的“Hello world!”问候语响应 HTTP 请求。

应用的初始代码已完成,可以存储在版本控制系统中。

8. 创建代码库

  1. 返回到屏幕底部的 Cloud Shell 终端。
  2. 确保您仍位于正确的目录中:
    cd ~/codelab-genai
    
  3. 初始化 Git 代码库
    git init -b main
    
  4. 登录 GitHub CLI
    gh auth login
    
    Enter 接受默认选项,然后按照 GitHub CLI 工具中的说明操作,包括:
    1. 您要登录哪个账号? GitHub.com
    2. 您希望在此主机上使用哪种协议进行 Git 操作? HTTPS
    3. 是否使用您的 GitHub 凭据对 Git 进行身份验证?Y(如果未显示此界面,请跳过。)
    4. 您想如何对 GitHub CLI 进行身份验证? Login with a web browser
    5. 复制一次性验证码
    6. 打开 https://github.com/login/device
    7. 粘贴一次性验证码
    8. 点击 Authorize github
    9. 完成登录
  5. 确认您已登录:
    gh api user -q ".login"
    
    如果您已成功登录,此命令应会输出您的 GitHub 用户名。
  6. 创建 GITHUB_USERNAME 变量
    GITHUB_USERNAME=$(gh api user -q ".login")
    
  7. 确认您已创建环境变量:
    echo ${GITHUB_USERNAME}
    
    如果您已成功创建该变量,此命令应会输出您的 GitHub 用户名。
  8. 创建一个名为 codelab-genai 的空 GitHub 代码库:
    gh repo create codelab-genai --private
    
    如果您收到以下错误:
    GraphQL: Name already exists on this account (createRepository)
    
    那么您已经有一个名为 codelab-genai 的代码库。您可以通过以下两种方式继续学习本教程:
  9. codelab-genai 代码库添加为远程代码库 origin
    git remote add origin https://github.com/${GITHUB_USERNAME}/codelab-genai
    

9. 分享您的代码

  1. 确认您位于正确的目录中:
    cd ~/codelab-genai
    
  2. 将当前目录中的所有文件添加到相应提交中:
    git add .
    
  3. 创建第一个提交:
    git commit -m "add http server"
    
  4. 将提交推送到 origin 代码库的 main 分支:
    git push -u origin main
    

您可以运行此命令,然后访问生成的网址,以在 GitHub 上查看您的应用代码:

echo -e "\n\nTo see your code, visit this URL:\n \
    https://github.com/${GITHUB_USERNAME}/codelab-genai/blob/main/src/app/app.component.ts \n\n"

10. 设置自动部署

  1. 将 Cloud Shell 编辑器标签页保持打开状态。我们稍后会返回此标签页。
  2. 在新标签页中,访问 Cloud Run 页面
  3. 在控制台中选择正确的 Google Cloud 项目 Google Cloud 控制台项目下拉菜单
  4. 点击 CONNECT REPO
  5. 点击使用 Cloud Build 进行设置
    1. 选择 GitHub 作为代码库提供程序
      • 如果您尚未在浏览器中登录 GitHub 账号,请使用您的凭据登录。
    2. 点击验证,然后点击继续
    3. 登录后,您会在 Cloud Run 页面上看到一条消息,指出未针对您的任何代码库安装 GitHub 应用。
    4. 点击安装 Google Cloud Build 按钮。
      • 在“安装设置”页面上,选择仅选择代码库,然后选择您通过 CLI 创建的 codelab-genai 代码库。
      • 点击安装
      • 注意:如果您有大量 GitHub 代码库,则可能需要几分钟才能加载完成。
    5. 选择 your-user-name/codelab-genai 作为代码库
      • 如果未显示相应代码库,请点击管理关联的代码库链接。
    6. 分支保留为 ^main$
    7. 点击 Go、Node.js、Python、Java、.NET Core、Ruby 或 PHP(通过 Google Cloud Buildpack)
      • 其他字段(Build context directoryEntrypointFunction target)保持不变。
    8. 点击保存
  6. 向下滚动到身份验证
  7. 点击允许未经身份验证的调用
  8. 点击创建 (CREATE)

构建完成后(需要几分钟时间),运行此命令并访问生成的网址,以查看正在运行的应用:

echo -e "\n\nOnce the build finishes, visit your live application:\n \
    "$( \
        gcloud run services list | \
        grep codelab-genai | \
        awk '/URL/{print $2}' | \
        head -1 \
    )" \n\n"

11. 更改代码

返回到 Cloud Shell 编辑器

如果您仍打开着 Cloud Shell 编辑器,则可以跳过这些步骤。

  1. 前往 Cloud Shell 编辑器
  2. 如果终端未显示在屏幕底部,请打开它:
    • 点击汉堡式菜单 汉堡式菜单图标
    • 点击终端
    • 点击 New Terminal在 Cloud Shell 编辑器中打开新终端
  3. 在终端中,使用以下命令设置项目:
    • 格式:
      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
  4. 如果系统提示您进行授权,请点击授权以继续。点击以授权 Cloud Shell
  5. 您应会看到以下消息:
    Updated property [core/project].
    
    如果您看到 WARNING 并被问到 Do you want to continue (Y/N)?,则很可能是您输入的项目 ID 有误。按 N,按 Enter,然后尝试再次运行 gcloud config set project 命令。

将 Vertex AI 添加到您的应用

  1. 返回到屏幕底部的 Cloud Shell 终端。
  2. 确保您仍位于正确的目录中:
    cd ~/codelab-genai
    
  3. 安装 Node.js Vertex AI SDK:
    npm install @google-cloud/vertexai
    
  4. 安装 Node.js Google Auth SDK:
    npm install google-auth-library
    
  5. 在 Cloud Shell 编辑器中重新打开 server.ts
    cloudshell edit server.ts
    
  6. server.ts 文件中的代码替换为:
    // server.ts
    import { APP_BASE_HREF } from '@angular/common';
    import { CommonEngine } from '@angular/ssr';
    import express from 'express';
    import { fileURLToPath } from 'node:url';
    import { dirname, join, resolve } from 'node:path';
    import bootstrap from './src/main.server';
    
    import { VertexAI } from '@google-cloud/vertexai';
    import { GoogleAuth } from 'google-auth-library';
    
    
    // The Express app is exported so that it can be used by serverless Functions.
    export function app(): express.Express {
        const server = express();
        const serverDistFolder = dirname(fileURLToPath(import.meta.url));
        const browserDistFolder = resolve(serverDistFolder, '../browser');
        const indexHtml = join(serverDistFolder, 'index.server.html');
        const commonEngine = new CommonEngine();
    
        const auth = new GoogleAuth();
    
        server.set('view engine', 'html');
        server.set('views', browserDistFolder);
    
        // Example Express Rest API endpoints
        server.get('/api/facts', async (req, res) => {
            const project = await auth.getProjectId();
    
            const vertex = new VertexAI({ project: project });
            const generativeModel = vertex.getGenerativeModel({
                model: 'gemini-1.5-flash',
                generationConfig: { responseMimeType: 'application/json' }
            });
    
            const animal = req.query['animal'] || 'dog';
            const prompt = `Give me 10 fun facts about ${animal}. 
                            Return as json as an array in the format ['fact 1', 'fact 2']
                            Remove backticks and other markdown formatting.`;
    
            const resp = await generativeModel.generateContent(prompt);
            let factArray = '';
    
            if (resp.response.candidates) {
                factArray = JSON.parse(resp.response.candidates[0].content.parts[0].text || '');
            }
            res.send(factArray);
        });
    
        // Serve static files from /browser
        server.get('**', express.static(browserDistFolder, {
            maxAge: '1y',
            index: 'index.html',
        }));
    
        // All regular routes use the Angular engine
        server.get('**', (req, res, next) => {
            const { protocol, originalUrl, baseUrl, headers } = req;
    
            commonEngine
                .render({
                    bootstrap,
                    documentFilePath: indexHtml,
                    url: `${protocol}://${headers.host}${originalUrl}`,
                    publicPath: browserDistFolder,
                    providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }],
                })
                .then((html) => res.send(html))
                .catch((err) => next(err));
        });
    
        return server;
    }
    
    function run(): void {
        const port = process.env['PORT'] || 4000;
    
        // Start up the Node server
        const server = app();
        server.listen(port, () => {
            console.log(`Node Express server listening on http://localhost:${port}`);
        });
    }
    
    run();
    
  7. 在 Cloud Shell Editor 中打开 app.component.ts
    cloudshell edit src/app/app.component.ts
    
  8. app.components.ts 文件中的代码替换为:
    // app.component.ts
    import { Component, signal } from '@angular/core';
    import { FormsModule } from '@angular/forms';
    import { RouterOutlet } from '@angular/router';
    
    @Component({
        selector: 'app-root',
        standalone: true,
        imports: [RouterOutlet, FormsModule],
        template: `
            <section>
                <input
                    type="text"
                    placeholder="dog"
                    [(ngModel)]="animal"
                    class="text-black border-2 p-2 m-2 rounded"
                />
                <button
                    (click)="getNewFunFacts()"
                >
                    Get New Fun Facts
                </button>
                <ol>
                    @for(fact of facts(); track fact) {
                        <li>{{fact}}</li>  
                    } @empty {
                        <li>No facts are available</li>
                    }
                </ol>
            </section>
        `,
        styles: '',
    })
    export class AppComponent {
        animal = '';
        facts = signal<string[]>([]);
    
        getNewFunFacts() {
            fetch(`/api/facts?animal=${this.animal}`).then(response => response.json()).then(facts => {
                this.facts.set(facts);
            });
        }
    }
    

12. 重新部署

  1. 确保您仍在 Cloud Shell 中位于正确的目录中:
    cd ~/codelab-genai
    
  2. 运行以下命令,将应用的新版本提交到本地 Git 代码库:
    git add .
    git commit -m "add latest changes"
    
  3. 将更改推送到 GitHub:
    git push
    
  4. 构建完成后,运行以下命令并访问已部署的应用:
    echo -e "\n\nOnce the build finishes, visit your live application:\n \
        "$( \
            gcloud run services list | \
            grep codelab-genai | \
            awk '/URL/{print $2}' | \
            head -1 \
        )" \n\n"
    

可能需要过几分钟,build 才能完成,然后您才能看到所做的更改。

您可以在以下网址查看所有修订版本的历史记录:https://console.cloud.google.com/run/detail/us-central1/codelab-genai/revisions

13. (可选)审核 Vertex AI 使用情况

与其他 Google Cloud 服务一样,您可以审核 Vertex AI 操作。审核日志可帮助您回答“哪些用户何时在何处执行过哪些操作?”这一问题。Vertex AI 的管理审核日志默认处于启用状态。如需审核生成内容的相关请求,您必须启用数据访问审核日志

  1. 在 Google Cloud 控制台中,前往审核日志页面:

    如果您使用搜索栏查找此页面,请选择子标题为 IAM 和管理的结果。
  2. 确保现有 Google Cloud 项目是您创建 Cloud Run 应用的项目。
  3. 数据访问审核日志配置表中,从“服务”列中找到并选择 Vertex AI API
  4. 日志类型标签页中,选择数据访问审核日志类型 Admin readData read
  5. 点击保存

启用后,您将能够看到应用每次调用的审核日志。如需查看包含调用详情的审核日志,请执行以下操作:

  1. 返回已部署的应用,然后刷新页面以触发日志。
  2. 在 Google Cloud 控制台中,前往日志浏览器页面:

  3. 在查询窗口中,输入:
    LOG_ID("cloudaudit.googleapis.com%2Fdata_access")
    protoPayload.serviceName="aiplatform.googleapis.com"
    
  4. 点击运行查询

审核日志会捕获 Vertex AI API 的使用情况,但不会让您观察工作负载相关数据,例如提示或回答详细信息。

14. (可选)提高 AI 工作负载的可观测性

审核日志不会捕获与工作负载相关的信息。为了提高工作负载的可观测性,您必须明确记录此信息。您可以使用自己喜欢的日志记录框架来完成此操作。以下步骤演示了如何使用原生 Node.js 日志记录机制来实现此目的。

  1. 在 Cloud Shell 编辑器中重新打开 server.ts
    cloudshell edit ~/codelab-genai/server.ts
    
  2. 在对 await generativeModel.generateContent(prompt)(第 19 行)的调用后,添加以下代码行:
    console.log(JSON.stringify({
        severity: 'DEBUG',
        message: 'Content is generated',
        prompt: prompt,
        response: resp.response,
    }));
    
    此代码使用结构化日志记录格式将有关生成内容的 stdout 信息写入日志。Cloud Run 中的日志记录代理会捕获打印到 stdout 的输出,并以这种格式写入 Cloud Logging。
  3. 重新打开 Cloud Shell,然后输入以下命令,确保您位于正确的目录中:
    cd ~/codelab-genai
    
  4. 提交更改:
    git commit -am "observe generated content"
    
  5. 将更改推送到 GitHub 以触发修改后版本的重新部署:
    git push
    

新版本部署完毕后,您可以观察有关对 Vertex AI 的调用的调试信息。

如需查看应用日志,请执行以下操作:

  1. 在 Google Cloud 控制台中,前往日志浏览器页面:

  2. 在查询窗口中,输入:
    LOG_ID("run.googleapis.com%2Fstdout")
    severity=DEBUG
    
  3. 点击运行查询

查询结果会显示包含提示和 Vertex AI 回答的日志,其中包括可用于监控安全实践的“安全评级”

15. (可选)清理

虽然 Cloud Run 不会对未在使用中的服务计费,但您可能仍然需要支付将容器映像存储在 Artifact Registry 中而产生的相关费用。您可以删除 Cloud 项目,以避免产生费用。删除 Cloud 项目后,系统即会停止对该项目中使用的所有资源计费。

如果您愿意,可以删除项目:

gcloud projects delete $GOOGLE_CLOUD_PROJECT

您可能还希望从 Cloud Shell 磁盘中删除不必要的资源。您可以:

  1. 删除 Codelab 项目目录:
    rm -rf ~/codelab-genai
    
  2. 警告!此操作无法撤消!如果您想删除 Cloud Shell 中的所有内容以释放空间,可以删除整个主目录。请务必将要保留的所有内容保存到其他位置。
    sudo rm -rf $HOME
    

16. 恭喜

在本实验中,您编写了一个 Web 应用,并配置了 Cloud Run,以便在应用的源代码发生更改时自动部署应用。然后,您修改了应用并再次部署。

如果您喜欢本实验,可以尝试使用其他编码语言或框架再次完成本实验:

如果您有兴趣参与用户体验 (UX) 调研,以帮助我们改进您今天使用的产品,请在此处注册

以下是一些可供您继续学习的选项: