1. Panoramica
Cloud Run è una piattaforma completamente gestita che consente di eseguire il codice direttamente sull'infrastruttura scalabile di Google. Questo Codelab mostrerà come connettere un'applicazione Next.js su Cloud Run a un database Cloud SQL per PostgreSQL.
In questo lab, imparerai a:
- Crea un'istanza Cloud SQL per PostgreSQL
- Esegui il deployment di un'applicazione su Cloud Run che si connette al tuo database Cloud SQL
2. Prerequisiti
- Se non hai ancora un Account Google, devi crearne uno.
- Utilizza un account personale anziché un account di lavoro o della scuola. Gli account di lavoro e della scuola potrebbero avere limitazioni che impediscono l'attivazione delle API necessarie per questo lab.
3. Configurazione del progetto
- Accedi alla console Google Cloud.
- Abilita la fatturazione in Cloud Console.
- Il completamento di questo lab dovrebbe costare meno di 1 $in risorse cloud.
- Per evitare ulteriori addebiti, puoi seguire i passaggi alla fine di questo lab per eliminare le risorse.
- I nuovi utenti hanno diritto alla prova senza costi di 300$.
- Crea un nuovo progetto o scegli di riutilizzarne uno esistente.
4. Apri editor di Cloud Shell
- Vai all'editor di Cloud Shell.
- Se il terminale non viene visualizzato nella parte inferiore dello schermo, aprilo:
- Fai clic sul menu a tre linee
. - Fai clic su Terminale.
- Fai clic su Nuovo terminale
.
- Fai clic sul menu a tre linee
- Nel terminale, imposta il tuo progetto con questo comando:
- Formato:
gcloud config set project [PROJECT_ID] - Esempio:
gcloud config set project lab-project-id-example - Se non ricordi l'ID progetto:
- Puoi elencare tutti gli ID progetto con:
gcloud projects list | awk '/PROJECT_ID/{print $2}'

- Puoi elencare tutti gli ID progetto con:
- Formato:
- Se ti viene richiesto di concedere l'autorizzazione, fai clic su Autorizza per continuare.

- Dovresti vedere questo messaggio:
Se visualizzi unUpdated property [core/project].
WARNINGe ti viene chiestoDo you want to continue (Y/N)?, probabilmente hai inserito l'ID progetto in modo errato. PremiN, premiEntere prova a eseguire di nuovo il comandogcloud config set project.
5. Abilita API
Nel terminale, abilita le 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
Se ti viene richiesto di concedere l'autorizzazione, fai clic su Autorizza per continuare. 
Il completamento di questo comando potrebbe richiedere alcuni minuti, ma alla fine dovrebbe essere visualizzato un messaggio di operazione riuscita simile a questo:
Operation "operations/acf.p2-73d90d00-47ee-447a-b600" finished successfully.
6. Configurare un service account
Crea e configura un service account Google Cloud da utilizzare con Cloud Run in modo che disponga delle autorizzazioni corrette per connettersi a Cloud SQL.
- Esegui il comando
gcloud iam service-accounts createcome segue per creare un nuovo service account:gcloud iam service-accounts create quickstart-service-account \ --display-name="Quickstart Service Account" - Esegui il comando gcloud projects add-iam-policy-binding come segue per aggiungere il ruolo Scrittore log al service account Google Cloud appena creato.
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. Crea il database Cloud SQL
- Crea un criterio di connessione del servizio per consentire la connettività di rete da Cloud Run a Cloud SQL con 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 - Genera una password univoca per il tuo database
export DB_PASSWORD=$(openssl rand -base64 20) - Esegui il comando
gcloud sql instances createper creare un'istanza Cloud SQLgcloud 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
Il completamento di questo comando potrebbe richiedere alcuni minuti.
- Esegui il comando
gcloud sql databases createper creare un database Cloud SQL all'interno diquickstart-instance.gcloud sql databases create quickstart_db \ --instance=quickstart-instance
8. Prepara applicazione
Prepara un'applicazione Next.js che risponda alle richieste HTTP.
- Per creare un nuovo progetto Next.js denominato
task-app, utilizza il comando:npx --yes create-next-app@15 task-app \ --ts \ --eslint \ --tailwind \ --no-src-dir \ --turbopack \ --app \ --no-import-alias - Passa alla directory
task-app:cd task-app - Installa
pgper interagire con il database PostgreSQL.npm install pg - Installa
@types/pgcome dipendenza di sviluppo per utilizzare l'applicazione TypeScript Next.js.npm install --save-dev @types/pg - Apri il file
actions.tsnell'editor di Cloud Shell: Ora nella parte superiore dello schermo dovrebbe essere visualizzato un file vuoto. Qui puoi modificare questo filecloudshell edit app/actions.tsactions.ts.
- Copia il seguente codice e incollalo nel file
actions.tsaperto:'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; } - Apri il file
page.tsxnell'editor di Cloud Shell: Ora nella parte superiore dello schermo dovrebbe essere visualizzato un file esistente. Qui puoi modificare questo filecloudshell edit app/page.tsxpage.tsx.
- Elimina i contenuti esistenti del file
page.tsx. - Copia il seguente codice e incollalo nel file
page.tsxaperto:'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> ); }
L'applicazione è ora pronta per il deployment.
9. Esegui il deployment dell'applicazione in Cloud Run
- Esegui il comando gcloud projects add-iam-policy-binding come segue per aggiungere il ruolo Utente di rete al service account Cloud Run per il servizio Cloud Run che stai per creare.
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"
- Esegui il comando gcloud projects add-iam-policy-binding nel modo seguente per aggiungere il ruolo Scrittore Artifact Registry all'utente corrente per il servizio Cloud Run che stai per creare.
gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \ --member=user:$(gcloud auth list --filter=status:ACTIVE --format="value(account)") \ --role="roles/artifactregistry.writer"
- Esegui questo comando per eseguire il deployment dell'applicazione su 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 - Se richiesto, premi
YeEnterper confermare che vuoi continuare:Do you want to continue (Y/n)? Y
Dopo qualche minuto, l'applicazione dovrebbe fornire un URL da visitare.
Vai all'URL per vedere la tua applicazione in azione. Ogni volta che visiti l'URL o aggiorni la pagina, vedrai l'app Attività.
10. Aggiungere una funzionalità con Gemini Code Assist
Ora hai eseguito il deployment di un'app web con un database. Successivamente, aggiungeremo una nuova funzionalità alla nostra app Next.js utilizzando la potenza dell'assistenza AI.
- Tornare all'editor di Cloud Shell
- Apri di nuovo
page.tsxcd ~/task-app cloudshell edit app/page.tsx - Vai a Gemini Code Assist nell'editor di Cloud Shell:
- Fai clic sull'icona di Gemini
nella barra degli strumenti sul lato sinistro dello schermo. - Se richiesto, accedi con le credenziali del tuo Account Google.
- Se ti viene chiesto di selezionare un progetto, seleziona quello che hai creato per questo Codelab

