1. مقدمه
نمای کلی
در این لبه کد، Cloud Run را به گونهای پیکربندی میکنید که هر زمان که تغییرات کد منبع خود را به مخزن GitHub وارد میکنید ، بهطور خودکار نسخههای جدید برنامه خود را بسازد و اجرا کند .
این برنامه آزمایشی داده های کاربر را در firestore ذخیره می کند، با این حال، تنها مقدار جزئی از داده ها به درستی ذخیره می شود. شما پیادهسازیهای پیوسته را به گونهای پیکربندی میکنید که وقتی یک رفع اشکال را به مخزن GitHub خود فشار میدهید، بهطور خودکار مشاهده میکنید که اصلاح در یک نسخه جدید در دسترس است.
چیزی که یاد خواهید گرفت
- با Cloud Shell Editor یک برنامه وب Express بنویسید
- حساب GitHub خود را برای استقرار مداوم به Google Cloud متصل کنید
- به طور خودکار برنامه خود را در Cloud Run مستقر کنید
- نحوه استفاده از HTMX و TailwindCSS را بیاموزید
2. راه اندازی و الزامات
پیش نیازها
- شما یک حساب GitHub دارید و با ایجاد و ارسال کد به مخازن آشنا هستید.
- شما به کنسول Cloud وارد شده اید.
- شما قبلاً یک سرویس Cloud Run را مستقر کرده اید. برای مثال، میتوانید برای شروع ، استقرار یک سرویس وب را از کد منبع سریع دنبال کنید.
Cloud Shell را فعال کنید
- از Cloud Console، روی Activate Cloud Shell کلیک کنید .
اگر این اولین باری است که Cloud Shell را راه اندازی می کنید، با یک صفحه میانی روبرو می شوید که آن را توصیف می کند. اگر با یک صفحه میانی مواجه شدید، روی Continue کلیک کنید.
تهیه و اتصال به Cloud Shell فقط باید چند لحظه طول بکشد.
این ماشین مجازی با تمام ابزارهای توسعه مورد نیاز بارگذاری شده است. این یک فهرست اصلی 5 گیگابایتی دائمی ارائه میکند و در Google Cloud اجرا میشود، که عملکرد و احراز هویت شبکه را بسیار افزایش میدهد. بسیاری از کارهای شما، اگر نه همه، در این کد لبه با مرورگر قابل انجام است.
پس از اتصال به Cloud Shell، باید ببینید که احراز هویت شده اید و پروژه به ID پروژه شما تنظیم شده است.
- برای تایید احراز هویت، دستور زیر را در Cloud Shell اجرا کنید:
gcloud auth list
خروجی فرمان
Credentialed Accounts ACTIVE ACCOUNT * <my_account>@<my_domain.com> To set the active account, run: $ gcloud config set account `ACCOUNT`
- دستور زیر را در Cloud Shell اجرا کنید تا تأیید کنید که دستور gcloud از پروژه شما اطلاع دارد:
gcloud config list project
خروجی فرمان
[core] project = <PROJECT_ID>
اگر اینطور نیست، می توانید آن را با این دستور تنظیم کنید:
gcloud config set project <PROJECT_ID>
خروجی فرمان
Updated property [core/project].
3. API ها را فعال کنید و متغیرهای محیط را تنظیم کنید
API ها را فعال کنید
این آزمایشگاه کد نیاز به استفاده از 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
4. یک حساب کاربری ایجاد کنید
این حساب سرویس توسط Cloud Run برای فراخوانی Vertex AI Gemini API استفاده خواهد شد. این حساب سرویس همچنین دارای مجوز خواندن و نوشتن در Firestor و خواندن اسرار از Secret Manager است.
ابتدا با اجرای این دستور اکانت سرویس ایجاد کنید:
gcloud iam service-accounts create $SERVICE_ACCOUNT \ --display-name="Cloud Run access to Firestore"
اکنون، به حساب سرویس دسترسی خواندن و نوشتن به Firestor اجازه دهید.
gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:$SERVICE_ACCOUNT_ADDRESS \ --role=roles/datastore.user
5. یک پروژه Firebase ایجاد و پیکربندی کنید
- در کنسول Firebase ، روی افزودن پروژه کلیک کنید.
- برای افزودن Firebase به یکی از پروژههای Google Cloud موجود، <YOUR_PROJECT_ID> را وارد کنید
- در صورت درخواست، شرایط Firebase را بررسی کرده و بپذیرید.
- روی Continue کلیک کنید.
- برای تأیید طرح صورتحساب Firebase روی تأیید طرح کلیک کنید.
- این اختیاری است که Google Analytics را برای این کد لبه فعال کنید.
- روی Add Firebase کلیک کنید.
- پس از ایجاد پروژه، روی Continue کلیک کنید.
- از منوی Build ، روی پایگاه داده Firestore کلیک کنید.
- روی ایجاد پایگاه داده کلیک کنید.
- منطقه خود را از منوی کشویی Location انتخاب کنید، سپس روی Next کلیک کنید.
- از Start پیش فرض در حالت تولید استفاده کنید، سپس روی Create کلیک کنید.
6. برنامه را بنویسید
ابتدا یک دایرکتوری برای کد منبع و سی دی در آن دایرکتوری ایجاد کنید.
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>`;
یک فایل input.css
برای tailwindCSS ایجاد کنید
@tailwind base; @tailwind components; @tailwind utilities;
و فایل tailwind.config.js
را برای tailwindCSS ایجاد کنید
/** @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>
7. برنامه را به صورت محلی اجرا کنید
در این بخش، برنامه را به صورت محلی اجرا می کنید تا زمانی که کاربر سعی می کند داده ها را ذخیره کند، یک اشکال در برنامه وجود دارد.
ابتدا، برای دسترسی به Firestore یا باید نقش Datastore User را داشته باشید (اگر از هویت خود برای احراز هویت استفاده می کنید، مثلاً در Cloud Shell در حال اجرا هستید) یا می توانید جعل هویت حساب کاربری که قبلاً ایجاد شده است.
استفاده از ADC هنگام اجرای محلی
اگر در Cloud Shell در حال اجرا هستید، در حال حاضر روی یک ماشین مجازی موتور محاسباتی گوگل کار می کنید. اعتبارنامه شما مرتبط با این ماشین مجازی (همانطور که با اجرای gcloud auth list
نشان داده شده است) به طور خودکار توسط Application Default Credentials (ADC) استفاده می شود، بنابراین استفاده از دستور gcloud auth application-default login
ضروری نیست. با این حال، هویت شما همچنان به نقش کاربر Datastore نیاز دارد. می توانید به بخش اجرای برنامه به صورت محلی پرش کنید.
با این حال، اگر در ترمینال محلی خود در حال اجرا هستید (یعنی نه در Cloud Shell)، باید از اعتبارنامه پیش فرض برنامه برای احراز هویت در API های Google استفاده کنید. شما می توانید 1) با استفاده از اطلاعات کاربری خود وارد شوید (به شرطی که نقش کاربر Datastore را داشته باشید) یا 2) می توانید با جعل هویت حساب سرویس مورد استفاده در این کد لبه وارد شوید.
گزینه 1) استفاده از اعتبارنامه خود برای ADC
اگر میخواهید از اعتبارنامههای خود استفاده کنید، میتوانید ابتدا gcloud auth list
را اجرا کنید تا نحوه احراز هویت خود را در gcloud تأیید کنید. در مرحله بعد، ممکن است لازم باشد به هویت خود نقش Vertex AI User را بدهید. اگر هویت شما دارای نقش مالک است، شما از قبل این نقش کاربری کاربر Datastore را دارید. اگر نه، میتوانید این دستور را اجرا کنید تا به هویت خود، نقش کاربر Vertex AI و نقش کاربر Datastore را اعطا کنید.
USER=<YOUR_PRINCIPAL_EMAIL> gcloud projects add-iam-policy-binding $PROJECT_ID \ --member user:$USER \ --role=roles/datastore.user
سپس دستور زیر را اجرا کنید
gcloud auth application-default login
گزینه 2) جعل هویت یک حساب سرویس برای ADC
اگر میخواهید از حساب سرویس ایجاد شده در این کد لبه استفاده کنید، حساب کاربری شما باید نقش ایجاد کننده رمز حساب سرویس را داشته باشد. با اجرای دستور زیر می توانید این نقش را بدست آورید:
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
برای Codelab خود هستید.
cd .. && pwd
اکنون، وابستگی ها را نصب خواهید کرد.
npm install
در نهایت، می توانید برنامه را با اجرای اسکریپت زیر راه اندازی کنید. این اسکریپت همچنین فایل output.css را از tailwindCSS تولید می کند.
npm run dev
اکنون مرورگر وب خود را به http://localhost:8080 باز کنید. اگر در Cloud Shell هستید، می توانید با باز کردن دکمه Web Preview و انتخاب Preview Port 8080 وب سایت را باز کنید.
متنی را برای فیلدهای ورودی نام و شهر وارد کنید و ذخیره را بزنید. سپس صفحه را رفرش کنید. متوجه خواهید شد که میدان شهر پابرجا نبود. در بخش بعدی این باگ را برطرف خواهید کرد.
اجرای محلی برنامه اکسپرس را متوقف کنید (مثلاً Ctrl^c در MacOS).
8. یک مخزن GitHub ایجاد کنید
در فهرست محلی خود، یک مخزن جدید با main به عنوان نام شعبه پیش فرض ایجاد کنید.
git init git branch -M main
پایگاه کد فعلی را که حاوی باگ است، متعهد کنید. پس از پیکربندی استقرار مداوم، باگ را برطرف خواهید کرد.
git add . git commit -m "first commit for express application"
به GitHub بروید و یک مخزن خالی ایجاد کنید که یا برای شما خصوصی است یا عمومی. این آزمایشگاه کد نامگذاری مخزن خود را به نام cloud-run-auto-deploy-codelab
توصیه می کند برای ایجاد یک مخزن خالی، تمام تنظیمات پیش فرض را علامت نزنید یا روی هیچکدام تنظیم نکنید، به طوری که هنگام ایجاد، هیچ محتوایی به طور پیش فرض در مخزن نباشد، به عنوان مثال.
اگر این مرحله را به درستی انجام داده باشید، دستورالعمل های زیر را در صفحه خالی مخزن خواهید دید:
با اجرای دستورات زیر ، فشار یک مخزن موجود را از دستورالعمل های خط فرمان دنبال خواهید کرد:
ابتدا مخزن راه دور را با اجرا اضافه کنید
git remote add origin <YOUR-REPO-URL-PER-GITHUB-INSTRUCTIONS>
سپس شاخه اصلی را به مخزن بالادست فشار دهید.
git push -u origin main
9. راه اندازی مستمر استقرار
اکنون که کدی در یک GitHub دارید، می توانید استقرار مداوم را تنظیم کنید. برای Cloud Run به Cloud Console بروید.
- روی ایجاد سرویس کلیک کنید
- روی Continuously Deploy from a Repository کلیک کنید
- روی SET UP CLOUD BUILD کلیک کنید.
- در زیر مخزن منبع
- GitHub را به عنوان ارائه دهنده مخزن انتخاب کنید
- برای پیکربندی دسترسی Cloud Build به مخزن ، روی مدیریت مخازن متصل کلیک کنید
- مخزن خود را انتخاب کنید و روی Next کلیک کنید
- تحت پیکربندی ساخت
- شعبه را به عنوان ^main$ ترک کنید
- برای نوع ساخت، Go، Node.js، Python، Java، NET Core، Ruby یا PHP را از طریق بستههای ساخت Google Cloud انتخاب کنید.
- دایرکتوری زمینه ساخت را به عنوان
/
رها کنید - روی ذخیره کلیک کنید
- تحت احراز هویت
- روی اجازه دادن به فراخوانهای احراز هویت نشده کلیک کنید
- تحت کانتینر(ها)، حجم، شبکه، امنیت
- در برگه امنیت، حساب سرویسی را که در مرحله قبلی ایجاد کردید، انتخاب کنید، به عنوان مثال
Cloud Run access to Firestore
- در برگه امنیت، حساب سرویسی را که در مرحله قبلی ایجاد کردید، انتخاب کنید، به عنوان مثال
- روی CREATE کلیک کنید
با این کار سرویس Cloud Run حاوی اشکالی است که در بخش بعدی رفع خواهید کرد.
10. رفع اشکال
رفع اشکال در کد
در Cloud Shell Editor، فایل 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"
و سپس آن را به مخزن بالادستی در GitHub فشار دهید.
git push origin main
Cloud Build به طور خودکار تغییرات شما را اجرا می کند. برای نظارت بر تغییرات استقرار می توانید به کنسول Cloud برای سرویس Cloud Run خود بروید.
تعمیر را در تولید بررسی کنید
هنگامی که کنسول Cloud برای سرویس Cloud Run شما نشان داد که نسخه دوم اکنون 100٪ ترافیک را ارائه می دهد، به عنوان مثال https://console.cloud.google.com/run/detail/<YOUR_REGION>/<YOUR_SERVICE_NAME>/revisions، می توانید باز کنید URL سرویس Cloud Run را در مرورگر خود و بررسی کنید که دادههای شهر تازه وارد شده پس از رفرش صفحه همچنان باقی بماند.
11. تبریک می گویم!
برای تکمیل کد لبه تبریک می گویم!
توصیه میکنیم مستندات Cloud Run و استقرار مداوم از git را مرور کنید.
آنچه را پوشش داده ایم
- با Cloud Shell Editor یک برنامه وب Express بنویسید
- حساب GitHub خود را برای استقرار مداوم به Google Cloud متصل کنید
- به طور خودکار برنامه خود را در Cloud Run مستقر کنید
- نحوه استفاده از HTMX و TailwindCSS را بیاموزید
12. پاکسازی کنید
برای جلوگیری از هزینههای غیرعمدی، (به عنوان مثال، اگر سرویسهای Cloud Run به طور ناخواسته بیشتر از تخصیص فراخوانی ماهانه Cloud Run در ردیف رایگان فراخوانی میشوند)، میتوانید Cloud Run را حذف کنید یا پروژهای را که در مرحله 2 ایجاد کردهاید حذف کنید.
برای حذف سرویس Cloud Run، به کنسول Cloud Run Cloud در https://console.cloud.google.com/run بروید و سرویس Cloud Run را که در این Codelab ایجاد کرده اید حذف کنید، به عنوان مثال، cloud-run-auto-deploy-codelab
را حذف کنید. -سرویس cloud-run-auto-deploy-codelab
.
اگر تصمیم به حذف کل پروژه دارید، میتوانید به https://console.cloud.google.com/cloud-resource-manager بروید، پروژهای را که در مرحله ۲ ایجاد کردهاید انتخاب کنید و حذف را انتخاب کنید. اگر پروژه را حذف کنید، باید پروژه ها را در Cloud SDK خود تغییر دهید. با اجرای gcloud projects list
می توانید لیست تمام پروژه های موجود را مشاهده کنید.