使用 AlloyDB 将 JavaScript 应用部署到 Cloud Run

1. 概览

Cloud Run 是一个完全托管的无服务器平台,供您运行可通过 HTTP 请求调用的无状态容器。本 Codelab 将演示如何使用 IAM 身份验证通过服务账号安全地将 Cloud Run 上的 Node.js 应用连接到 AlloyDB

学习内容

在本实验中,您将学习如何完成以下操作:

  • 创建 AlloyDB 实例(配置为使用 Private Service Connect
  • 将应用部署到 Cloud Run,以连接到 AlloyDB 实例
  • 使用 Gemini Code Assist 为应用添加功能

2. 前提条件

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

3. 项目设置

  1. 登录 Google Cloud 控制台
  2. 在 Cloud 控制台中启用结算功能
    • 完成本实验所需的 Cloud 资源费用应低于 1 美元。
    • 您可以按照本实验最后的步骤删除资源,以免产生更多费用。
    • 新用户符合参与 300 美元免费试用的条件。
  3. 创建新项目或选择重复使用现有项目。

4. 打开 Cloud Shell Editor

  1. 前往 Cloud Shell Editor
  2. 如果终端未显示在屏幕底部,请打开它:
    • 点击汉堡式菜单 汉堡式三线图标
    • 点击终端
    • 点击 New Terminal在 Cloud Shell Editor 中打开新终端
  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 Editor 终端中设置项目 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 \
  compute.googleapis.com \
  alloydb.googleapis.com \
  run.googleapis.com \
  artifactregistry.googleapis.com \
  cloudbuild.googleapis.com \
  cloudaicompanion.googleapis.com

如果系统提示您进行授权,请点击授权继续。点击以授权 Cloud Shell

此命令可能需要几分钟才能完成,但最终应该会显示类似以下内容的成功消息:

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

6. 设置服务账号

创建并配置供 Cloud Run 使用的 Google Cloud 服务账号,使其具有正确的权限来连接到 AlloyDB。

  1. 按照以下方式运行 gcloud iam service-accounts create 命令来创建新的服务账号:
    gcloud iam service-accounts create quickstart-service-account \
      --display-name="Quickstart Service Account"
    
  2. 按照以下方式运行 gcloud projects add-iam-policy-binding 命令,将 AlloyDB 数据库用户角色添加到您刚刚创建的 Google Cloud 服务账号。
    gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
      --member="serviceAccount:quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
      --role="roles/alloydb.databaseUser"
    
  3. 按照以下方式运行 gcloud projects add-iam-policy-binding 命令,将 Service Usage Consumer 角色添加到您刚刚创建的 Google Cloud 服务账号。
    gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
      --member="serviceAccount:quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
      --role="roles/serviceusage.serviceUsageConsumer"
    
  4. 按如下所示运行 gcloud projects add-iam-policy-binding 命令,将 Log Writer 角色添加到您刚刚创建的 Google Cloud 服务账号。
    gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
      --member="serviceAccount:quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
      --role="roles/logging.logWriter"
    

7. 创建 AlloyDB 实例

  1. 运行 gcloud alloydb clusters create 命令以创建 Cloud SQL 实例
    gcloud alloydb clusters create quickstart-cluster \
      --password=$(openssl rand -base64 20) \
      --region=us-central1 \
      --project=${GOOGLE_CLOUD_PROJECT} \
      --enable-private-service-connect \
      --database-version=POSTGRES_16
    

此命令可能需要几分钟才能完成。

  1. 运行 gcloud alloydb instances create 命令以创建 Cloud SQL 实例
    gcloud alloydb instances create quickstart-instance \
      --project=${GOOGLE_CLOUD_PROJECT} \
      --instance-type=PRIMARY \
      --cpu-count=2 \
      --region=us-central1 \
      --cluster=quickstart-cluster \
      --allowed-psc-projects=${GOOGLE_CLOUD_PROJECT} \
      --database-flags=alloydb.iam_authentication=on
    
  2. 运行 gcloud alloydb instances describe 命令以获取 PSC 服务连接链接,并将其导出到变量
    export SERVICE_ATTACHMENT=$(gcloud alloydb instances describe quickstart-instance \
        --cluster=quickstart-cluster --region=us-central1 \
        --format="value(pscInstanceConfig.serviceAttachmentLink)")
    
  3. gcloud compute addresses create quickstart-address \
      --region=us-central1 \
      --subnet=default
    
  4. gcloud compute forwarding-rules create quickstart-endpoint \
      --region=us-central1 \
      --network=default \
      --address=quickstart-address \
      --target-service-attachment=${SERVICE_ATTACHMENT}
    

为您之前创建的服务账号创建 PostgreSQL 数据库用户,以便访问数据库。

gcloud alloydb users create quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam \
  --cluster=quickstart-cluster \
  --region=us-central1 \
  --type=IAM_BASED \
  --superuser=true

8. 准备申请材料

准备一个响应 HTTP 请求的 Node.js 应用。

  1. 在 Cloud Shell 中,创建一个名为 helloworld 的新目录,然后切换到该目录:
    mkdir helloworld
    cd helloworld
    
  2. package.json 文件作为模块进行初始化。
    npm init -y
    npm pkg set type="module"
    npm pkg set main="index.mjs"
    npm pkg set scripts.start="node index.mjs"
    
  3. 安装 Google Cloud Auth 库。
    npm install google-auth-library
    
  4. 安装 pg 以与 PostgreSQL 数据库交互。
    npm install pg
    
  5. 安装 Express 以接受传入的 HTTP 请求。
    npm install express
    
  6. 创建一个包含应用代码的 index.mjs 文件。此代码能够:
    • 接受 HTTP 请求
    • 连接到数据库
    • 将 HTTP 请求的时间存储在数据库中
    • 返回最近五次请求的时间
    在 Cloud Shell 中运行以下命令:
    cat > index.mjs << "EOF"
    import express from 'express';
    import pg from 'pg';
    const { Pool } = pg;
    import {GoogleAuth} from 'google-auth-library';
    
    const auth = new GoogleAuth({
      scopes: ['https://www.googleapis.com/auth/alloydb.login'],
    });
    
    const pool = new Pool({
      host: process.env.DB_HOST,
      user: process.env.DB_USER,
      password: async () => {
        return await auth.getAccessToken();
      },
      database: process.env.DB_NAME,
      ssl: {
        require: true,
        rejectUnauthorized: false, // required for self-signed certs
        // https://node-postgres.com/features/ssl#self-signed-cert
      }
    });
    
    const app = express();
    
    app.get('/', async (req, res) => {
      await pool.query('INSERT INTO visits(created_at) VALUES(NOW())');
      const {rows} = await pool.query('SELECT created_at FROM visits ORDER BY created_at DESC LIMIT 5');
      console.table(rows); // prints the last 5 visits
      res.send(rows);
    });
    
    const port = parseInt(process.env.PORT) || 8080;
    app.listen(port, async () => {
      console.log('process.env: ', process.env);
      await pool.query(`CREATE TABLE IF NOT EXISTS visits (
        id SERIAL NOT NULL,
        created_at timestamp NOT NULL,
        PRIMARY KEY (id)
      );`);
      console.log(`helloworld: listening on port ${port}`);
    });
    
    EOF
    

这段代码会创建一个基本 Web 服务器,监听由 PORT 环境变量定义的端口。应用现已准备好部署。

9. 部署 Cloud Run 应用

  1. 按照以下方式运行 gcloud projects add-iam-policy-binding 命令,将 Network User 角色添加到您即将创建的 Cloud Run 服务的 Cloud Run 服务账号。
    gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
    --member "serviceAccount:service-$(gcloud projects describe ${GOOGLE_CLOUD_PROJECT} --format="value(projectNumber)")@serverless-robot-prod.iam.gserviceaccount.com" \
    --role "roles/compute.networkUser"
    
  1. 运行以下命令将应用部署到 Cloud Run:
    gcloud run deploy helloworld \
      --region=us-central1 \
      --source=. \
      --set-env-vars DB_NAME="quickstart_db" \
      --set-env-vars DB_USER="postgres" \
      --set-env-vars DB_PASSWORD=${DB_PASSWORD} \
      --set-env-vars DB_HOST="$(gcloud sql instances describe quickstart-instance --project=${GOOGLE_CLOUD_PROJECT} --format='value(settings.ipConfiguration.pscConfig.pscAutoConnections.ipAddress)')" \
      --service-account="quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
      --network=default \
      --subnet=default \
      --allow-unauthenticated
    
  2. 如果系统提示,请按 YEnter 确认您要继续:
    Do you want to continue (Y/n)? Y
    

几分钟后,应用应会提供一个网址供您访问。

前往该网址,查看应用的实际运行情况。您每次访问该网址或刷新页面时,都会看到系统以 JSON 格式返回的最近 5 次访问记录。

几分钟后,应用应会提供一个网址供您访问。

前往该网址,查看应用的实际运行情况。您每次访问该网址或刷新页面时,都会看到系统以 JSON 格式返回的最近 5 次访问记录。

10. 恭喜

在本实验中,您学习了如何执行以下操作:

  • 创建 AlloyDB 实例(配置为使用 Private Service Connect
  • 将应用部署到 Cloud Run,以连接到 AlloyDB 实例
  • 使用 Gemini Code Assist 为应用添加功能

清理

为避免因本教程中使用的资源导致您的 Google Cloud 账号产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。如果您想删除整个项目,可以运行以下命令:

gcloud projects delete ${GOOGLE_CLOUD_PROJECT}