PostgreSQL এর জন্য ক্লাউড এসকিউএল সহ ক্লাউড রানে একটি সম্পূর্ণ স্ট্যাক জাভাস্ক্রিপ্ট অ্যাপ্লিকেশন স্থাপন করুন

1. সংক্ষিপ্ত বিবরণ

ক্লাউড রান একটি সম্পূর্ণরূপে পরিচালিত প্ল্যাটফর্ম যা আপনাকে গুগলের স্কেলেবল অবকাঠামোর উপরে সরাসরি আপনার কোড চালাতে সক্ষম করে। এই কোডল্যাবটি ক্লাউড রানে একটি Next.js অ্যাপ্লিকেশনকে PostgreSQL ডাটাবেসের জন্য একটি ক্লাউড SQL এর সাথে কীভাবে সংযুক্ত করতে হয় তা প্রদর্শন করবে।

এই ল্যাবে আপনি শিখবেন কিভাবে:

  • PostgreSQL ইনস্ট্যান্সের জন্য একটি ক্লাউড SQL তৈরি করুন
  • ক্লাউড রানে এমন একটি অ্যাপ্লিকেশন স্থাপন করুন যা আপনার ক্লাউড SQL ডাটাবেসের সাথে সংযুক্ত হবে।

2. পূর্বশর্ত

  1. যদি আপনার ইতিমধ্যেই একটি Google অ্যাকাউন্ট না থাকে, তাহলে আপনাকে অবশ্যই একটি Google অ্যাকাউন্ট তৈরি করতে হবে।
    • কর্মক্ষেত্র বা স্কুল অ্যাকাউন্টের পরিবর্তে ব্যক্তিগত অ্যাকাউন্ট ব্যবহার করুন। কর্মক্ষেত্র এবং স্কুল অ্যাকাউন্টগুলিতে এমন বিধিনিষেধ থাকতে পারে যা আপনাকে এই ল্যাবের জন্য প্রয়োজনীয় API গুলি সক্ষম করতে বাধা দেয়।

৩. প্রকল্প সেটআপ

  1. গুগল ক্লাউড কনসোলে সাইন-ইন করুন।
  2. ক্লাউড কনসোলে বিলিং সক্ষম করুন
    • এই ল্যাবটি সম্পূর্ণ করতে ক্লাউড রিসোর্সে $1 USD এর কম খরচ হবে।
    • আরও চার্জ এড়াতে আপনি এই ল্যাবের শেষে রিসোর্স মুছে ফেলার ধাপগুলি অনুসরণ করতে পারেন।
    • নতুন ব্যবহারকারীরা $300 USD বিনামূল্যে ট্রায়ালের জন্য যোগ্য।
  3. একটি নতুন প্রকল্প তৈরি করুন অথবা বিদ্যমান প্রকল্পটি পুনরায় ব্যবহার করতে বেছে নিন।

৪. ক্লাউড শেল এডিটর খুলুন

  1. ক্লাউড শেল এডিটরে নেভিগেট করুন
  2. যদি স্ক্রিনের নীচে টার্মিনালটি না দেখা যায়, তাহলে এটি খুলুন:
    • হ্যামবার্গার মেনুতে ক্লিক করুন হ্যামবার্গার মেনু আইকন
    • টার্মিনাল ক্লিক করুন
    • নতুন টার্মিনাল ক্লিক করুন ক্লাউড শেল এডিটরে নতুন টার্মিনাল খুলুন
  3. টার্মিনালে, এই কমান্ড দিয়ে আপনার প্রকল্পটি সেট করুন:
    • বিন্যাস:
      gcloud config set project [PROJECT_ID]
      
    • উদাহরণ:
      gcloud config set project lab-project-id-example
      
    • যদি আপনি আপনার প্রকল্প আইডি মনে করতে না পারেন:
      • আপনি আপনার সমস্ত প্রকল্প আইডি তালিকাভুক্ত করতে পারেন:
        gcloud projects list | awk '/PROJECT_ID/{print $2}'
        
      ক্লাউড শেল এডিটর টার্মিনালে প্রোজেক্ট আইডি সেট করুন
  4. অনুমোদনের জন্য অনুরোধ করা হলে, চালিয়ে যেতে অনুমোদনে ক্লিক করুন। ক্লাউড শেল অনুমোদন করতে ক্লিক করুন
  5. আপনার এই বার্তাটি দেখা উচিত:
    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.

৬. একটি পরিষেবা অ্যাকাউন্ট সেট আপ করুন

ক্লাউড রান দ্বারা ব্যবহারের জন্য একটি গুগল ক্লাউড পরিষেবা অ্যাকাউন্ট তৈরি এবং কনফিগার করুন যাতে এটি ক্লাউড এসকিউএল এর সাথে সংযোগ করার জন্য সঠিক অনুমতি পায়।

  1. একটি নতুন পরিষেবা অ্যাকাউন্ট তৈরি করতে gcloud iam service-accounts create কমান্ডটি নিম্নরূপ চালান:
    gcloud iam service-accounts create quickstart-service-account \
      --display-name="Quickstart Service Account"
    
  2. আপনার তৈরি করা গুগল ক্লাউড সার্ভিস অ্যাকাউন্টে লগ রাইটার ভূমিকা যোগ করতে gcloud projects add-iam-policy-binding কমান্ডটি নিম্নরূপে চালান।
    gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
      --member="serviceAccount:quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
      --role="roles/logging.logWriter"
    

