1. Обзор
Cloud Run — это полностью управляемая платформа, позволяющая запускать код непосредственно на масштабируемой инфраструктуре Google. В этой лабораторной работе будет показано, как подключить приложение Next.js в Cloud Run к базе данных Cloud SQL for PostgreSQL.
В этой лабораторной работе вы научитесь:
- Создайте экземпляр Cloud SQL для PostgreSQL
- Разверните приложение в Cloud Run, которое подключается к вашей базе данных Cloud SQL.
2. Предпосылки
- Если у вас еще нет учетной записи Google, вам необходимо ее создать .
- Используйте личную учётную запись вместо рабочей или учебной. Рабочие и учебные учётные записи могут иметь ограничения, которые не позволят вам включить API, необходимые для этой лабораторной работы.
3. Настройка проекта
- Войдите в Google Cloud Console .
- Включите выставление счетов в Cloud Console.
- Выполнение этой лабораторной работы обойдется менее чем в 1 доллар США в виде облачных ресурсов.
- Вы можете следовать инструкциям в конце этой лабораторной работы, чтобы удалить ресурсы и избежать дальнейших расходов.
- Новые пользователи имеют право на бесплатную пробную версию стоимостью 300 долларов США .
- Создайте новый проект или выберите повторное использование существующего проекта.
4. Откройте редактор Cloud Shell
- Перейдите в редактор Cloud Shell.
- Если терминал не отображается внизу экрана, откройте его:
- Нажмите на меню гамбургера.

- Нажмите «Терминал»
- Нажмите «Новый терминал».

- Нажмите на меню гамбургера.
- В терминале настройте свой проект с помощью этой команды:
- Формат:
gcloud config set project [PROJECT_ID] - Пример:
gcloud config set project lab-project-id-example - Если вы не можете вспомнить идентификатор своего проекта:
- Вы можете вывести список всех идентификаторов своих проектов с помощью:
gcloud projects list | awk '/PROJECT_ID/{print $2}'

- Вы можете вывести список всех идентификаторов своих проектов с помощью:
- Формат:
- Если будет предложено авторизоваться, нажмите «Авторизовать» , чтобы продолжить.

