1. מבוא

סקירה כללית
Cloud Run services מתאים לקונטיינרים שפועלים ללא הגבלת זמן ומאזינים לבקשות HTTP, בעוד ש-jobs ב-Cloud Run מתאים יותר לקונטיינרים שפועלים עד לסיום (נכון לעכשיו עד 24 שעות) ולא מטפלים בבקשות. לדוגמה, עיבוד רשומות ממסד נתונים, עיבוד רשימת קבצים מקטגוריה של Cloud Storage או פעולה שפועלת לאורך זמן, כמו חישוב של פאי, יתאימו אם יוטמעו כמשימה ב-Cloud Run.
לג'ובים אין אפשרות לטפל בבקשות או להאזין ליציאה. המשמעות היא שבניגוד לשירותים ב-Cloud Run, משימות לא צריכות לכלול שרת אינטרנט. במקום זאת, קונטיינרים של משימות צריכים לצאת כשהם מסיימים.
במשימות של Cloud Run, אפשר להריץ כמה עותקים של הקונטיינר במקביל על ידי ציון מספר המשימות. כל משימה מייצגת עותק אחד של הקונטיינר שפועל. שימוש בכמה משימות יכול להיות שימושי אם כל משימה יכולה לעבד באופן עצמאי קבוצת משנה של הנתונים. לדוגמה, עיבוד של 10,000 רשומות מ-Cloud SQL או של 10,000 קבצים מ-Cloud Storage יכול להתבצע מהר יותר באמצעות 10 משימות לעיבוד של 1,000 רשומות או קבצים, כל אחת במקביל.
השימוש במשימות של Cloud Run כולל שני שלבים:
- יצירת משימה: המשימה כוללת את כל ההגדרות שנדרשות להרצת המשימה, כמו קובץ האימג' בקונטיינר, האזור ומשתני הסביבה.
- הפעלת העבודה: הפעולה הזו יוצרת הרצה חדשה של העבודה. אפשר גם להגדיר את המשימה להרצה לפי לוח זמנים באמצעות Cloud Scheduler.
ב-codelab הזה, קודם בודקים אפליקציית 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 יוצר באופן אוטומטי מחרוזת ייחודית, ובדרך כלל לא צריך לדעת מה היא. ברוב ה-Codelabs, תצטרכו להפנות למזהה הפרויקט (בדרך כלל מסומן כ-
PROJECT_ID). אם אתם לא אוהבים את המזהה שנוצר, אתם יכולים ליצור מזהה אקראי אחר. אפשר גם לנסות שם משתמש משלכם ולבדוק אם הוא זמין. אי אפשר לשנות את ההגדרה הזו אחרי השלב הזה, והיא נשארת לאורך הפרויקט. - לידיעתכם, יש ערך שלישי, מספר פרויקט, שחלק מממשקי ה-API משתמשים בו. מידע נוסף על שלושת הערכים האלה מופיע במאמרי העזרה.
- בשלב הבא, תצטרכו להפעיל את החיוב במסוף Cloud כדי להשתמש במשאבי Cloud או בממשקי API של Cloud. השלמת ה-codelab הזה לא תעלה לכם הרבה, אם בכלל. כדי להשבית את המשאבים ולוודא שלא תחויבו על שימוש בהם אחרי שתסיימו את המדריך הזה, תוכלו למחוק את המשאבים שיצרתם או למחוק את הפרויקט. משתמשים חדשים ב-Google Cloud זכאים לתוכנית תקופת ניסיון בחינם בשווי 300$.
הפעלת Cloud Shell
אפשר להפעיל את Google Cloud מרחוק מהמחשב הנייד, אבל ב-codelab הזה תשתמשו ב-Google Cloud Shell, סביבת שורת פקודה שפועלת ב-Cloud.
ב-Google Cloud Console, לוחצים על סמל Cloud Shell בסרגל הכלים שבפינה הימנית העליונה:

הקצאת המשאבים והחיבור לסביבה יימשכו רק כמה רגעים. בסיום התהליך, אמור להופיע משהו כזה:

המכונה הווירטואלית הזו טעונה בכל הכלים הדרושים למפתחים. יש בה ספריית בית בנפח מתמיד של 5GB והיא פועלת ב-Google Cloud, מה שמשפר מאוד את הביצועים והאימות ברשת. אפשר לבצע את כל העבודה ב-Codelab הזה בדפדפן. לא צריך להתקין שום דבר.
הגדרת 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
הפעלת ממשקי API
מפעילים את כל השירותים הנדרשים:
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 מועבר כמשתנה הסביבה
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 בדוגמה הזו. כך מוודאים ש-2 מאגרי תגים יפעלו עבור 2 כתובות ה-URL שאנחנו רוצים לעבד.
כל משימה יכולה לפעול עד 24 שעות. אפשר לקצר את משך הזמן הזה באמצעות הדגל --task-timeout, כמו בדוגמה הזו. כדי שהעבודה תושלם בהצלחה, כל המשימות צריכות להצליח. כברירת מחדל, לא מתבצע ניסיון חוזר של משימות שנכשלו. אפשר להגדיר ניסיון חוזר של משימות שנכשלו. אם מספר הניסיונות החוזרים של משימה מסוימת חורג מהמספר המקסימלי, העבודה כולה נכשלת.
כברירת מחדל, העבודה תופעל עם כמה שיותר משימות במקביל. הערך הזה יהיה שווה למספר המשימות בעבודה, עד למקסימום של 100. יכול להיות שתרצו להגדיר רמת מקביליות נמוכה יותר למשימות שמתבצעת בהן גישה לחלק האחורי של האתר עם יכולת הרחבה מוגבלת. לדוגמה, מסד נתונים שתומך במספר מוגבל של חיבורים פעילים. אפשר להקטין את רמת ההקביליות באמצעות הדגל --parallelism.
6. הרצת משימה
לפני שמריצים את העבודה, מריצים את הפקודה list כדי לוודא שהיא נוצרה:
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 jobs ב-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 jobs ולוחצים על הקטע Triggers:

לוחצים על הלחצן Add Scheduler Trigger:

חלונית תיפתח בצד שמאל. יוצרים עבודה ב-Scheduler שתפעל כל יום בשעה 9:00 עם ההגדרה הזו ובוחרים באפשרות Continue:

בדף הבא, בוחרים את חשבון השירות שמוגדר כברירת מחדל ב-Compute ולוחצים על Create:

עכשיו אמור להופיע טריגר חדש של Cloud Scheduler שיצרתם:

לוחצים על View Details כדי לעבור לדף Cloud Scheduler.
אפשר לחכות עד השעה 9:00 כדי שהכלי לתזמון יתחיל לפעול, או להפעיל את Cloud Scheduler באופן ידני על ידי בחירת Force Run:

אחרי כמה שניות, אמורה להופיע הודעה שהמשימה של Cloud Scheduler בוצעה בהצלחה:

בנוסף, אמורים להופיע עוד 3 צילומי מסך שנוספו לשיחה מ-Cloud Scheduler:

9. מזל טוב
כל הכבוד, סיימתם את ה-Codelab!
ניקוי (אופציונלי)
כדי להימנע מחיובים, מומלץ למחוק את המשאבים.
אם לא צריך את הפרויקט, אפשר פשוט למחוק אותו:
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.