ক্লাউড বিল্ড ব্যবহার করে কীভাবে গিটহাব থেকে ক্লাউড রানে আপনার পরিবর্তনগুলি স্বয়ংক্রিয়ভাবে স্থাপন করবেন

১. ভূমিকা

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

এই কোডল্যাবে, আপনি ক্লাউড রানকে এমনভাবে কনফিগার করবেন যাতে যখনই আপনি আপনার সোর্স কোডের পরিবর্তনগুলো একটি গিটহাব রিপোজিটরিতে পুশ করবেন, তখনই এটি স্বয়ংক্রিয়ভাবে আপনার অ্যাপ্লিকেশনের নতুন সংস্করণগুলো বিল্ড এবং ডিপ্লয় করে

এই ডেমো অ্যাপ্লিকেশনটি ব্যবহারকারীর ডেটা ফায়ারস্টোরে সংরক্ষণ করে, তবে ডেটার কেবল আংশিক অংশই সঠিকভাবে সংরক্ষিত হয়। আপনাকে কন্টিনিউয়াস ডেপ্লয়মেন্ট এমনভাবে কনফিগার করতে হবে, যাতে আপনি যখন আপনার গিটহাব রিপোজিটরিতে কোনো বাগ ফিক্স পুশ করবেন, তখন ফিক্সটি স্বয়ংক্রিয়ভাবে একটি নতুন রিভিশনে উপলব্ধ হয়ে যাবে।

আপনি যা শিখবেন

  • ক্লাউড শেল এডিটর ব্যবহার করে একটি এক্সপ্রেস ওয়েব অ্যাপ্লিকেশন লিখুন।
  • নিরবচ্ছিন্ন ডেপ্লয়মেন্টের জন্য আপনার গিটহাব অ্যাকাউন্ট গুগল ক্লাউডের সাথে সংযুক্ত করুন।
  • আপনার অ্যাপ্লিকেশনটি স্বয়ংক্রিয়ভাবে ক্লাউড রান-এ ডেপ্লয় করুন।
  • HTMLX এবং TailwindCSS কীভাবে ব্যবহার করতে হয় তা শিখুন।

২. সেটআপ এবং প্রয়োজনীয়তা

পূর্বশর্ত

  • আপনার একটি গিটহাব অ্যাকাউন্ট আছে এবং আপনি রিপোজিটরি তৈরি ও তাতে কোড পুশ করার বিষয়ে পরিচিত।
  • আপনি ক্লাউড কনসোলে লগ ইন করেছেন।
  • আপনি পূর্বে একটি ক্লাউড রান সার্ভিস ডেপ্লয় করেছেন। উদাহরণস্বরূপ, কাজ শুরু করার জন্য আপনি ‘ ডিপ্লয় এ ওয়েব সার্ভিস ফ্রম সোর্স কোড’ কুইকস্টার্টটি অনুসরণ করতে পারেন।

ক্লাউড শেল সক্রিয় করুন

  1. ক্লাউড কনসোল থেকে, অ্যাক্টিভেট ক্লাউড শেল-এ ক্লিক করুন। d1264ca30785e435.png .

cb81e7c8e34bc8d.png

আপনি যদি প্রথমবারের মতো ক্লাউড শেল চালু করেন, তাহলে এটি কী তা বর্ণনা করে একটি মধ্যবর্তী স্ক্রিন আপনার সামনে আসবে। যদি একটি মধ্যবর্তী স্ক্রিন আসে, তাহলে 'চালিয়ে যান' (Continue) এ ক্লিক করুন।

d95252b003979716.png

ক্লাউড শেল প্রস্তুত করতে এবং এর সাথে সংযোগ স্থাপন করতে মাত্র কয়েক মুহূর্ত সময় লাগা উচিত।

7833d5e1c5d18f54.png

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

ক্লাউড শেলে সংযুক্ত হওয়ার পর, আপনি দেখতে পাবেন যে আপনাকে প্রমাণীকৃত করা হয়েছে এবং প্রজেক্টটি আপনার প্রজেক্ট আইডিতে সেট করা আছে।

  1. আপনি প্রমাণীকৃত কিনা তা নিশ্চিত করতে ক্লাউড শেলে নিম্নলিখিত কমান্ডটি চালান:
gcloud auth list

