1. مقدمة

نظرة عامة
تُعد الخدمات في Cloud Run مناسبة للحاويات التي تعمل إلى أجل غير مسمى وتستمع إلى طلبات HTTP، بينما تكون المهام في Cloud Run أكثر ملاءمة للحاويات التي تعمل حتى الاكتمال (حاليًا لمدة تصل إلى 24 ساعة) ولا تعالج الطلبات. على سبيل المثال، ستكون معالجة السجلات من قاعدة بيانات أو معالجة قائمة ملفات من حزمة Cloud Storage أو عملية طويلة الأمد، مثل حساب Pi، مناسبة إذا تم تنفيذها كإحدى مهام Cloud Run.
لا يمكن للوظائف عرض الطلبات أو الاستماع إلى منفذ. وهذا يعني أنّه على عكس خدمات Cloud Run، يجب ألا تتضمّن المهام خادم ويب. بدلاً من ذلك، يجب أن تتوقف حاويات المهام عند الانتهاء منها.
في مهام Cloud Run، يمكنك تشغيل نُسخ متعددة من الحاوية بالتوازي عن طريق تحديد عدد من المهام. تمثّل كل مهمة نسخة واحدة قيد التشغيل من الحاوية. يكون استخدام مهام متعددة مفيدًا إذا كان بإمكان كل مهمة معالجة مجموعة فرعية من بياناتك بشكل مستقل. على سبيل المثال، يمكن معالجة 10,000 سجلّ من Cloud SQL أو 10,000 ملف من Cloud Storage بشكل أسرع باستخدام 10 مهام تعالج 1,000 سجلّ أو ملف، كلّ على حدة بالتوازي.
يتضمّن استخدام مهام Cloud Run خطوتَين:
- إنشاء مهمة: يشمل ذلك جميع الإعدادات اللازمة لتشغيل المهمة، مثل صورة الحاوية والمنطقة ومتغيرات البيئة.
- تنفيذ المهمة: يؤدي ذلك إلى إنشاء عملية تنفيذ جديدة للمهمة. يمكنك اختياريًا إعداد مهمتك ليتم تنفيذها وفقًا لجدول زمني باستخدام Cloud Scheduler.
في هذا الدرس التطبيقي حول الترميز، ستستكشف أولاً تطبيق Node.js لالتقاط لقطات شاشة لصفحات الويب وتخزينها في Cloud Storage. بعد ذلك، يمكنك إنشاء صورة حاوية للتطبيق وتشغيلها على مهام Cloud Run وتعديل المهمة لمعالجة المزيد من صفحات الويب وتشغيل المهمة وفقًا لجدول زمني باستخدام Cloud Scheduler.
أهداف الدورة التعليمية
- كيفية استخدام تطبيق لأخذ لقطات شاشة لصفحات الويب
- كيفية إنشاء صورة حاوية للتطبيق
- كيفية إنشاء مهمة Cloud Run للتطبيق
- كيفية تشغيل التطبيق كإحدى مهام Cloud Run
- كيفية تعديل الوظيفة
- كيفية جدولة المهمة باستخدام Cloud Scheduler
2. الإعداد والمتطلبات
إعداد البيئة بوتيرة ذاتية
- سجِّل الدخول إلى Google Cloud Console وأنشِئ مشروعًا جديدًا أو أعِد استخدام مشروع حالي. إذا لم يكن لديك حساب على Gmail أو Google Workspace، عليك إنشاء حساب.



