Implantar um aplicativo full stack do Next.js no Cloud Run com o Cloud SQL para PostgreSQL usando o conector Node.js do Cloud SQL

Implantar um aplicativo full stack do Next.js no Cloud Run com o Cloud SQL para PostgreSQL usando o conector Node.js do Cloud SQL

Sobre este codelab

subjectÚltimo abr. 11, 2025 atualizado
account_circleEscrito por Luke Schlangen

1. Visão geral

O Cloud Run é uma plataforma totalmente gerenciada que permite executar seu código diretamente na infraestrutura escalonável do Google. Neste codelab, vamos demonstrar como conectar um aplicativo Next.js no Cloud Run a um banco de dados Cloud SQL para PostgreSQL usando o conector Node.js do Cloud SQL.

Neste laboratório, você vai aprender a:

  • Criar uma instância do Cloud SQL para PostgreSQL
  • Implantar um aplicativo no Cloud Run que se conecte ao seu banco de dados do Cloud SQL

2. Pré-requisitos

  1. Se você ainda não tem uma Conta do Google, crie uma.
    • Use uma conta pessoal em vez de uma conta de trabalho ou escolar. As contas escolares e de trabalho podem ter restrições que impedem a ativação das APIs necessárias para este laboratório.

3. Configurar o projeto

  1. Faça login no Console do Google Cloud.
  2. Ative o faturamento no Console do Cloud.
    • A conclusão deste laboratório deve custar menos de US $1 em recursos do Cloud.
    • Siga as etapas no final deste laboratório para excluir recursos e evitar cobranças.
    • Novos usuários estão qualificados para o teste sem custo financeiro de US$300.
  3. Crie um novo projeto ou escolha reutilizar um projeto atual.

4. Abrir editor do Cloud Shell

  1. Acesse o editor do Cloud Shell.
  2. Se o terminal não aparecer na parte de baixo da tela, abra-o:
    • Clique no menu de navegação Ícone do menu de navegação
    • Clique em Terminal.
    • Clique em Novo Terminal.Abrir um novo terminal no editor do Cloud Shell
  3. No terminal, defina seu projeto com este comando:
    • Formato:
      gcloud config set project [PROJECT_ID]
    • Exemplo:
      gcloud config set project lab-project-id-example
    • Se você não souber o ID do projeto:
      • É possível listar todos os IDs de projetos com:
        gcloud projects list | awk '/PROJECT_ID/{print $2}'
      Definir o ID do projeto no terminal do Editor do Cloud Shell
  4. Se for necessário autorizar, clique em Autorizar para continuar. Clique para autorizar o Cloud Shell
  5. Você vai receber esta mensagem:
    Updated property [core/project].
    
    Se você receber uma WARNING e receber uma solicitação Do you want to continue (Y/N)?, provavelmente inseriu o ID do projeto incorretamente. Pressione N, pressione Enter e tente executar o comando gcloud config set project novamente.

5. Ativar APIs

No terminal, ative as APIs:

gcloud services enable \
  sqladmin.googleapis.com \
  run.googleapis.com \
  artifactregistry.googleapis.com \
  cloudbuild.googleapis.com

Se for necessário autorizar, clique em Autorizar para continuar. Clique para autorizar o Cloud Shell

Esse comando pode levar alguns minutos para ser concluído, mas vai gerar uma mensagem de sucesso semelhante a esta:

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

6. Configurar uma conta de serviço

Crie e configure uma conta de serviço do Google Cloud para ser usada pelo Cloud Run, de modo que ela tenha as permissões corretas para se conectar ao Cloud SQL.

  1. Execute o comando gcloud iam service-accounts create da seguinte maneira para criar uma nova conta de serviço:
    gcloud iam service-accounts create quickstart-service-account \
     
    --display-name="Quickstart Service Account"
  2. Execute o comando gcloud projects add-iam-policy-binding da seguinte maneira para adicionar o papel Cliente do Cloud SQL à conta de serviço do Google Cloud que você acabou de criar.
    gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
      --member="serviceAccount:quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
      --role="roles/cloudsql.client"
  3. Execute o comando gcloud projects add-iam-policy-binding da seguinte maneira para adicionar o papel Usuário da instância do Cloud SQL à conta de serviço do Google Cloud que você acabou de criar.
    gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
      --member="serviceAccount:quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
      --role="roles/cloudsql.instanceUser"
  4. Execute o comando gcloud projects add-iam-policy-binding da seguinte maneira para adicionar o papel de Gravador de registros à conta de serviço do Google Cloud que você acabou de criar.
    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. Criar um banco de dados do Cloud SQL

  1. Execute o comando gcloud sql instances create para criar uma instância do Cloud SQL.
    gcloud sql instances create quickstart-instance \
        --database-version=POSTGRES_14 \
        --cpu=4 \
        --memory=16GB \
        --region=us-central1 \
        --database-flags=cloudsql.iam_authentication=on