কমান্ড আউটপুট

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. gcloud কমান্ডটি আপনার প্রজেক্ট সম্পর্কে জানে কিনা তা নিশ্চিত করতে ক্লাউড শেলে নিম্নলিখিত কমান্ডটি চালান:
gcloud config list project

কমান্ড আউটপুট

[core]
project = <PROJECT_ID>

যদি তা না থাকে, তবে আপনি এই কমান্ডটি দিয়ে এটি সেট করতে পারেন:

gcloud config set project <PROJECT_ID>

কমান্ড আউটপুট

Updated property [core/project].

৩. এপিআই সক্রিয় করুন এবং এনভায়রনমেন্ট ভেরিয়েবল সেট করুন

এপিআই সক্ষম করুন

এই কোডল্যাবটির জন্য নিম্নলিখিত API-গুলো ব্যবহার করা প্রয়োজন। আপনি নিম্নলিখিত কমান্ডটি চালিয়ে সেই API-গুলো সক্রিয় করতে পারেন:

gcloud services enable run.googleapis.com \
    cloudbuild.googleapis.com \
    firestore.googleapis.com \
    iamcredentials.googleapis.com

পরিবেশ ভেরিয়েবল সেটআপ করুন

আপনি এনভায়রনমেন্ট ভেরিয়েবল সেট করতে পারেন, যা এই কোডল্যাব জুড়ে ব্যবহৃত হবে।

REGION=<YOUR-REGION>
PROJECT_ID=<YOUR-PROJECT-ID>
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
SERVICE_ACCOUNT="firestore-accessor"
SERVICE_ACCOUNT_ADDRESS=$SERVICE_ACCOUNT@$PROJECT_ID.iam.gserviceaccount.com

৪. একটি পরিষেবা অ্যাকাউন্ট তৈরি করুন

এই সার্ভিস অ্যাকাউন্টটি ক্লাউড রান দ্বারা ভার্টেক্স এআই জেমিনি এপিআই কল করার জন্য ব্যবহৃত হবে। এই সার্ভিস অ্যাকাউন্টটির ফায়ারস্টোরে পড়া ও লেখার এবং সিক্রেট ম্যানেজার থেকে গোপনীয় তথ্য পড়ার অনুমতিও থাকবে।

প্রথমে, এই কমান্ডটি চালিয়ে সার্ভিস অ্যাকাউন্টটি তৈরি করুন:

gcloud iam service-accounts create $SERVICE_ACCOUNT \
  --display-name="Cloud Run access to Firestore"

এখন, সার্ভিস অ্যাকাউন্টটিকে ফায়ারস্টোরে পঠন ও লিখন অ্যাক্সেস দিন।

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
  --role=roles/datastore.user

৫. একটি ফায়ারবেস প্রজেক্ট তৈরি এবং কনফিগার করুন

  1. Firebase কনসোলে , 'Add project'- এ ক্লিক করুন।
  2. আপনার বিদ্যমান গুগল ক্লাউড প্রজেক্টগুলোর কোনো একটিতে ফায়ারবেস যোগ করতে <আপনার_প্রজেক্ট_আইডি> লিখুন।
  3. অনুরোধ করা হলে, Firebase-এর শর্তাবলী পর্যালোচনা করুন এবং মেনে নিন।
  4. চালিয়ে যান-এ ক্লিক করুন।
  5. Firebase বিলিং প্ল্যানটি নিশ্চিত করতে ‘Confirm Plan’-এ ক্লিক করুন।
  6. এই কোডল্যাবের জন্য গুগল অ্যানালিটিক্স চালু করা ঐচ্ছিক।
  7. ফায়ারবেস যোগ করুন -এ ক্লিক করুন।
  8. প্রজেক্টটি তৈরি হয়ে গেলে, 'চালিয়ে যান'-এ ক্লিক করুন।
  9. Build মেনু থেকে Firestore database-এ ক্লিক করুন।
  10. ডাটাবেস তৈরি করুন -এ ক্লিক করুন।
  11. লোকেশন ড্রপ-ডাউন থেকে আপনার অঞ্চল নির্বাচন করুন, তারপর নেক্সট-এ ক্লিক করুন।
  12. ডিফল্টভাবে প্রোডাকশন মোডে স্টার্ট করুন , তারপর ক্রিয়েট-এ ক্লিক করুন।

