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 ויוצרים פרויקט חדש או משתמשים בפרויקט קיים. אם עדיין אין לכם חשבון 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, סביבת שורת פקודה שפועלת בענן.
ב-מסוף Google Cloud, לוחצים על סמל 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. הסבר על הקוד
כדי לעיין בקוד, משתמשים בכלי לעריכת טקסט שמוטמע בחלון Cloud Shell. לשם כך, לוחצים על הלחצן 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. הקוד שלכם אחראי לקבוע איזה task מטפל באיזה קבוצת משנה של הנתונים. שימו לב ל---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 ולוחצים על הקטע Triggers:

לוחצים על הכפתור Add Scheduler Trigger:

חלונית תיפתח בצד שמאל. יוצרים עבודה במתזמן המשימות שתפעל כל יום בשעה 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.