৭. ক্লাউড এসকিউএল ডাটাবেস তৈরি করুন

  1. প্রাইভেট সার্ভিস কানেক্টের মাধ্যমে ক্লাউড থেকে ক্লাউড SQL-এ নেটওয়ার্ক সংযোগের অনুমতি দেওয়ার জন্য একটি পরিষেবা সংযোগ নীতি তৈরি করুন।
    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
    
  2. আপনার ডাটাবেসের জন্য একটি অনন্য পাসওয়ার্ড তৈরি করুন
    export DB_PASSWORD=$(openssl rand -base64 20)
    
  3. ক্লাউড এসকিউএল ইনস্ট্যান্স তৈরি করতে gcloud sql instances create কমান্ডটি চালান।
    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
    

এই কমান্ডটি সম্পন্ন হতে কয়েক মিনিট সময় লাগতে পারে।

  1. quickstart-instance এর মধ্যে একটি ক্লাউড SQL ডাটাবেস তৈরি করতে gcloud sql databases create কমান্ডটি চালান।
    gcloud sql databases create quickstart_db \
      --instance=quickstart-instance
    

৮. আবেদনপত্র প্রস্তুত করুন

HTTP অনুরোধের জবাব দেয় এমন একটি Next.js অ্যাপ্লিকেশন প্রস্তুত করুন।

  1. task-app নামে একটি নতুন Next.js প্রকল্প তৈরি করতে, কমান্ডটি ব্যবহার করুন:
    npx --yes create-next-app@15 task-app \
      --ts \
      --eslint \
      --tailwind \
      --no-src-dir \
      --turbopack \
      --app \
      --no-import-alias
    
  2. ডিরেক্টরিটি task-app পরিবর্তন করুন:
    cd task-app
    
  3. PostgreSQL ডাটাবেসের সাথে ইন্টারঅ্যাক্ট করতে pg ইনস্টল করুন।
    npm install pg
    
  4. TypeScript Next.js অ্যাপ্লিকেশন ব্যবহার করার জন্য @types/pg ডেভ নির্ভরতা হিসেবে ইনস্টল করুন।
    npm install --save-dev @types/pg
    
  5. ক্লাউড শেল এডিটরে actions.ts ফাইলটি খুলুন:
    cloudshell edit app/actions.ts
    
    এখন স্ক্রিনের উপরের অংশে একটি খালি ফাইল দেখা যাবে। এখানেই আপনি এই actions.ts ফাইলটি সম্পাদনা করতে পারবেন। দেখান যে কোডটি স্ক্রিনের উপরের অংশে যায়।
  6. নিচের কোডটি কপি করে খোলা 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;
    }
    
  7. ক্লাউড শেল এডিটরে page.tsx ফাইলটি খুলুন:
    cloudshell edit app/page.tsx
    
    এখন স্ক্রিনের উপরের অংশে একটি বিদ্যমান ফাইল প্রদর্শিত হবে। এখানেই আপনি এই page.tsx ফাইলটি সম্পাদনা করতে পারবেন। দেখান যে কোডটি স্ক্রিনের উপরের অংশে যায়।
  8. page.tsx ফাইলের বিদ্যমান বিষয়বস্তু মুছে ফেলুন।
  9. নিচের কোডটি কপি করে খোলা 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>
      );
    }
    

অ্যাপ্লিকেশনটি এখন স্থাপনের জন্য প্রস্তুত।

৯. অ্যাপ্লিকেশনটি ক্লাউড রানে স্থাপন করুন

  1. আপনি যে ক্লাউড রান পরিষেবা তৈরি করতে চলেছেন তার জন্য ক্লাউড রান পরিষেবা অ্যাকাউন্টে নেটওয়ার্ক ব্যবহারকারীর ভূমিকা যোগ করতে gcloud projects add-iam-policy-binding কমান্ডটি নিম্নরূপ চালান।
    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"
    
  1. আপনি যে ক্লাউড রান পরিষেবাটি তৈরি করতে চলেছেন তার বর্তমান ব্যবহারকারীর সাথে আর্টিফ্যাক্ট রেজিস্ট্রি রাইটার ভূমিকা যোগ করতে gcloud projects add-iam-policy-binding কমান্ডটি নিম্নরূপ চালান।
    gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
        --member=user:$(gcloud auth list --filter=status:ACTIVE --format="value(account)") \
        --role="roles/artifactregistry.writer"
    
  1. ক্লাউড রানে আপনার অ্যাপ্লিকেশন স্থাপন করতে নীচের কমান্ডটি চালান:
    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
    
  2. যদি অনুরোধ করা হয়, তাহলে আপনি যে চালিয়ে যেতে চান তা নিশ্চিত করতে Y এবং Enter টিপুন:
    Do you want to continue (Y/n)? Y
    