৬. আবেদনপত্রটি লিখুন।

প্রথমে, সোর্স কোডের জন্য একটি ডিরেক্টরি তৈরি করুন এবং সেই ডিরেক্টরিতে প্রবেশ করুন।

mkdir cloud-run-github-cd-demo && cd $_

এরপর, নিম্নলিখিত বিষয়বস্তু সহ একটি package.json ফাইল তৈরি করুন:

{
  "name": "cloud-run-github-cd-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node app.js",
    "nodemon": "nodemon app.js",
    "tailwind-dev": "npx tailwindcss -i ./input.css -o ./public/output.css --watch",
    "tailwind": "npx tailwindcss -i ./input.css -o ./public/output.css",
    "dev": "npm run tailwind && npm run nodemon"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@google-cloud/firestore": "^7.3.1",
    "axios": "^1.6.7",
    "express": "^4.18.2",
    "htmx.org": "^1.9.10"
  },
  "devDependencies": {
    "nodemon": "^3.1.0",
    "tailwindcss": "^3.4.1"
  }
}

প্রথমে, নিচের বিষয়বস্তু দিয়ে একটি app.js সোর্স ফাইল তৈরি করুন। এই ফাইলে সার্ভিসের এন্ট্রি পয়েন্ট এবং অ্যাপের মূল লজিক থাকবে।

const express = require("express");
const app = express();
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
const path = require("path");
const { get } = require("axios");

const { Firestore } = require("@google-cloud/firestore");
const firestoreDb = new Firestore();

const fs = require("fs");
const util = require("util");
const { spinnerSvg } = require("./spinnerSvg.js");

const service = process.env.K_SERVICE;
const revision = process.env.K_REVISION;

app.use(express.static("public"));

app.get("/edit", async (req, res) => {
    res.send(`<form hx-post="/update" hx-target="this" hx-swap="outerHTML">
                <div>
  <p>
    <label>Name</label>    
    <input class="border-2" type="text" name="name" value="Cloud">
    </p><p>
    <label>Town</label>    
    <input class="border-2" type="text" name="town" value="Nibelheim">
    </p>
  </div>
  <div class="flex items-center mr-[10px] mt-[10px]">
  <button class="btn bg-blue-500 text-white px-4 py-2 rounded-lg text-center text-sm font-medium mr-[10px]">Submit</button>
  <button class="btn bg-gray-200 text-gray-800 px-4 py-2 rounded-lg text-center text-sm font-medium mr-[10px]" hx-get="cancel">Cancel</button>  
                ${spinnerSvg} 
                </div>
  </form>`);
});

app.post("/update", async function (req, res) {
    let name = req.body.name;
    let town = req.body.town;
    const doc = firestoreDb.doc(`demo/${name}`);

    //TODO: fix this bug
    await doc.set({
        name: name
        /* town: town */
    });

    res.send(`<div hx-target="this" hx-swap="outerHTML" hx-indicator="spinner">
                <p>
                <div><label>Name</label>: ${name}</div>
                </p><p>
                <div><label>Town</label>: ${town}</div>
                </p>
                <button
                    hx-get="/edit"
                    class="bg-blue-500 text-white px-4 py-2 rounded-lg text-sm font-medium mt-[10px]"
                >
                    Click to update
                </button>               
            </div>`);
});

app.get("/cancel", (req, res) => {
    res.send(`<div hx-target="this" hx-swap="outerHTML">
                <p>
                <div><label>Name</label>: Cloud</div>
                </p><p>
                <div><label>Town</label>: Nibelheim</div>
                </p>
                <div>
                <button
                    hx-get="/edit"
                    class="bg-blue-500 text-white px-4 py-2 rounded-lg text-sm font-medium mt-[10px]"
                >
                    Click to update
                </button>                
                </div>
            </div>`);
});

const port = parseInt(process.env.PORT) || 8080;
app.listen(port, async () => {
    console.log(`booth demo: listening on port ${port}`);

    //serviceMetadata = helper();
});