- Вы должны увидеть это сообщение:
Если вы видитеUpdated property [core/project].
WARNINGи вопросDo you want to continue (Y/N)?, вероятно, вы неправильно ввели идентификатор проекта. НажмитеN, затемEnterи попробуйте снова выполнить командуgcloud config set project.
5. Включите API
В терминале включите API:
gcloud services enable \
compute.googleapis.com \
sqladmin.googleapis.com \
run.googleapis.com \
artifactregistry.googleapis.com \
cloudbuild.googleapis.com \
networkconnectivity.googleapis.com \
servicenetworking.googleapis.com \
cloudaicompanion.googleapis.com
Если будет предложено авторизоваться, нажмите «Авторизовать» , чтобы продолжить. 
Выполнение этой команды может занять несколько минут, но в конечном итоге должно выдать сообщение об успешном выполнении, похожее на это:
Operation "operations/acf.p2-73d90d00-47ee-447a-b600" finished successfully.
6. Создайте учетную запись службы
Создайте и настройте учетную запись службы Google Cloud, которая будет использоваться Cloud Run, чтобы у нее были необходимые разрешения для подключения к Cloud SQL.
- Чтобы создать новую учетную запись службы, выполните команду
gcloud iam service-accounts createследующим образом:gcloud iam service-accounts create quickstart-service-account \ --display-name="Quickstart Service Account" - Выполните команду 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. Создайте облачную базу данных SQL
- Создайте политику подключения к службе, чтобы разрешить сетевое подключение из Cloud Run в Cloud SQL с помощью Private Service Connect.
gcloud network-connectivity service-connection-policies create quickstart-policy \ --network=default \ --project=${GOOGLE_CLOUD_PROJECT} \ --region=us-central1 \ --service-class=google-cloud-sql \ --subnets=https://www.googleapis.com/compute/v1/projects/${GOOGLE_CLOUD_PROJECT}/regions/us-central1/subnetworks/default - Создайте уникальный пароль для вашей базы данных
export DB_PASSWORD=$(openssl rand -base64 20) - Выполните команду
gcloud sql instances create, чтобы создать экземпляр Cloud SQL.gcloud sql instances create quickstart-instance \ --project=${GOOGLE_CLOUD_PROJECT} \ --root-password=${DB_PASSWORD} \ --database-version=POSTGRES_17 \ --tier=db-perf-optimized-N-2 \ --region=us-central1 \ --ssl-mode=ENCRYPTED_ONLY \ --no-assign-ip \ --enable-private-service-connect \ --psc-auto-connections=network=projects/${GOOGLE_CLOUD_PROJECT}/global/networks/default
Выполнение этой команды может занять несколько минут.
- Выполните команду
gcloud sql databases create, чтобы создать базу данных Cloud SQL вquickstart-instance.gcloud sql databases create quickstart_db \ --instance=quickstart-instance
8. Подготовить заявку
Подготовьте приложение Next.js, которое отвечает на HTTP-запросы.
- Чтобы создать новый проект Next.js с именем
task-app, используйте команду:npx --yes create-next-app@15 task-app \ --ts \ --eslint \ --tailwind \ --no-src-dir \ --turbopack \ --app \ --no-import-alias - Смените каталог на
task-app:cd task-app - Установите
pgдля взаимодействия с базой данных PostgreSQL.npm install pg - Установите
@types/pgкак зависимость разработки для использования приложения TypeScript Next.js.npm install --save-dev @types/pg - Откройте файл
actions.tsв редакторе Cloud Shell: В верхней части экрана должен появиться пустой файл. Здесь вы можете редактировать файлcloudshell edit app/actions.tsactions.ts.
- Скопируйте следующий код и вставьте его в открытый файл
actions.ts:'use server' import pg from 'pg'; type Task = { id: string; title: string; status: 'IN_PROGRESS' | 'COMPLETE'; }; const { Pool } = pg; const pool = new Pool({ host: process.env.DB_HOST, user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, ssl: { // @ts-expect-error require true is not recognized by @types/pg, but does exist on pg require: true, rejectUnauthorized: false, // required for self-signed certs // https://node-postgres.com/features/ssl#self-signed-cert } }); 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; } - Откройте файл
page.tsxв редакторе Cloud Shell: Существующий файл должен появиться в верхней части экрана. Здесь вы можете редактировать файлcloudshell edit app/page.tsxpage.tsx.
- Удалите существующее содержимое файла
page.tsx. - Скопируйте следующий код и вставьте его в открытый файл
page.tsx:'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'; }; 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} onClick={() => 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> ); }
Приложение теперь готово к развертыванию.
9. Разверните приложение в Cloud Run.
- Выполните команду gcloud projects add-iam-policy-binding следующим образом, чтобы добавить роль сетевого пользователя в учетную запись службы 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"
- Выполните команду gcloud projects add-iam-policy-binding следующим образом, чтобы добавить роль Artifact Registry Writer текущему пользователю для службы Cloud Run, которую вы собираетесь создать.
gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \ --member=user:$(gcloud auth list --filter=status:ACTIVE --format="value(account)") \ --role="roles/artifactregistry.writer"
- Выполните команду ниже, чтобы развернуть приложение в 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 - При появлении запроса нажмите
YиEnter, чтобы подтвердить свое желание продолжить:Do you want to continue (Y/n)? Y
Через несколько минут приложение должно предоставить вам URL-адрес для перехода по ссылке.
Перейдите по URL-адресу, чтобы увидеть приложение в действии. Каждый раз, когда вы переходите по URL-адресу или обновляете страницу, вы будете видеть приложение-задачу.
10. Добавьте функцию с помощью Gemini Code Assist
Итак, вы развернули веб-приложение с базой данных. Теперь мы добавим новую функцию в наше приложение next.js, используя возможности искусственного интеллекта.
- Вернуться в редактор Cloud Shell
- Откройте
page.tsxеще раз.cd ~/task-app cloudshell edit app/page.tsx - Перейдите к Gemini Code Assist в редакторе Cloud Shell:
- Нажмите на значок Близнецов.
на панели инструментов в левой части экрана - При появлении запроса войдите в систему, используя данные своей учетной записи Google.
- Если будет предложено выбрать проект, выберите проект, который вы создали для этой лабораторной работы.