Isso pode demorar alguns minutos.

  1. Execute o comando gcloud sql databases create para criar um banco de dados do Cloud SQL no quickstart-instance.
    gcloud sql databases create quickstart_db \
       
    --instance=quickstart-instance
  2. Crie um usuário do banco de dados PostgreSQL para a conta de serviço que você criou anteriormente para acessar o banco de dados.
    gcloud sql users create quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam \
        --instance=quickstart-instance \
        --type=cloud_iam_service_account

8. Preparar a inscrição

Prepare um aplicativo Next.js que responda a solicitações HTTP.

  1. Para criar um novo projeto Next.js chamado task-app, use o comando:
    npx --yes create-next-app@15.2.4 task-app \
      --ts \
      --eslint \
      --tailwind \
      --no-src-dir \
      --turbopack \
      --app \
      --no-import-alias
  2. Altere o diretório para task-app:
    cd task-app
  1. Instale pg e a biblioteca de conector do Node.js do Cloud SQL para interagir com o banco de dados PostgreSQL.
    npm install pg @google-cloud/cloud-sql-connector google-auth-library
  2. Instale o @types/pg como uma dependência de desenvolvimento para usar um aplicativo TypeScript Next.js.
    npm install --save-dev @types/pg
  1. Abra o arquivo actions.ts no editor do Cloud Shell:
    cloudshell edit app/actions.ts
    Um arquivo vazio vai aparecer na parte de cima da tela. É aqui que você pode editar o arquivo actions.ts. Mostre que o código vai na seção de cima da tela
  2. Copie e cole o código abaixo no arquivo actions.ts aberto:
    'use server'
    import pg from 'pg';
    import { AuthTypes, Connector } from '@google-cloud/cloud-sql-connector';
    import { GoogleAuth } from 'google-auth-library';
    const auth = new GoogleAuth();

    const { Pool } = pg;

    type Task = {
     
    id: string;
     
    title: string;
     
    status: 'IN_PROGRESS' | 'COMPLETE';
    };

    const projectId = await auth.getProjectId();

    const connector = new Connector();
    const clientOpts = await connector.getOptions({
     
    instanceConnectionName: `${projectId}:us-central1:quickstart-instance`,
     
    authType: AuthTypes.IAM,
    });

    const pool = new Pool({
     
    ...clientOpts,
     
    user: `quickstart-service-account@${projectId}.iam`,
     
    database: 'quickstart_db',
    });

    const tableCreationIfDoesNotExist = async () => {
     
    await pool.query(`CREATE TABLE IF NOT EXISTS tasks (
         
    id SERIAL NOT NULL,
         
    created_at timestamp NOT NULL,
         
    status VARCHAR(255) NOT NULL default 'IN_PROGRESS',
         
    title VARCHAR(1024) NOT NULL,
         
    PRIMARY KEY (id)
       
    );`);
    }

    // CREATE
    export async function addNewTaskToDatabase(newTask: string) {
     
    await tableCreationIfDoesNotExist();
     
    await pool.query(`INSERT INTO tasks(created_at, status, title) VALUES(NOW(), 'IN_PROGRESS', $1)`, [newTask]);
     
    return;
    }

    // READ
    export async function getTasksFromDatabase() {
     
    await tableCreationIfDoesNotExist();
     
    const { rows } = await pool.query(`SELECT id, created_at, status, title FROM tasks ORDER BY created_at DESC LIMIT 100`);
     
    return rows;
    }

    // UPDATE
    export async function updateTaskInDatabase(task: Task) {
     
    await tableCreationIfDoesNotExist();
     
    await pool.query(
       
    `UPDATE tasks SET status = $1, title = $2 WHERE id = $3`,
       
    [task.status, task.title, task.id]
     
    );
     
    return;
    }

    // DELETE
    export async function deleteTaskFromDatabase(taskId: string) {
     
    await tableCreationIfDoesNotExist();
     
    await pool.query(`DELETE FROM tasks WHERE id = $1`, [taskId]);
     
    return;
    }
  1. Abra o arquivo page.tsx no editor do Cloud Shell:
    cloudshell edit app/page.tsx
    Um arquivo vai aparecer na parte de cima da tela. É aqui que você pode editar o arquivo page.tsx. Mostre que o código vai na seção de cima da tela
  2. Exclua o conteúdo do arquivo page.tsx.
  3. Copie e cole o código abaixo no arquivo page.tsx aberto:
    'use client'
    import React, { useEffect, useState } from "react";
    import { addNewTaskToDatabase, getTasksFromDatabase, deleteTaskFromDatabase, updateTaskInDatabase } from "./actions";

    type Task = {
     
    id: string;
     
    title: string;
     
    status: 'IN_PROGRESS' | 'COMPLETE';
     
    createdAt: number;
    };

    export default function Home() {
     
    const [newTaskTitle, setNewTaskTitle] = useState('');
     
    const [tasks, setTasks] = useState<Task[]>([]);

     
    async function getTasks() {
       
    const updatedListOfTasks = await getTasksFromDatabase();
       
    setTasks(updatedListOfTasks);
     
    }

     
    useEffect(() => {
       
    getTasks();
     
    }, []);

     
    async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
       
    e.preventDefault();
       
    await addNewTaskToDatabase(newTaskTitle);
       
    await getTasks();
       
    setNewTaskTitle('');
     
    };

     
    async function updateTask(task: Task, newTaskValues: Partial<Task>) {
       
    await updateTaskInDatabase({ ...task, ...newTaskValues });
       
    await getTasks();
     
    }

     
    async function deleteTask(taskId: string) {
       
    await deleteTaskFromDatabase(taskId);
       
    await getTasks();
     
    }

     
    return (
       
    <main className="p-4">
         
    <h2 className="text-2xl font-bold mb-4">To Do List</h2>
          <
    div className="flex mb-4">
            <
    form onSubmit={handleSubmit} className="flex mb-8">
              <
    input
               
    type="text"
               
    placeholder="New Task Title"
               
    value={newTaskTitle}
               
    onChange={(e) => setNewTaskTitle(e.target.value)}
               
    className="flex-grow border border-gray-400 rounded px-3 py-2 mr-2 bg-inherit"
             
    />
             
    <button
               
    type="submit"
               
    className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded text-nowrap"
             
    >
               
    Add New Task
             
    </button>
            <
    /form>
         
    </div>
          <
    table className="w-full">
            <
    tbody>
             
    {tasks.map(function (task) {
               
    const isComplete = task.status === 'COMPLETE';
               
    return (
                  <
    tr key={task.id} className="border-b border-gray-200">
                    <
    td className="py-2 px-4">
                      <
    input
                       
    type="checkbox"
                       
    checked={isComplete}
                       
    onChange={() => updateTask(task, { status: isComplete ? 'IN_PROGRESS' : 'COMPLETE' })}
                       
    className="transition-transform duration-300 ease-in-out transform scale-100 checked:scale-125 checked:bg-green-500"
                     
    />
                   
    </td>
                    <
    td className="py-2 px-4">
                      <
    span
                       
    className={`transition-all duration-300 ease-in-out ${isComplete ? 'line-through text-gray-400 opacity-50' : 'opacity-100'}`}
                      >
                       
    {task.title}
                      <
    /span>
                   
    </td>
                    <
    td className="py-2 px-4">
                      <
    button
                       
    onClick={() => deleteTask(task.id)}
                       
    className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded float-right"
                      >
                       
    Delete
                      <
    /button>
                   
    </td>
                  <
    /tr>
               
    );
             
    })}
           
    </tbody>
          <
    /table>
       
    </main>
     
    );
    }