app.get("/helper", async (req, res) => {
    let region = "";
    let projectId = "";
    let div = "";

    try {
        // Fetch the token to make a GCF to GCF call
        const response1 = await get(
            "http://metadata.google.internal/computeMetadata/v1/project/project-id",
            {
                headers: {
                    "Metadata-Flavor": "Google"
                }
            }
        );

        // Fetch the token to make a GCF to GCF call
        const response2 = await get(
            "http://metadata.google.internal/computeMetadata/v1/instance/region",
            {
                headers: {
                    "Metadata-Flavor": "Google"
                }
            }
        );

        projectId = response1.data;
        let regionFull = response2.data;
        const index = regionFull.lastIndexOf("/");
        region = regionFull.substring(index + 1);

        div = `
        <div>
        This created the revision <code>${revision}</code> of the 
        Cloud Run service <code>${service}</code> in <code>${region}</code>
        for project <code>${projectId}</code>.
        </div>`;
    } catch (ex) {
        // running locally
        div = `<div> This is running locally.</div>`;
    }

    res.send(div);
});

spinnerSvg.js নামে একটি ফাইল তৈরি করুন।

module.exports.spinnerSvg = `<svg id="spinner" alt="Loading..."
                    class="htmx-indicator animate-spin -ml-1 mr-3 h-5 w-5 text-blue-500"
                    xmlns="http://www.w3.org/2000/svg"
                    fill="none"
                    viewBox="0 0 24 24"
                >
                    <circle
                        class="opacity-25"
                        cx="12"
                        cy="12"
                        r="10"
                        stroke="currentColor"
                        stroke-width="4"
                    ></circle>
                    <path
                        class="opacity-75"
                        fill="currentColor"
                        d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
                    ></path>
                </svg>`;

tailwindCSS-এর জন্য একটি input.css ফাইল তৈরি করুন।

@tailwind base;
@tailwind components;
@tailwind utilities;

এবং tailwindCSS-এর জন্য tailwind.config.js ফাইলটি তৈরি করুন।

/** @type {import('tailwindcss').Config} */
module.exports = {
    content: ["./**/*.{html,js}"],
    theme: {
        extend: {}
    },
    plugins: []
};

এবং একটি .gitignore ফাইল তৈরি করুন।

node_modules/

npm-debug.log
coverage/

package-lock.json

.DS_Store

এখন, একটি নতুন public ডিরেক্টরি তৈরি করুন।

mkdir public
cd public

এবং সেই পাবলিক ডিরেক্টরির ভেতরে ফ্রন্ট এন্ডের জন্য index.html ফাইলটি তৈরি করুন, যেটি htmx ব্যবহার করবে।

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta
            name="viewport"
            content="width=device-width, initial-scale=1.0"
        />
        <script
            src="https://unpkg.com/htmx.org@1.9.10"
            integrity="sha384-D1Kt99CQMDuVetoL1lrYwg5t+9QdHe7NLX/SoJYkXDFfX37iInKRy5xLSi8nO7UC"
            crossorigin="anonymous"
        ></script>

        <link href="./output.css" rel="stylesheet" />
        <title>Demo 1</title>
    </head>
    <body
        class="font-sans bg-body-image bg-cover bg-center leading-relaxed"
    >
        <div class="container max-w-[700px] mt-[50px] ml-auto mr-auto">
            <div class="hero flex items-center">                    
                <div class="message text-base text-center mb-[24px]">
                    <h1 class="text-2xl font-bold mb-[10px]">
                        It's running!
                    </h1>
                    <div class="congrats text-base font-normal">
                        Congratulations, you successfully deployed your
                        service to Cloud Run. 
                    </div>
                </div>
            </div>

            <div class="details mb-[20px]">
                <p>
                    <div hx-trigger="load" hx-get="/helper" hx-swap="innerHTML" hx-target="this">Hello</div>                   
                </p>
            </div>

            <p
                class="callout text-sm text-blue-700 font-bold pt-4 pr-6 pb-4 pl-10 leading-tight"
            >
                You can deploy any container to Cloud Run that listens for
                HTTP requests on the port defined by the
                <code>PORT</code> environment variable. Cloud Run will
                scale automatically based on requests and you never have to
                worry about infrastructure.
            </p>

            <h1 class="text-2xl font-bold mt-[40px] mb-[20px]">
                Persistent Storage Example using Firestore
            </h1>
            <div hx-target="this" hx-swap="outerHTML">
                <p>
                <div><label>Name</label>: Cloud</div>
                </p><p>
                <div><label>Town</label>: Nibelheim</div>
                </p>
                <div>
                <button
                    hx-get="/edit"
                    class="bg-blue-500 text-white px-4 py-2 rounded-lg text-sm font-medium mt-[10px]"
                >
                    Click to update
                </button>                
                </div>
            </div>

            <h1 class="text-2xl font-bold mt-[40px] mb-[20px]">
                What's next
            </h1>
            <p class="next text-base mt-4 mb-[20px]">
                You can build this demo yourself!
            </p>
            <p class="cta">
                <button
                    class="bg-blue-500 text-white px-4 py-2 rounded-lg text-center text-sm font-medium"
                >
                    VIEW CODELAB
                </button>
            </p> 
        </div>
   </body>