কয়েক মিনিট পরে, অ্যাপ্লিকেশনটি আপনার দেখার জন্য একটি URL প্রদান করবে।

আপনার অ্যাপ্লিকেশনটি কীভাবে কাজ করছে তা দেখতে URL-এ যান। প্রতিবার URL-এ গেলে বা পৃষ্ঠাটি রিফ্রেশ করলে, আপনি টাস্ক অ্যাপটি দেখতে পাবেন।

১০. জেমিনি কোড অ্যাসিস্টের সাথে একটি বৈশিষ্ট্য যুক্ত করুন

এখন আপনি একটি ডাটাবেস সহ একটি ওয়েব অ্যাপ স্থাপন করেছেন। এরপর, আমরা AI সহায়তার শক্তি ব্যবহার করে আমাদের next.js অ্যাপে একটি নতুন বৈশিষ্ট্য যুক্ত করতে যাচ্ছি।

  1. ক্লাউড শেল এডিটরে ফিরে যান
  2. আবার page.tsx খুলুন।
    cd ~/task-app
    cloudshell edit app/page.tsx
    
  3. ক্লাউড শেল এডিটরের মধ্যে জেমিনি কোড অ্যাসিস্টে নেভিগেট করুন:
    • মিথুন আইকনে ক্লিক করুন জেমিনি কোড অ্যাসিস্ট আইকন স্ক্রিনের বাম দিকের টুলবারে
    • যদি অনুরোধ করা হয়, আপনার Google অ্যাকাউন্টের শংসাপত্র দিয়ে সাইন ইন করুন।
    • যদি কোনও প্রকল্প নির্বাচন করতে বলা হয়, তাহলে এই কোডল্যাবের জন্য আপনার তৈরি করা প্রকল্পটি নির্বাচন করুন। জেমিনি কোড অ্যাসিস্টের জন্য প্রকল্প নির্বাচন করুন
  4. প্রম্পটটি প্রবেশ করান: 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);
    };
    
  5. 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>
      );
    }
    

১১. অ্যাপ্লিকেশনটি ক্লাউড রানে পুনরায় স্থাপন করুন

  1. ক্লাউড রানে আপনার অ্যাপ্লিকেশন স্থাপন করতে নীচের কমান্ডটি চালান:
    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
    
  2. যদি অনুরোধ করা হয়, তাহলে আপনি যে চালিয়ে যেতে চান তা নিশ্চিত করতে Y এবং Enter টিপুন:
    Do you want to continue (Y/n)? Y
    

১২. অভিনন্দন

এই ল্যাবে, আপনি নিম্নলিখিত কাজগুলি শিখেছেন:

  • PostgreSQL ইনস্ট্যান্সের জন্য একটি ক্লাউড SQL তৈরি করুন
  • ক্লাউড রানে এমন একটি অ্যাপ্লিকেশন স্থাপন করুন যা আপনার ক্লাউড SQL ডাটাবেসের সাথে সংযুক্ত হবে।

পরিষ্কার করা

ক্লাউড এসকিউএল-এর কোনও ফ্রি টিয়ার নেই এবং আপনি যদি এটি ব্যবহার চালিয়ে যান তবে আপনাকে চার্জ করা হবে। অতিরিক্ত চার্জ এড়াতে আপনি আপনার ক্লাউড প্রকল্পটি মুছে ফেলতে পারেন।

পরিষেবাটি ব্যবহার না করা অবস্থায় ক্লাউড রান চার্জ করে না, তবুও আর্টিফ্যাক্ট রেজিস্ট্রিতে কন্টেইনার চিত্র সংরক্ষণের জন্য আপনাকে চার্জ করা হতে পারে। আপনার ক্লাউড প্রকল্পটি মুছে ফেলার ফলে সেই প্রকল্পের মধ্যে ব্যবহৃত সমস্ত সংস্থানের জন্য বিলিং বন্ধ হয়ে যায়।

আপনি যদি চান, প্রকল্পটি মুছে ফেলুন:

gcloud projects delete $GOOGLE_CLOUD_PROJECT

আপনি আপনার ক্লাউডশেল ডিস্ক থেকে অপ্রয়োজনীয় রিসোর্স মুছে ফেলতেও চাইতে পারেন। আপনি করতে পারেন:

  1. কোডল্যাব প্রজেক্ট ডিরেক্টরিটি মুছে ফেলুন:
    rm -rf ~/task-app
    
  2. সতর্কতা! পরবর্তী পদক্ষেপটি পূর্বাবস্থায় ফেরানো যাবে না! যদি আপনি আপনার ক্লাউড শেলের সবকিছু মুছে ফেলতে চান যাতে জায়গা খালি হয়, তাহলে আপনি আপনার সম্পূর্ণ হোম ডিরেক্টরি মুছে ফেলতে পারেন। আপনি যা রাখতে চান তা যেন অন্য কোথাও সংরক্ষিত থাকে সেদিকে খেয়াল রাখুন।
    sudo rm -rf $HOME
    

শিখতে থাকো