O aplicativo está pronto para ser implantado.

9. Implantar o aplicativo no Cloud Run

  1. Execute o comando abaixo para implantar seu aplicativo no Cloud Run:
    gcloud run deploy to-do-tracker \
        --region=us-central1 \
        --source=. \
        --service-account="quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
        --allow-unauthenticated
  2. Se necessário, pressione Y e Enter para confirmar que você quer continuar:
    Do you want to continue (Y/n)? Y
    

Após alguns minutos, o aplicativo vai fornecer um URL para você visitar.

Navegue até o URL para conferir o aplicativo em ação. O app de tarefas vai aparecer sempre que você visitar o URL ou atualizar a página.

10. Parabéns

Neste laboratório, você aprendeu a:

  • Criar uma instância do Cloud SQL para PostgreSQL
  • Implantar um aplicativo no Cloud Run que se conecte ao seu banco de dados do Cloud SQL

Limpar

O Cloud SQL não tem um nível sem custo financeiro e vai cobrar se você continuar usando. Você pode excluir seu projeto do Cloud para evitar cobranças adicionais.

O Cloud Run não gera custos quando o serviço não está em uso, mas você ainda pode receber cobranças pelo armazenamento da imagem do contêiner no Artifact Registry. A exclusão do projeto do Cloud interrompe o faturamento de todos os recursos usados nesse projeto.

Se quiser, exclua o projeto:

gcloud projects delete $GOOGLE_CLOUD_PROJECT

Você também pode excluir recursos desnecessários do disco do cloudshell. Você pode:

  1. Exclua o diretório do projeto do codelab:
    rm -rf ~/task-app
  2. Aviso: Não é possível desfazer esta ação. Se você quiser excluir tudo no Cloud Shell para liberar espaço, exclua o diretório principal inteiro. Confira se tudo o que você quer manter está salvo em outro lugar.
    sudo rm -rf $HOME

Continue aprendendo