</html>

৭. অ্যাপ্লিকেশনটি স্থানীয়ভাবে চালান

এই অংশে, ব্যবহারকারী যখন ডেটা সংরক্ষণ করার চেষ্টা করেন, তখন অ্যাপ্লিকেশনটিতে কোনো বাগ আছে কিনা তা নিশ্চিত করার জন্য আপনি অ্যাপ্লিকেশনটি স্থানীয়ভাবে চালাবেন।

প্রথমত, Firestore অ্যাক্সেস করার জন্য আপনার হয় Datastore User রোলটি থাকতে হবে (যদি প্রমাণীকরণের জন্য আপনার নিজের পরিচয় ব্যবহার করেন, যেমন আপনি Cloud Shell-এ চালাচ্ছেন) অথবা আপনি পূর্বে তৈরি করা ইউজার অ্যাকাউন্টটি ইমপারসোনেট করতে পারেন।

স্থানীয়ভাবে চালানোর সময় ADC ব্যবহার করা

আপনি যদি ক্লাউড শেলে (Cloud Shell) চালান, তাহলে আপনি ইতিমধ্যেই একটি গুগল কম্পিউট ইঞ্জিন (Google Compute Engine) ভার্চুয়াল মেশিনে কাজ করছেন। এই ভার্চুয়াল মেশিনের সাথে যুক্ত আপনার ক্রেডেনশিয়াল (যা gcloud auth list কমান্ড চালালে দেখা যায়) অ্যাপ্লিকেশন ডিফল্ট ক্রেডেনশিয়ালস (ADC) দ্বারা স্বয়ংক্রিয়ভাবে ব্যবহৃত হবে, তাই gcloud auth application-default login কমান্ডটি ব্যবহার করার প্রয়োজন নেই। তবে, আপনার আইডেন্টিটিতে ডেটাস্টোর ইউজার (Datastore User) রোলটি থাকা প্রয়োজন হবে। আপনি সরাসরি 'অ্যাপটি স্থানীয়ভাবে চালান' (Run the app locally ) অংশে চলে যেতে পারেন।

তবে, আপনি যদি আপনার লোকাল টার্মিনালে (অর্থাৎ ক্লাউড শেল-এ নয়) এটি চালান, তাহলে গুগল এপিআই-তে প্রমাণীকরণের জন্য আপনাকে অ্যাপ্লিকেশন ডিফল্ট ক্রেডেনশিয়াল ব্যবহার করতে হবে। আপনি হয় ১) আপনার ক্রেডেনশিয়াল ব্যবহার করে লগইন করতে পারেন (যদি আপনার ডেটাস্টোর ইউজার রোল থাকে) অথবা ২) এই কোডল্যাবে ব্যবহৃত সার্ভিস অ্যাকাউন্টটিকে ইমপারসোনেট করে লগইন করতে পারেন।

বিকল্প ১) ADC-এর জন্য আপনার পরিচয়পত্র ব্যবহার করা

আপনি যদি আপনার ক্রেডেনশিয়াল ব্যবহার করতে চান, তাহলে প্রথমে gcloud-এ আপনার অথেন্টিকেশন যাচাই করার জন্য gcloud auth list চালাতে পারেন। এরপর, আপনার আইডেন্টিটিকে Vertex AI User রোলটি প্রদান করার প্রয়োজন হতে পারে। যদি আপনার আইডেন্টিটির Owner রোল থাকে, তাহলে আপনার কাছে ইতিমধ্যেই এই Datastore User রোলটি আছে। যদি না থাকে, তাহলে আপনার আইডেন্টিটিকে Vertex AI user রোল এবং Datastore User রোল উভয়ই প্রদান করার জন্য আপনি এই কমান্ডটি চালাতে পারেন।

