۱. مرور کلی
Cloud Run یک پلتفرم کاملاً مدیریتشده است که به شما امکان میدهد کد خود را مستقیماً روی زیرساخت مقیاسپذیر گوگل اجرا کنید. این Codelab نحوه اتصال یک برنامه Next.js در Cloud Run به یک پایگاه داده Cloud SQL برای PostgreSQL را نشان میدهد.
در این آزمایشگاه، شما یاد خواهید گرفت که چگونه:
- ایجاد یک Cloud SQL برای نمونه PostgreSQL
- یک برنامه را در Cloud Run مستقر کنید که به پایگاه داده Cloud SQL شما متصل شود
۲. پیشنیازها
- اگر از قبل حساب گوگل ندارید، باید یک حساب گوگل ایجاد کنید .
- به جای حساب کاری یا تحصیلی از یک حساب شخصی استفاده کنید. حسابهای کاری و تحصیلی ممکن است محدودیتهایی داشته باشند که مانع از فعال کردن APIهای مورد نیاز برای این آزمایشگاه توسط شما شود.
۳. راهاندازی پروژه
- وارد کنسول ابری گوگل شوید.
- فعال کردن پرداخت در کنسول ابری
- تکمیل این آزمایشگاه باید کمتر از ۱ دلار آمریکا از طریق منابع ابری هزینه داشته باشد.
- شما میتوانید مراحل انتهای این آزمایش را برای حذف منابع دنبال کنید تا از هزینههای بیشتر جلوگیری شود.
- کاربران جدید واجد شرایط استفاده از دوره آزمایشی رایگان ۳۰۰ دلاری هستند.
- یک پروژه جدید ایجاد کنید یا از یک پروژه موجود دوباره استفاده کنید.
۴. ویرایشگر 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اجرا کنید.
۵. فعال کردن 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.
۶. یک حساب کاربری سرویس راهاندازی کنید
یک حساب کاربری سرویس 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"
۷. ایجاد پایگاه داده ابری 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
۸. آمادهسازی درخواست
یک برنامه 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 - برای تعامل با پایگاه داده PostgreSQL،
pgرا نصب کنید.npm install pg - برای استفاده از برنامه TypeScript Next.js،
@types/pgرا به عنوان یک وابستگی توسعهدهنده نصب کنید.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> ); }
اکنون برنامه آمادهی استقرار است.
۹. برنامه را روی Cloud Run مستقر کنید
- دستور 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"
- دستور 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) بازدید میکنید یا صفحه را رفرش میکنید، برنامهی وظیفه (task app) را مشاهده خواهید کرد.
۱۰. با استفاده از Gemini Code Assist یک ویژگی اضافه کنید
حالا که یک برنامه وب با پایگاه داده ایجاد کردهاید، در مرحله بعد، با استفاده از قدرت هوش مصنوعی، یک ویژگی جدید به برنامه next.js خود اضافه خواهیم کرد.
- بازگشت به ویرایشگر Cloud Shell
- دوباره
page.tsxباز کنیدcd ~/task-app cloudshell edit app/page.tsx - به بخش Gemini Code Assist در ویرایشگر Cloud Shell بروید:
- روی آیکون جمینی کلیک کنید
در نوار ابزار سمت چپ صفحه - در صورت درخواست، با اطلاعات حساب گوگل خود وارد شوید
- اگر از شما خواسته شد پروژهای را انتخاب کنید، پروژهای را که برای این Codelab ایجاد کردهاید، انتخاب کنید.

- روی آیکون جمینی کلیک کنید
- اعلان را وارد کنید:
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> ); }
۱۱. برنامه را دوباره در 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
۱۲. تبریک
در این آزمایشگاه، شما یاد گرفتهاید که چگونه موارد زیر را انجام دهید:
- ایجاد یک 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
به یادگیری ادامه دهید
- با استفاده از رابط Node.js در Cloud SQL، یک برنامه کامل Next.js را روی Cloud Run با Cloud SQL برای PostgreSQL مستقر کنید.
- با استفاده از رابط Node.js در Cloud SQL، یک برنامه Angular فولاستک را روی Cloud Run با Cloud SQL برای PostgreSQL مستقر کنید.
- با استفاده از Node.js Admin SDK، یک برنامه Angular فول استک را روی Cloud Run با Firestore مستقر کنید.
- با استفاده از Node.js Admin SDK، یک برنامه کامل Next.js را با استفاده از Firestore روی Cloud Run مستقر کنید.