- Fai clic sull'icona di Gemini
- Inserisci il prompt:
Add the ability to update the title of the task. The code in your output should be complete and working code.. La risposta dovrebbe includere qualcosa di simile a questi snippet per aggiungere le funzionihandleEditStartehandleEditCancel:const [editingTaskId, setEditingTaskId] = useState(''); const [editedTaskTitle, setEditedTaskTitle] = useState(''); function handleEditStart(task: Task) { setEditingTaskId(task.id); setEditedTaskTitle(task.title); }; - Sostituisci
page.tsxcon l'output di Gemini Code Assist. Ecco un esempio funzionante:'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. Esegui di nuovo il deployment dell'applicazione in Cloud Run
- Esegui questo comando per eseguire il deployment dell'applicazione su 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 - Se richiesto, premi
YeEnterper confermare che vuoi continuare:Do you want to continue (Y/n)? Y
12. Complimenti
In questo lab hai imparato a:
- Crea un'istanza Cloud SQL per PostgreSQL
- Esegui il deployment di un'applicazione su Cloud Run che si connette al tuo database Cloud SQL
Esegui la pulizia
Cloud SQL non ha un livello senza costi e ti addebiterà dei costi se continui a utilizzarlo. Puoi eliminare il tuo progetto Cloud per evitare addebiti aggiuntivi.
Sebbene non siano previsti addebiti per Cloud Run quando il servizio non è in uso, ti potrebbero comunque essere addebitati i costi di archiviazione dell'immagine container in Artifact Registry. L'eliminazione del progetto Cloud interrompe la fatturazione per tutte le risorse utilizzate al suo interno.
Se vuoi, elimina il progetto:
gcloud projects delete $GOOGLE_CLOUD_PROJECT
Potresti anche voler eliminare le risorse non necessarie dal disco Cloud Shell. Puoi:
- Elimina la directory del progetto codelab:
rm -rf ~/task-app - Attenzione. La prossima azione non può essere annullata. Se vuoi eliminare tutti i contenuti di Cloud Shell per liberare spazio, puoi eliminare l'intera home directory. Fai attenzione che tutto ciò che vuoi conservare sia salvato altrove.
sudo rm -rf $HOME
Continua a imparare
- Esegui il deployment di un'applicazione Next.js full-stack su Cloud Run con Cloud SQL per PostgreSQL utilizzando il connettore Node.js Cloud SQL
- Esegui il deployment di un'applicazione Angular full-stack su Cloud Run con Cloud SQL per PostgreSQL utilizzando il connettore Node.js Cloud SQL
- Esegui il deployment di un'applicazione Angular full-stack su Cloud Run con Firestore utilizzando l'SDK Node.js Admin
- Esegui il deployment di un'applicazione Next.js full-stack su Cloud Run con Firestore utilizzando l'SDK Node.js Admin