USER=<YOUR_PRINCIPAL_EMAIL>

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member user:$USER \
  --role=roles/datastore.user

তারপর নিম্নলিখিত কমান্ডটি চালান।

gcloud auth application-default login

বিকল্প ২) এডিসি-র জন্য একটি সার্ভিস অ্যাকাউন্টের ছদ্মবেশ ধারণ করা

আপনি যদি এই কোডল্যাবে তৈরি করা সার্ভিস অ্যাকাউন্টটি ব্যবহার করতে চান, তাহলে আপনার ইউজার অ্যাকাউন্টে ‘সার্ভিস অ্যাকাউন্ট টোকেন ক্রিয়েটর’ রোলটি থাকতে হবে। নিম্নলিখিত কমান্ডটি চালিয়ে আপনি এই রোলটি পেতে পারেন:

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member user:$USER \
  --role=roles/iam.serviceAccountTokenCreator

এরপরে, সার্ভিস অ্যাকাউন্টের সাথে ADC ব্যবহার করার জন্য আপনাকে নিম্নলিখিত কমান্ডটি চালাতে হবে।

gcloud auth application-default login --impersonate-service-account=$SERVICE_ACCOUNT_ADDRESS

অ্যাপটি স্থানীয়ভাবে চালান

এরপর, নিশ্চিত করুন যে আপনি আপনার কোডল্যাবের জন্য রুট ডিরেক্টরি cloud-run-github-cd-demo তে আছেন।

cd .. && pwd

এখন, আপনি ডিপেন্ডেন্সিগুলো ইনস্টল করবেন।

npm install

সবশেষে, নিচের স্ক্রিপ্টটি রান করে আপনি অ্যাপটি চালু করতে পারেন। এই স্ক্রিপ্টটি tailwindCSS থেকে output.css ফাইলটিও তৈরি করবে।

npm run dev

এখন আপনার ওয়েব ব্রাউজার খুলে http://localhost:8080-এ যান। আপনি যদি ক্লাউড শেলে থাকেন, তাহলে ওয়েব প্রিভিউ বাটনটি খুলে প্রিভিউ পোর্ট ৮০৮০ নির্বাচন করে ওয়েবসাইটটি খুলতে পারেন।

ওয়েব প্রিভিউ - পোর্ট ৮০৮০-তে প্রিভিউ বাটন

নাম এবং শহরের ইনপুট ফিল্ডে টেক্সট প্রবেশ করান এবং সেভ করুন। এরপর পেজটি রিফ্রেশ করুন। আপনি লক্ষ্য করবেন যে শহরের ফিল্ডটি আর থাকছে না। আপনি পরবর্তী অংশে এই বাগটি ঠিক করবেন।

স্থানীয়ভাবে এক্সপ্রেস অ্যাপটি চালানো বন্ধ করুন (যেমন MacOS-এ Ctrl^c)।

৮. একটি গিটহাব রিপোজিটরি তৈরি করুন

আপনার লোকাল ডিরেক্টরিতে, 'main' কে ডিফল্ট ব্রাঞ্চ নাম হিসেবে ব্যবহার করে একটি নতুন রিপো তৈরি করুন।

git init
git branch -M main

যে কোডবেসে বাগটি রয়েছে, সেটি কমিট করুন। কন্টিনিউয়াস ডেপ্লয়মেন্ট কনফিগার করার পর আপনি বাগটি ঠিক করবেন।

git add .
git commit -m "first commit for express application"

গিটহাবে যান এবং একটি খালি রিপোজিটরি তৈরি করুন যা আপনার জন্য ব্যক্তিগত বা সর্বজনীন হতে পারে। এই কোডল্যাবটি আপনার রিপোজিটরির নাম cloud-run-auto-deploy-codelab রাখার পরামর্শ দেয়। একটি খালি রিপোজিটরি তৈরি করতে, আপনি সমস্ত ডিফল্ট সেটিংস আনচেক করে রাখবেন অথবা 'none' এ সেট করবেন, যাতে তৈরি করার সময় ডিফল্টরূপে রিপোটিতে কোনো কন্টেন্ট না থাকে, যেমন।