- اسم المشروع هو الاسم المعروض للمشاركين في هذا المشروع. وهي سلسلة أحرف لا تستخدمها Google APIs. ويمكنك تعديلها في أي وقت.
- معرّف المشروع هو معرّف فريد في جميع مشاريع Google Cloud ولا يمكن تغييره بعد ضبطه. تنشئ Cloud Console تلقائيًا سلسلة فريدة، ولا يهمّك عادةً ما هي. في معظم الجلسات التدريبية، عليك الرجوع إلى رقم تعريف مشروعك (يُشار إليه عادةً باسم
PROJECT_ID). إذا لم يعجبك المعرّف الذي تم إنشاؤه، يمكنك إنشاء معرّف عشوائي آخر. يمكنك بدلاً من ذلك تجربة اسم مستخدم من اختيارك ومعرفة ما إذا كان متاحًا. لا يمكن تغيير هذا الخيار بعد هذه الخطوة وسيظل ساريًا طوال مدة المشروع. - للعلم، هناك قيمة ثالثة، وهي رقم المشروع، تستخدمها بعض واجهات برمجة التطبيقات. يمكنك الاطّلاع على مزيد من المعلومات عن كل هذه القيم الثلاث في المستندات.
- بعد ذلك، عليك تفعيل الفوترة في Cloud Console لاستخدام موارد/واجهات برمجة تطبيقات Cloud. لن تكلفك تجربة هذا الدرس البرمجي الكثير، إن وُجدت أي تكلفة على الإطلاق. لإيقاف الموارد وتجنُّب تحمّل تكاليف تتجاوز هذا البرنامج التعليمي، يمكنك حذف الموارد التي أنشأتها أو حذف المشروع. يمكن لمستخدمي Google Cloud الجدد الاستفادة من برنامج الفترة التجريبية المجانية بقيمة 300 دولار أمريكي.
بدء Cloud Shell
على الرغم من إمكانية تشغيل Google Cloud عن بُعد من الكمبيوتر المحمول، ستستخدم في هذا الدرس العملي Google Cloud Shell، وهي بيئة سطر أوامر تعمل في السحابة الإلكترونية.
من Google Cloud Console، انقر على رمز Cloud Shell في شريط الأدوات أعلى يسار الصفحة:

لن يستغرق توفير البيئة والاتصال بها سوى بضع لحظات. عند الانتهاء، من المفترض أن يظهر لك ما يلي:

يتم تحميل هذه الآلة الافتراضية مزوّدة بكل أدوات التطوير التي ستحتاج إليها. توفّر هذه الخدمة دليلًا منزليًا دائمًا بسعة 5 غيغابايت، وتعمل على Google Cloud، ما يؤدي إلى تحسين أداء الشبكة والمصادقة بشكل كبير. يمكن إكمال جميع المهام في هذا الدرس العملي ضمن المتصفّح. لست بحاجة إلى تثبيت أي شيء.
إعداد gcloud
في Cloud Shell، اضبط رقم تعريف مشروعك والمنطقة التي تريد نشر مهمة Cloud Run فيها. احفظها كمتغيرات PROJECT_ID وREGION. في المستقبل، ستتمكّن من اختيار منطقة من إحدى المواقع الجغرافية التي يتوفّر فيها Cloud Run.
PROJECT_ID=[YOUR-PROJECT-ID] REGION=us-central1 gcloud config set core/project $PROJECT_ID
تفعيل واجهات برمجة التطبيقات
فعِّل جميع الخدمات اللازمة:
gcloud services enable \ artifactregistry.googleapis.com \ cloudbuild.googleapis.com \ run.googleapis.com
3- الحصول على الشفرة
ستستكشف أولاً تطبيق Node.js لالتقاط لقطات شاشة لصفحات الويب وتخزينها في Cloud Storage. في وقت لاحق، يمكنك إنشاء صورة حاوية للتطبيق وتشغيلها كمهمة على Cloud Run.
من Cloud Shell، شغِّل الأمر التالي لاستنساخ رمز التطبيق من مستودع هذا:
git clone https://github.com/GoogleCloudPlatform/jobs-demos.git
انتقِل إلى الدليل الذي يحتوي على التطبيق:
cd jobs-demos/screenshot
من المفترض أن يظهر تخطيط الملف التالي:
screenshot | ├── Dockerfile ├── README.md ├── screenshot.js ├── package.json
في ما يلي وصف موجز لكل ملف:
- يحتوي
screenshot.jsعلى رمز Node.js للتطبيق. - تحدّد السمة
package.jsonالموارد التابعة للمكتبة. - تحدّد
Dockerfileصورة الحاوية.
4. استكشاف الرمز
لاستكشاف الرمز، استخدِم محرّر النصوص المضمّن من خلال النقر على الزر Open Editor في أعلى نافذة Cloud Shell.