- Нажмите на значок Близнецов.
- Введите запрос:
Add the ability to update the title of the task. The code in your output should be complete and working code.Ответ должен содержать что-то вроде следующих фрагментов для добавления функцийhandleEditStartиhandleEditCancel:const [editingTaskId, setEditingTaskId] = useState(''); const [editedTaskTitle, setEditedTaskTitle] = useState(''); function handleEditStart(task: Task) { setEditingTaskId(task.id); setEditedTaskTitle(task.title); }; - Замените
page.tsxна вывод Gemini Code Assist. Вот рабочий пример:'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'; }; export default function Home() { const [newTaskTitle, setNewTaskTitle] = useState(''); const [tasks, setTasks] = useState<Task[]>([]); const [editingTaskId, setEditingTaskId] = useState(''); const [editedTaskTitle, setEditedTaskTitle] = useState(''); 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(); setEditingTaskId(''); setEditedTaskTitle(''); } async function deleteTask(taskId: string) { await deleteTaskFromDatabase(taskId); await getTasks(); } function handleEditStart(task: Task) { setEditingTaskId(task.id); setEditedTaskTitle(task.title); }; 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} onClick={() => 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"> {editingTaskId === task.id ? ( <form onSubmit={(e) => { e.preventDefault(); updateTask(task, { title: editedTaskTitle }); }} className="flex" > <input type="text" value={editedTaskTitle} onChange={(e) => setEditedTaskTitle(e.target.value)} onBlur={() => updateTask(task, { title: editedTaskTitle })} // Handle clicking outside input className="flex-grow border border-gray-400 rounded px-3 py-1 mr-2 bg-inherit" /> </form> ) : ( <span onClick={() => handleEditStart(task)} className={`transition-all duration-300 ease-in-out cursor-pointer ${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> ); }
11. Повторно разверните приложение в Cloud Run.
- Выполните команду ниже, чтобы развернуть приложение в 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 - При появлении запроса нажмите
YиEnter, чтобы подтвердить свое желание продолжить:Do you want to continue (Y/n)? Y
12. Поздравления
В этой лабораторной работе вы научились делать следующее:
- Создайте экземпляр Cloud SQL для PostgreSQL
- Разверните приложение в Cloud Run, которое подключается к вашей базе данных Cloud SQL.
Уборка
У Cloud SQL нет бесплатного тарифа, и при дальнейшем использовании с вас будет взиматься плата. Вы можете удалить свой проект Cloud, чтобы избежать дополнительных расходов.
Хотя Cloud Run не взимает плату, когда сервис не используется, с вас может взиматься плата за хранение образа контейнера в Artifact Registry. Удаление проекта Cloud прекращает выставление счетов за все ресурсы, используемые в этом проекте.
Если хотите, удалите проект:
gcloud projects delete $GOOGLE_CLOUD_PROJECT
Вы также можете удалить ненужные ресурсы с диска CloudShell. Вы можете:
- Удалить каталог проекта codelab:
rm -rf ~/task-app - Внимание! Следующее действие нельзя отменить! Если вы хотите удалить всё из Cloud Shell, чтобы освободить место, вы можете удалить весь домашний каталог . Убедитесь, что всё, что вы хотите сохранить, сохранено где-то ещё.
sudo rm -rf $HOME
Продолжайте учиться
- Разверните полнофункциональное приложение Next.js в Cloud Run с Cloud SQL для PostgreSQL с помощью Cloud SQL Node.js Connector
- Разверните полнофункциональное приложение Angular в Cloud Run с Cloud SQL для PostgreSQL, используя Cloud SQL Node.js Connector
- Разверните полнофункциональное приложение Angular в Cloud Run с Firestore, используя Node.js Admin SDK
- Разверните полнофункциональное приложение Next.js в Cloud Run с Firestore, используя Node.js Admin SDK