গিটহাবের ডিফল্ট সেটিংস

আপনি যদি এই ধাপটি সঠিকভাবে সম্পন্ন করে থাকেন, তাহলে খালি রিপোজিটরি পৃষ্ঠায় নিম্নলিখিত নির্দেশাবলী দেখতে পাবেন:

খালি গিটহাব রিপো নির্দেশাবলী

নিম্নলিখিত কমান্ডগুলি চালিয়ে আপনি কমান্ড লাইন থেকে একটি বিদ্যমান রিপোজিটরি পুশ করার নির্দেশাবলী অনুসরণ করবেন:

প্রথমে, রান করে রিমোট রিপোজিটরি যোগ করুন।

git remote add origin <YOUR-REPO-URL-PER-GITHUB-INSTRUCTIONS>

তারপর প্রধান শাখাটি আপস্ট্রিম রিপোতে পুশ করুন।

git push -u origin main

৯. কন্টিনিউয়াস ডিপ্লয়মেন্ট সেটআপ করুন

এখন যেহেতু আপনার কোড গিটহাবে আছে, আপনি কন্টিনিউয়াস ডেপ্লয়মেন্ট সেটআপ করতে পারেন। ক্লাউড রান-এর জন্য ক্লাউড কনসোলে যান।

  • একটি পরিষেবা তৈরি করতে ক্লিক করুন
  • একটি রিপোজিটরি থেকে ক্রমাগত ডিপ্লয় করতে ক্লিক করুন
  • সেট আপ ক্লাউড বিল্ড-এ ক্লিক করুন।
  • সোর্স রিপোজিটরির অধীনে
    • রিপোজিটরি প্রোভাইডার হিসেবে গিটহাব নির্বাচন করুন
    • রিপোটিতে ক্লাউড বিল্ড অ্যাক্সেস কনফিগার করতে ‘ম্যানেজ কানেক্টেড রিপোজিটরিজ’- এ ক্লিক করুন।
    • আপনার সংগ্রহস্থল নির্বাচন করুন এবং পরবর্তী ধাপে যান।
  • বিল্ড কনফিগারেশনের অধীনে
    • শাখাটি ^main$ হিসাবে রেখে দিন
    • বিল্ড টাইপের জন্য, গুগল ক্লাউডের বিল্ডপ্যাকগুলির মাধ্যমে Go, Node.js, Python, Java, .NET Core, Ruby অথবা PHP নির্বাচন করুন।
  • বিল্ড কনটেক্সট ডিরেক্টরি / হিসাবে রাখুন
  • সংরক্ষণ করুন ক্লিক করুন
  • প্রমাণীকরণের অধীনে
    • প্রমাণীকরণবিহীন আহ্বানের অনুমতি দিন -এ ক্লিক করুন
  • কন্টেইনার, ভলিউম, নেটওয়ার্কিং, নিরাপত্তা এর অধীনে
    • সিকিউরিটি ট্যাবের অধীনে, পূর্ববর্তী ধাপে আপনার তৈরি করা সার্ভিস অ্যাকাউন্টটি নির্বাচন করুন, যেমন Cloud Run access to Firestore
  • তৈরি করতে ক্লিক করুন

এটি সেই ক্লাউড রান পরিষেবাটি স্থাপন করবে, যেটিতে বাগটি রয়েছে এবং যা আপনি পরবর্তী বিভাগে ঠিক করবেন।

১০. ত্রুটিটি সংশোধন করুন

কোডের ত্রুটিটি সংশোধন করুন।

ক্লাউড শেল এডিটরে, app.js ফাইলটি খুলুন এবং //TODO: fix this bug লেখা কমেন্টটিতে যান।

নিম্নলিখিত লাইনটি পরিবর্তন করুন

 //TODO: fix this bug
    await doc.set({
        name: name
    });

থেকে

//fixed town bug
    await doc.set({
        name: name,
        town: town
    });

সমাধানটি যাচাই করতে চালান

npm run start

এবং আপনার ওয়েব ব্রাউজারটি খুলুন। শহরের জন্য ডেটা আবার সেভ করুন এবং রিফ্রেশ করুন। আপনি দেখতে পাবেন যে রিফ্রেশ করার পর নতুন প্রবেশ করানো শহরের ডেটা সঠিকভাবে সংরক্ষিত হয়েছে।

