1. Обзор
Cloud Run — это полностью управляемая платформа, позволяющая запускать код непосредственно поверх масштабируемой инфраструктуры Google. В этом практическом занятии мы продемонстрируем, как подключить приложение Next.js на Cloud Run к базе данных Firestore с помощью Node.js Admin SDK.
В этой лабораторной работе вы научитесь:
- Создайте базу данных Firestore.
- Разверните приложение в Cloud Run, которое будет подключаться к вашей базе данных Firestore.
2. Предварительные требования
- Если у вас еще нет учетной записи Google, вам необходимо ее создать .
- Используйте личный аккаунт вместо рабочего или учебного. Рабочие и учебные аккаунты могут иметь ограничения, которые не позволят вам включить API, необходимые для этой лабораторной работы.
3. Настройка проекта
- Войдите в консоль Google Cloud .
- Включите выставление счетов в облачной консоли.
- Выполнение этой лабораторной работы должно обойтись менее чем в 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 \
firestore.googleapis.com \
run.googleapis.com \
artifactregistry.googleapis.com \
cloudbuild.googleapis.com
Если появится запрос на авторизацию, нажмите «Авторизовать» , чтобы продолжить. 
Выполнение этой команды может занять несколько минут, но в итоге должно отобразиться сообщение об успешном завершении, похожее на это:
Operation "operations/acf.p2-73d90d00-47ee-447a-b600" finished successfully.
6. Создайте базу данных Firestore.
- Выполните команду
gcloud firestore databases create, чтобы создать базу данных Firestore.gcloud firestore databases create --location=nam5
7. Подготовьте заявление.
Подготовьте приложение 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
- Установите
firebase-adminдля взаимодействия с базой данных Firestore.npm install firebase-admin
- Откройте файл
actions.tsв редакторе Cloud Shell: Теперь в верхней части экрана должен появиться пустой файл. Здесь вы можете редактировать файлcloudshell edit app/actions.tsactions.ts.
- Скопируйте следующий код и вставьте его в открытый файл
actions.ts:'use server' import { initializeApp, applicationDefault, getApps } from 'firebase-admin/app'; import { getFirestore } from 'firebase-admin/firestore'; const credential = applicationDefault(); // Only initialize app if it does not already exist if (getApps().length === 0) { initializeApp({ credential }); } const db = getFirestore(); const tasksRef = db.collection('tasks'); type Task = { id: string; title: string; status: 'IN_PROGRESS' | 'COMPLETE'; createdAt: number; }; // CREATE export async function addNewTaskToDatabase(newTask: string) { await tasksRef.doc().create({ title: newTask, status: 'IN_PROGRESS', createdAt: Date.now(), }); return; } // READ export async function getTasksFromDatabase() { const snapshot = await tasksRef.orderBy('createdAt', 'desc').limit(100).get(); const tasks = await snapshot.docs.map(doc => ({ id: doc.id, title: doc.data().title, status: doc.data().status, createdAt: doc.data().createdAt, })); return tasks; } // UPDATE export async function updateTaskInDatabase(task: Task) { await tasksRef.doc(task.id).set(task); return; } // DELETE export async function deleteTaskFromDatabase(taskId: string) { await tasksRef.doc(taskId).delete(); 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'; 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> ); }
Приложение готово к развертыванию.
8. Разверните приложение в Cloud Run.
- Выполните указанную ниже команду, чтобы развернуть приложение в Cloud Run:
gcloud run deploy helloworld \ --region=us-central1 \ --source=. - Если появится запрос, нажмите
YиEnter, чтобы подтвердить продолжение:Do you want to continue (Y/n)? Y
Через несколько минут приложение должно предоставить вам URL-адрес для перехода по ссылке.
Перейдите по указанному URL-адресу, чтобы увидеть приложение в действии. При каждом посещении URL-адреса или обновлении страницы вы будете видеть приложение для выполнения задач.
9. Поздравляем!
В этой лабораторной работе вы научились выполнять следующие действия:
- Создайте экземпляр Cloud SQL для PostgreSQL.
- Разверните приложение в Cloud Run, которое подключается к вашей базе данных Cloud SQL.
Уборка
В Cloud SQL нет бесплатного тарифа, и за дальнейшее использование взимается плата. Вы можете удалить свой проект в Cloud, чтобы избежать дополнительных расходов.
Хотя Cloud Run не взимает плату, когда услуга не используется, с вас все равно может взиматься плата за хранение образа контейнера в реестре артефактов. Удаление вашего проекта 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.
- Разверните полнофункциональное Angular-приложение в Cloud Run с помощью Cloud SQL для PostgreSQL, используя коннектор Cloud SQL Node.js.
- Разверните полнофункциональное Angular-приложение в Cloud Run с помощью Firestore, используя Node.js Admin SDK.
- Разверните полнофункциональное приложение Next.js в Cloud Run с Firestore, используя Node.js Admin SDK.