في ما يلي شرح موجز لكل ملف.
screenshot.js
يضيف screenshot.js أولاً Puppeteer وCloud Storage كعناصر تابعة. Puppeteer هي مكتبة Node.js تُستخدَم لأخذ لقطات شاشة لصفحات الويب:
const puppeteer = require('puppeteer');
const {Storage} = require('@google-cloud/storage');
تتوفّر دالة initBrowser لتهيئة Puppeteer ودالة takeScreenshot لأخذ لقطات شاشة لعنوان URL معيّن:
async function initBrowser() {
console.log('Initializing browser');
return await puppeteer.launch();
}
async function takeScreenshot(browser, url) {
const page = await browser.newPage();
console.log(`Navigating to ${url}`);
await page.goto(url);
console.log(`Taking a screenshot of ${url}`);
return await page.screenshot({
fullPage: true
});
}
بعد ذلك، هناك دالة للحصول على حزمة Cloud Storage أو إنشائها، ودالة أخرى لتحميل لقطة شاشة لصفحة ويب إلى حزمة:
async function createStorageBucketIfMissing(storage, bucketName) {
console.log(`Checking for Cloud Storage bucket '${bucketName}' and creating if not found`);
const bucket = storage.bucket(bucketName);
const [exists] = await bucket.exists();
if (exists) {
// Bucket exists, nothing to do here
return bucket;
}
// Create bucket
const [createdBucket] = await storage.createBucket(bucketName);
console.log(`Created Cloud Storage bucket '${createdBucket.name}'`);
return createdBucket;
}
async function uploadImage(bucket, taskIndex, imageBuffer) {
// Create filename using the current time and task index
const date = new Date();
date.setMinutes(date.getMinutes() - date.getTimezoneOffset());
const filename = `${date.toISOString()}-task${taskIndex}.png`;
console.log(`Uploading screenshot as '${filename}'`)
await bucket.file(filename).save(imageBuffer);
}
أخيرًا، الدالة main هي نقطة الدخول:
async function main(urls) {
console.log(`Passed in urls: ${urls}`);
const taskIndex = process.env.CLOUD_RUN_TASK_INDEX || 0;
const url = urls[taskIndex];
if (!url) {
throw new Error(`No url found for task ${taskIndex}. Ensure at least ${parseInt(taskIndex, 10) + 1} url(s) have been specified as command args.`);
}
const bucketName = process.env.BUCKET_NAME;
if (!bucketName) {
throw new Error('No bucket name specified. Set the BUCKET_NAME env var to specify which Cloud Storage bucket the screenshot will be uploaded to.');
}
const browser = await initBrowser();
const imageBuffer = await takeScreenshot(browser, url).catch(async err => {
// Make sure to close the browser if we hit an error.
await browser.close();
throw err;
});
await browser.close();
console.log('Initializing Cloud Storage client')
const storage = new Storage();
const bucket = await createStorageBucketIfMissing(storage, bucketName);
await uploadImage(bucket, taskIndex, imageBuffer);
console.log('Upload complete!');
}
main(process.argv.slice(2)).catch(err => {
console.error(JSON.stringify({severity: 'ERROR', message: err.message}));
process.exit(1);
});
يُرجى ملاحظة ما يلي بشأن طريقة main:
- يتم تمرير عناوين URL كوسيطات.
- يتم تمرير اسم الحزمة كمتغير بيئة
BUCKET_NAMEيحدّده المستخدم. يجب أن يكون اسم الحزمة فريدًا على مستوى جميع خدمات Google Cloud. - يتم تمرير متغير بيئة
CLOUD_RUN_TASK_INDEXمن خلال مهام Cloud Run. يمكن أن تنفّذ مهام Cloud Run نُسخًا متعددة من التطبيق كمهام فريدة. يمثّلCLOUD_RUN_TASK_INDEXفهرس المهمة قيد التشغيل. يتم ضبط القيمة تلقائيًا على صفر عند تشغيل الرمز خارج مهام Cloud Run. عند تشغيل التطبيق كمهام متعددة، تختار كل مهمة/حاوية عنوان URL الذي تكون مسؤولة عنه، وتلتقط لقطة شاشة، وتحفظ الصورة في الحزمة.
package.json
يحدّد ملف package.json التطبيق ويحدّد التبعيات لكل من Cloud Storage وPuppeteer:
{
"name": "screenshot",
"version": "1.0.0",
"description": "Create a job to capture screenshots",
"main": "screenshot.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Google LLC",
"license": "Apache-2.0",
"dependencies": {
"@google-cloud/storage": "^5.18.2",
"puppeteer": "^13.5.1"
}
}
Dockerfile
يحدّد Dockerfile صورة الحاوية للتطبيق مع جميع المكتبات والعناصر التابعة المطلوبة:
FROM ghcr.io/puppeteer/puppeteer:16.1.0 COPY package*.json ./ RUN npm ci --omit=dev COPY . . ENTRYPOINT ["node", "screenshot.js"]
5- نشر مهمة
قبل إنشاء مهمة، عليك إنشاء حساب خدمة ستستخدمه لتنفيذ المهمة.
gcloud iam service-accounts create screenshot-sa --display-name="Screenshot app service account"
امنح حساب الخدمة دور storage.admin، حتى يمكن استخدامه لإنشاء حِزم وكائنات.
gcloud projects add-iam-policy-binding $PROJECT_ID \ --role roles/storage.admin \ --member serviceAccount:screenshot-sa@$PROJECT_ID.iam.gserviceaccount.com
أنت الآن مستعد لنشر مهمة Cloud Run تتضمّن الإعدادات اللازمة لتشغيل المهمة.
gcloud beta run jobs deploy screenshot \ --source=. \ --args="https://example.com" \ --args="https://cloud.google.com" \ --tasks=2 \ --task-timeout=5m \ --region=$REGION \ --set-env-vars=BUCKET_NAME=screenshot-$PROJECT_ID-$RANDOM \ --service-account=screenshot-sa@$PROJECT_ID.iam.gserviceaccount.com
يستخدم هذا الأمر عملية النشر المستندة إلى المصدر وينشئ مهمة Cloud Run بدون تنفيذها.
لاحظ كيف يتم تمرير صفحات الويب كمعلمات. يتم تمرير اسم الحزمة لحفظ لقطات الشاشة كمتغيّر بيئة.
يمكنك تشغيل نُسخ متعددة من الحاوية بالتوازي عن طريق تحديد عدد المهام التي سيتم تنفيذها باستخدام العلامة --tasks. تمثّل كل مهمة نسخة واحدة قيد التشغيل من الحاوية. يكون استخدام مهام متعددة مفيدًا إذا كان بإمكان كل مهمة معالجة مجموعة فرعية من بياناتك بشكل مستقل. لتسهيل ذلك، تكون كل مهمة على دراية بالفهرس الخاص بها، والذي يتم تخزينه في متغيّر البيئة CLOUD_RUN_TASK_INDEX. يكون الرمز مسؤولاً عن تحديد المهمة التي تعالج المجموعة الفرعية من البيانات. لاحظ --tasks=2 في هذا النموذج. يضمن ذلك تشغيل حاويتين لعنوانَي URL اللذين نريد معالجتهما.
يمكن أن يستغرق تنفيذ كل مهمة مدة تصل إلى 24 ساعة. يمكنك تقليل مهلة الانتظار هذه باستخدام العلامة --task-timeout، كما فعلنا في هذا المثال. يجب أن تنجح جميع المهام لكي تكتمل المهمة بنجاح. لا تتم إعادة محاولة تنفيذ المهام التي تعذّر تنفيذها تلقائيًا. يمكنك ضبط المهام ليتم إعادة محاولة تنفيذها عند تعذُّر إكمالها. إذا تجاوزت أي مهمة عدد محاولات إعادة تنفيذها، ستتعذّر المهمة بأكملها.
سيتم تلقائيًا تنفيذ مهمتك مع أكبر عدد ممكن من المهام بالتوازي. سيكون هذا الرقم مساويًا لعدد المهام في وظيفتك، وبحد أقصى 100. يمكنك ضبط درجة التنفيذ المتوازي على قيمة أقل للوظائف التي تصل إلى نظام خلفي ذي قابلية محدودة للتوسّع. على سبيل المثال، قاعدة بيانات تتيح عددًا محدودًا من عمليات الاتصال النشطة. يمكنك خفض درجة التنفيذ المتوازي باستخدام العلامة --parallelism.
6. تشغيل مهمة
قبل تشغيل المهمة، أدرِج المهمة للتأكّد من أنّها قد تم إنشاؤها:
gcloud run jobs list ✔ JOB: screenshot REGION: us-central LAST RUN AT: CREATED: 2022-02-22 12:20:50 UTC
شغِّل المهمة باستخدام الأمر التالي:
gcloud run jobs execute screenshot --region=$REGION
يؤدي هذا الإجراء إلى تنفيذ المهمة. يمكنك إدراج عمليات التنفيذ الحالية والسابقة:
gcloud run jobs executions list --job screenshot --region=$REGION ... JOB: screenshot EXECUTION: screenshot-znkmm REGION: $REGION RUNNING: 1 COMPLETE: 1 / 2 CREATED: 2022-02-22 12:40:42 UTC
صِف عملية التنفيذ. من المفترض أن تظهر لك علامة الصح الخضراء والرسالة tasks completed successfully:
gcloud run jobs executions describe screenshot-znkmm --region=$REGION ✔ Execution screenshot-znkmm in region $REGION 2 tasks completed successfully Image: $REGION-docker.pkg.dev/$PROJECT_ID/containers/screenshot at 311b20d9... Tasks: 2 Args: https://example.com https://cloud.google.com Memory: 1Gi CPU: 1000m Task Timeout: 3600s Parallelism: 2 Service account: 11111111-compute@developer.gserviceaccount.com Env vars: BUCKET_NAME screenshot-$PROJECT_ID-$RANDOM
يمكنك أيضًا الانتقال إلى صفحة مهام Cloud Run في Cloud Console للاطّلاع على الحالة:

إذا تحقّقت من حزمة Cloud Storage، من المفترض أن يظهر ملفا لقطات الشاشة اللذان تم إنشاؤهما:

في بعض الأحيان، قد تحتاج إلى إيقاف عملية تنفيذ قبل اكتمالها، ربما لأنّك أدركت أنّك بحاجة إلى تشغيل المهمة باستخدام مَعلمات مختلفة أو لأنّ هناك خطأ في الرمز، ولا تريد استخدام وقت حوسبة غير ضروري.
لإيقاف تنفيذ مهمتك، عليك حذف عملية التنفيذ:
gcloud run jobs executions delete screenshot-znkmm --region=$REGION
7. تعديل وظيفة
لا يتم تلقائيًا اختيار الإصدارات الجديدة من الحاوية من خلال مهام Cloud Run في عملية التنفيذ التالية. إذا غيّرت رمز وظيفتك، عليك إعادة إنشاء الحاوية وتعديل وظيفتك. سيساعدك استخدام الصور الموسومة في تحديد إصدار الصورة المستخدَم حاليًا.
وبالمثل، عليك أيضًا تعديل المهمة إذا أردت تعديل بعض متغيرات الإعداد. ستستخدم عمليات التنفيذ اللاحقة للمهمة الحاوية الجديدة وإعدادات الضبط.
عدِّل المهمة وغيِّر الصفحات التي يأخذ التطبيق لقطات شاشة لها في العلامة --args. عدِّل أيضًا العلامة --tasks لتعكس عدد الصفحات.
gcloud run jobs update screenshot \ --args="https://www.pinterest.com" \ --args="https://www.apartmenttherapy.com" \ --args="https://www.google.com" \ --region=$REGION \ --tasks=3
أعِد تشغيل المهمة. مرِّر هذا الوقت في العلامة --wait للانتظار إلى حين انتهاء عمليات التنفيذ:
gcloud run jobs execute screenshot --region=$REGION --wait
بعد بضع ثوانٍ، من المفترض أن ترى 3 لقطات شاشة أخرى تمت إضافتها إلى الحزمة:

8. جدولة مهمة
حتى الآن، أنت تنفّذ المهام يدويًا. في سيناريو واقعي، من المحتمل أنّك تريد تنفيذ المهام استجابةً لحدث أو وفقًا لجدول زمني. لنطّلِع على كيفية تشغيل مهمة لقطة الشاشة في جدول زمني باستخدام Cloud Scheduler.
تأكَّد أولاً من تفعيل Cloud Scheduler API:
gcloud services enable cloudscheduler.googleapis.com
انتقِل إلى صفحة تفاصيل مهام Cloud Run وانقر على القسم Triggers:

انقر على زر Add Scheduler Trigger:

سيتم فتح لوحة على يسار الصفحة. أنشئ مهمة في أداة جدولة المهام لتنفيذها كل يوم في الساعة 9:00 صباحًا باستخدام هذا الإعداد واختَر Continue:

في الصفحة التالية، اختَر حساب خدمة الحوسبة التلقائي وانقر على Create:

من المفترض أن يظهر لك الآن مشغّل Cloud Scheduler جديد تم إنشاؤه:

انقر على View Details للانتقال إلى صفحة Cloud Scheduler.
يمكنك الانتظار حتى الساعة 9 صباحًا لكي يبدأ المجدول عمله، أو يمكنك تشغيل Cloud Scheduler يدويًا من خلال النقر على Force Run:

بعد بضع ثوانٍ، من المفترض أن ترى أنّه تم تنفيذ مهمة Cloud Scheduler بنجاح:

من المفترض أن تظهر لك أيضًا 3 لقطات شاشة أخرى أضافتها المكالمة من Cloud Scheduler:

9- تهانينا
تهانينا، لقد أكملت درس البرمجة.
التنظيف (اختياري)
لتجنُّب تحمّل رسوم، يُنصح بتنظيف الموارد.
إذا لم تعُد بحاجة إلى المشروع، يمكنك ببساطة حذفه باتّباع الخطوات التالية:
gcloud projects delete $PROJECT_ID
إذا كنت بحاجة إلى المشروع، يمكنك حذف المراجع بشكل فردي.
احذف رمز المصدر:
rm -rf ~/jobs-demos/
احذف مستودع Artifact Registry:
gcloud artifacts repositories delete containers --location=$REGION
احذف حساب الخدمة باتّباع الخطوات التالية:
gcloud iam service-accounts delete screenshot-sa@$PROJECT_ID.iam.gserviceaccount.com
احذف مهمة Cloud Run:
gcloud run jobs delete screenshot --region=$REGION
احذف مهمة Cloud Scheduler:
gcloud scheduler jobs delete screenshot-scheduler-trigger --location=$REGION
احذف حزمة Cloud Storage:
gcloud storage rm --recursive gs://screenshot-$PROJECT_ID
المواضيع التي تناولناها
- كيفية استخدام تطبيق لأخذ لقطات شاشة لصفحات الويب
- كيفية إنشاء صورة حاوية للتطبيق
- كيفية إنشاء مهمة Cloud Run للتطبيق
- كيفية تشغيل التطبيق كإحدى مهام Cloud Run
- كيفية تعديل الوظيفة
- كيفية جدولة المهمة باستخدام Cloud Scheduler