এখন যেহেতু আপনি আপনার সমাধানটি যাচাই করে নিয়েছেন, আপনি এটি প্রয়োগ করার জন্য প্রস্তুত। প্রথমে, সমাধানটি কমিট করুন।

git add .
git commit -m "fixed town bug"

এবং তারপর এটি গিটহাবের আপস্ট্রিম রিপোজিটরিতে পুশ করুন।

git push origin main

ক্লাউড বিল্ড স্বয়ংক্রিয়ভাবে আপনার পরিবর্তনগুলো ডেপ্লয় করবে। ডেপ্লয়মেন্টের পরিবর্তনগুলো নিরীক্ষণ করতে আপনি আপনার ক্লাউড রান সার্ভিসের ক্লাউড কনসোলে যেতে পারেন।

প্রোডাকশনে ফিক্সটি যাচাই করুন

যখন আপনার ক্লাউড রান পরিষেবার ক্লাউড কনসোলে দেখা যাবে যে একটি দ্বিতীয় সংস্করণ এখন ১০০% ট্র্যাফিক পরিচালনা করছে, যেমন https://console.cloud.google.com/run/detail/<YOUR_REGION>/<YOUR_SERVICE_NAME>/revisions, তখন আপনি আপনার ব্রাউজারে ক্লাউড রান পরিষেবার URL-টি খুলে পৃষ্ঠাটি রিফ্রেশ করার পরেও নতুন প্রবেশ করানো শহরের তথ্য সংরক্ষিত আছে কিনা তা যাচাই করতে পারেন।

১১. অভিনন্দন!

কোডল্যাবটি সম্পন্ন করার জন্য অভিনন্দন!

আমরা ক্লাউড রান এবং গিট থেকে কন্টিনিউয়াস ডিপ্লয়মেন্ট ডকুমেন্টেশন পর্যালোচনা করার পরামর্শ দিই।

আমরা যা আলোচনা করেছি

  • ক্লাউড শেল এডিটর ব্যবহার করে একটি এক্সপ্রেস ওয়েব অ্যাপ্লিকেশন লিখুন।
  • নিরবচ্ছিন্ন ডেপ্লয়মেন্টের জন্য আপনার গিটহাব অ্যাকাউন্ট গুগল ক্লাউডের সাথে সংযুক্ত করুন।
  • আপনার অ্যাপ্লিকেশনটি স্বয়ংক্রিয়ভাবে ক্লাউড রান-এ ডেপ্লয় করুন।
  • HTMLX এবং TailwindCSS কীভাবে ব্যবহার করতে হয় তা শিখুন।

১২. পরিষ্কার করুন

অনিচ্ছাকৃত চার্জ এড়াতে (উদাহরণস্বরূপ, যদি ফ্রি টিয়ারে আপনার মাসিক ক্লাউড রান ব্যবহারের বরাদ্দের চেয়ে ক্লাউড রান পরিষেবাগুলো অনিচ্ছাকৃতভাবে বেশিবার চালু করা হয়), আপনি হয় ক্লাউড রানটি অথবা ধাপ ২-এ তৈরি করা প্রজেক্টটি ডিলিট করে দিতে পারেন।

Cloud Run সার্ভিসটি ডিলিট করতে, https://console.cloud.google.com/run-এ অবস্থিত Cloud Run ক্লাউড কনসোলে যান এবং এই কোডল্যাবে আপনার তৈরি করা Cloud Run সার্ভিসটি ডিলিট করুন, যেমন cloud-run-auto-deploy-codelab সার্ভিসটি ডিলিট করুন।

আপনি যদি পুরো প্রজেক্টটি মুছে ফেলতে চান, তাহলে আপনি https://console.cloud.google.com/cloud-resource-manager -এ গিয়ে, ধাপ ২-এ তৈরি করা প্রজেক্টটি নির্বাচন করে 'ডিলিট' (Delete) বিকল্পটি বেছে নিতে পারেন। প্রজেক্টটি মুছে ফেললে, আপনাকে আপনার ক্লাউড এসডিকে (Cloud SDK)-তে প্রজেক্ট পরিবর্তন করতে হবে। আপনি gcloud projects list চালিয়ে সমস্ত উপলব্ধ প্রজেক্টের তালিকা দেখতে পারেন।