1. סקירה כללית
בשיעור ה-Lab הזה תיצרו שירות חדש של Cloud Run, שירות קולאז', שיופעל על ידי Cloud Scheduler במרווחי זמן קבועים. השירות מאחזר את התמונות האחרונות שהועלו ויוצר מהן קולאז': הוא מוצא את רשימת התמונות האחרונות ב-Cloud Firestore, ואז מוריד את קובצי התמונות בפועל מ-Cloud Storage.

מה תלמדו
- Cloud Run
- Cloud Scheduler
- Cloud Storage
- Cloud Firestore
2. הגדרה ודרישות
הגדרת סביבה בקצב אישי
- נכנסים ל-מסוף Google Cloud ויוצרים פרויקט חדש או משתמשים בפרויקט קיים. אם עדיין אין לכם חשבון Gmail או Google Workspace, אתם צריכים ליצור חשבון.



- שם הפרויקט הוא השם המוצג למשתתפים בפרויקט. זו מחרוזת של תווים שלא נמצאת בשימוש ב-Google APIs, ואפשר לעדכן אותה בכל שלב.
- מזהה הפרויקט חייב להיות ייחודי לכל הפרויקטים ב-Google Cloud, והוא קבוע (אי אפשר לשנות אותו אחרי שהוא מוגדר). מסוף Cloud יוצר באופן אוטומטי מחרוזת ייחודית. בדרך כלל לא צריך לדעת מה היא. ברוב סדנאות ה-Codelab, תצטרכו להפנות למזהה הפרויקט (ובדרך כלל הוא מזוהה כ-
PROJECT_ID), אז אם אתם לא אוהבים אותו, תוכלו ליצור מזהה אקראי אחר, או לנסות ליצור מזהה משלכם ולראות אם הוא זמין. אחרי שהפרויקט נוצר, הוא 'קפוא'. - יש ערך שלישי, מספר פרויקט, שמשמש חלק מממשקי ה-API. מידע נוסף על שלושת הערכים האלה מופיע במאמרי העזרה.
- בשלב הבא, תצטרכו להפעיל את החיוב במסוף Cloud כדי להשתמש במשאבי Cloud או בממשקי API. העלות של התרגול הזה לא אמורה להיות גבוהה, ואולי לא תהיה עלות בכלל. כדי לכבות את המשאבים ולא לחייב אתכם מעבר למה שמוסבר במדריך הזה, צריך לפעול לפי ההוראות לניקוי שמופיעות בסוף ה-Codelab. משתמשים חדשים ב-Google Cloud זכאים לתוכנית תקופת ניסיון בחינם בשווי 300$.
מפעילים את Cloud Shell
אפשר להפעיל את Google Cloud מרחוק מהמחשב הנייד, אבל ב-Codelab הזה נשתמש ב-Google Cloud Shell, סביבת שורת פקודה שפועלת בענן.
ב-GCP Console, לוחצים על סמל Cloud Shell בסרגל הכלים שבפינה הימנית העליונה:

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

המכונה הווירטואלית הזו כוללת את כל הכלים שדרושים למפתחים. יש בה ספריית בית בנפח מתמיד של 5GB והיא פועלת ב-Google Cloud, מה שמשפר מאוד את הביצועים והאימות ברשת. אפשר לבצע את כל העבודה ב-Lab הזה רק באמצעות דפדפן.
3. הפעלת ממשקי ה-API
תצטרכו Cloud Scheduler כדי להפעיל את שירות Cloud Run במרווחי זמן קבועים. מוודאים שהיא מופעלת:
gcloud services enable cloudscheduler.googleapis.com
הפעולה אמורה להסתיים בהצלחה:
Operation "operations/acf.5c5ef4f6-f734-455d-b2f0-ee70b5a17322" finished successfully.
4. שיבוט הקוד
משכפלים את הקוד, אם עדיין לא עשיתם את זה בסדנת הקוד הקודמת:
git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop
אחר כך עוברים לספרייה שמכילה את השירות:
cd serverless-photosharing-workshop/services/collage/nodejs
הפריסה של הקובץ עבור השירות תהיה כזו:
services
|
├── collage
|
├── nodejs
|
├── Dockerfile
├── index.js
├── package.json
בתוך התיקייה יש 3 קבצים:
-
index.jsמכיל את קוד Node.js -
package.jsonמגדיר את יחסי התלות של הפרויקט בספריות -
Dockerfileמגדיר את קובץ האימג' של הקונטיינר
5. הסבר על הקוד
תלות
בקובץ package.json מוגדרים יחסי התלות בספריות הנדרשות:
{
"name": "collage_service",
"version": "0.0.1",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"bluebird": "^3.7.2",
"express": "^4.17.1",
"imagemagick": "^0.1.3",
"@google-cloud/firestore": "^4.9.9",
"@google-cloud/storage": "^5.8.3"
}
}
אנחנו מסתמכים על ספריית Cloud Storage כדי לקרוא ולשמור קובצי תמונה ב-Cloud Storage. אנחנו מגדירים תלות ב-Cloud Firestore כדי לאחזר מטא-נתונים של תמונות ששמרנו קודם. Express היא מסגרת אינטרנט של JavaScript / Node. Bluebird משמש לטיפול בהבטחות, ו-imagemagick היא ספריה לשינוי תמונות.
קובץ Docker
Dockerfile מגדיר את קובץ האימג' בקונטיינר של האפליקציה:
FROM node:14-slim
# installing Imagemagick
RUN set -ex; \
apt-get -y update; \
apt-get -y install imagemagick; \
rm -rf /var/lib/apt/lists/*
WORKDIR /picadaily/services/collage
COPY package*.json ./
RUN npm install --production
COPY . .
CMD [ "npm", "start" ]
אנחנו משתמשים בתמונת בסיס קלה של Node 14. אנחנו מתקינים את ספריית imagemagick. לאחר מכן אנחנו מתקינים את מודולי ה-NPM שנדרשים לקוד שלנו, ומריצים את קוד הצומת באמצעות npm start.
index.js
בואו נבחן את הקוד index.js:
const express = require('express');
const imageMagick = require('imagemagick');
const Promise = require("bluebird");
const path = require('path');
const {Storage} = require('@google-cloud/storage');
const Firestore = require('@google-cloud/firestore');
אנחנו צריכים את התלויות השונות שנדרשות להרצת התוכנית שלנו: Express הוא מסגרת האינטרנט של Node שבה נשתמש, ImageMagick היא הספרייה לביצוע מניפולציות על תמונות, Bluebird היא ספרייה לטיפול בהבטחות של JavaScript, Path משמשת לטיפול בנתיבים של קבצים וספריות, ו-Storage ו-Firestore משמשות לעבודה עם Google Cloud Storage (המאגרים שלנו של תמונות) ומאגר הנתונים של Cloud Firestore, בהתאמה.
const app = express();
app.get('/', async (req, res) => {
try {
console.log('Collage request');
/* ... */
} catch (err) {
console.log(`Error: creating the collage: ${err}`);
console.error(err);
res.status(500).send(err);
}
});
למעלה אפשר לראות את המבנה של ה-handler של Node: האפליקציה שלנו מגיבה לבקשות HTTP GET. אנחנו גם מבצעים טיפול בשגיאות למקרה שמשהו ישתבש. עכשיו נבדוק מה יש בתוך המבנה הזה.
const thumbnailFiles = [];
const pictureStore = new Firestore().collection('pictures');
const snapshot = await pictureStore
.where('thumbnail', '==', true)
.orderBy('created', 'desc')
.limit(4).get();
if (snapshot.empty) {
console.log('Empty collection, no collage to make');
res.status(204).send("No collage created.");
} else {
/* ... */
}
כדי ליצור קולאז', צריך להעלות לפחות 4 תמונות (שנוצרו להן תמונות ממוזערות).
אנחנו מאחזרים את 4 התמונות האחרונות שהועלו על ידי המשתמשים שלנו, מתוך המטא-נתונים שמאוחסנים ב-Cloud Firestore. אנחנו בודקים אם האוסף שנוצר ריק או לא, ואז ממשיכים הלאה בענף else של הקוד.
נאסוף את רשימת שמות הקבצים:
snapshot.forEach(doc => {
thumbnailFiles.push(doc.id);
});
console.log(`Picture file names: ${JSON.stringify(thumbnailFiles)}`);
אנחנו הולכים להוריד כל אחד מהקבצים האלה ממאגר התמונות הממוזערות, שהשם שלו מגיע ממשתנה סביבה שהגדרנו בזמן הפריסה:
const thumbBucket = storage.bucket(process.env.BUCKET_THUMBNAILS);
await Promise.all(thumbnailFiles.map(async fileName => {
const filePath = path.resolve('/tmp', fileName);
await thumbBucket.file(fileName).download({
destination: filePath
});
}));
console.log('Downloaded all thumbnails');
אחרי העלאת התמונות הממוזערות העדכניות, נשתמש בספריית ImageMagick כדי ליצור רשת של 4x4 של התמונות הממוזערות האלה. אנחנו משתמשים בספריית Bluebird וביישום Promise שלה כדי להפוך את הקוד מבוסס הקריאה החוזרת לקוד ידידותי ל-async / await, ואז אנחנו ממתינים להבטחה שיוצרת את קולאז' התמונות:
const collagePath = path.resolve('/tmp', 'collage.png');
const thumbnailPaths = thumbnailFiles.map(f => path.resolve('/tmp', f));
const convert = Promise.promisify(im.convert);
await convert([
'(', ...thumbnailPaths.slice(0, 2), '+append', ')',
'(', ...thumbnailPaths.slice(2), '+append', ')',
'-size', '400x400', 'xc:none', '-background', 'none', '-append',
collagePath]);
console.log("Created local collage picture");
תמונת הקולאז' נשמרה בדיסק באופן מקומי בתיקייה הזמנית, ועכשיו צריך להעלות אותה ל-Cloud Storage ולהחזיר תגובה של הצלחה (קוד סטטוס 2xx):
await thumbBucket.upload(collagePath);
console.log("Uploaded collage to Cloud Storage bucket ${process.env.BUCKET_THUMBNAILS}");
res.status(204).send("Collage created.");
עכשיו צריך לגרום לסקריפט Node להאזין לבקשות נכנסות:
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Started collage service on port ${PORT}`);
});
בסוף קובץ המקור, יש הוראות להפעלת אפליקציית האינטרנט שלנו ב-Express ביציאה 8080 שמוגדרת כברירת מחדל.
6. בדיקה מקומית
בודקים את הקוד באופן מקומי כדי לוודא שהוא פועל לפני הפריסה לענן.
בתיקייה collage/nodejs, מתקינים את יחסי התלות של npm ומפעילים את השרת:
npm install; npm start
אם הכול עבר בצורה חלקה, השרת אמור להתחיל לפעול ביציאה 8080:
Started collage service on port 8080
כדי לצאת, לוחצים על CTRL-C.
7. פיתוח ופריסה ב-Cloud Run
לפני שמבצעים פריסה ב-Cloud Run, צריך להגדיר את האזור של Cloud Run לאחד מהאזורים הנתמכים ואת הפלטפורמה ל-managed:
gcloud config set run/region europe-west1 gcloud config set run/platform managed
כדי לבדוק שההגדרה מוגדרת:
gcloud config list ... [run] platform = managed region = europe-west1
במקום ליצור ולפרסם את קובץ האימג' של הקונטיינר באופן ידני באמצעות Cloud Build, אפשר גם להסתמך על Cloud Run כדי ליצור את קובץ האימג' של הקונטיינר באמצעות Google Cloud Buildpacks.
מריצים את הפקודה הבאה כדי ליצור את קובץ האימג' של הקונטיינר:
BUCKET_THUMBNAILS=thumbnails-$GOOGLE_CLOUD_PROJECT
SERVICE_NAME=collage-service
gcloud run deploy $SERVICE_NAME \
--source . \
--no-allow-unauthenticated \
--update-env-vars BUCKET_THUMBNAILS=$BUCKET_THUMBNAILS
שימו לב לסימון –-source. זוהי פריסה שמבוססת על קוד מקור ב-Cloud Run. אם קובץ Dockerfile נמצא בספריית קוד המקור, קוד המקור שהועלה ייבנה באמצעות קובץ Dockerfile הזה. אם אין Dockerfile בספריית קוד המקור, חבילות ה-Buildpack של Google Cloud מזהות באופן אוטומטי את השפה שבה אתם משתמשים ומאחזרות את התלויות של הקוד כדי ליצור קובץ אימג' של קונטיינר שמוכן לייצור, באמצעות קובץ אימג' בסיסי מאובטח שמנוהל על ידי Google. הפעולה הזו מסמנת ל-Cloud Run להשתמש ב-Google Cloud Buildpacks כדי ליצור את קובץ האימג' של הקונטיינר שמוגדר ב-Dockerfile.
חשוב גם לציין שפריסה מבוססת-מקור משתמשת ב-Artifact Registry כדי לאחסן קונטיינרים שנבנו. Artifact Registry היא גרסה מודרנית של Google Container Registry. אם ה-API לא מופעל בפרויקט, ה-CLI יציג בקשה להפעיל אותו, וייצור מאגר בשם cloud-run-source-deploy באזור שבו אתם מבצעים את הפריסה.
הדגל --no-allow-unauthenticated הופך את שירות Cloud Run לשירות פנימי שיופעל רק על ידי חשבונות שירות ספציפיים.
8. הגדרת Cloud Scheduler
עכשיו, אחרי שהשירות ב-Cloud Run מוכן ונפרס, הגיע הזמן ליצור את לוח הזמנים הקבוע להפעלת השירות מדי דקה.
יוצרים חשבון שירות:
SERVICE_ACCOUNT=collage-scheduler-sa gcloud iam service-accounts create $SERVICE_ACCOUNT \ --display-name "Collage Scheduler Service Account"
נותנים לחשבון השירות הרשאה להפעיל את שירות Cloud Run:
gcloud run services add-iam-policy-binding $SERVICE_NAME \ --member=serviceAccount:$SERVICE_ACCOUNT@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \ --role=roles/run.invoker
יוצרים משימה של Cloud Scheduler שתופעל כל דקה:
SERVICE_URL=$(gcloud run services describe $SERVICE_NAME --format 'value(status.url)') gcloud scheduler jobs create http $SERVICE_NAME-job --schedule "* * * * *" \ --http-method=GET \ --location=europe-west1 \ --uri=$SERVICE_URL \ --oidc-service-account-email=$SERVICE_ACCOUNT@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \ --oidc-token-audience=$SERVICE_URL
אפשר לעבור לקטע Cloud Scheduler ב-Cloud Console כדי לראות שהוא מוגדר ומפנה לכתובת ה-URL של שירות Cloud Run:

9. בדיקת השירות
כדי לבדוק אם ההגדרה פועלת, בודקים בדלי thumbnails אם יש תמונה של קולאז' (בשם collage.png). אפשר גם לבדוק את היומנים של השירות:
10. ניקוי (אופציונלי)
אם אתם לא מתכוונים להמשיך עם שאר המעבדות בסדרה, אתם יכולים לנקות את המשאבים כדי לחסוך בעלויות ולשמור על סביבת ענן נקייה. כדי לנקות משאבים בנפרד, פועלים לפי השלבים הבאים.
מוחקים את השירות:
gcloud run services delete $SERVICE_NAME -q
מחיקת המשימה ב-Cloud Scheduler:
gcloud scheduler jobs delete $SERVICE_NAME-job -q
אפשר גם למחוק את כל הפרויקט:
gcloud projects delete $GOOGLE_CLOUD_PROJECT
11. מעולה!
מעולה! יצרתם שירות מתוזמן: הודות ל-Cloud Scheduler, שדוחף הודעה כל דקה בנושא Pub/Sub, שירות הקולאז' של Cloud Run מופעל ויכול לצרף תמונות יחד כדי ליצור את התמונה שמתקבלת.
מה נכלל
- Cloud Run
- Cloud Scheduler
- Cloud Storage
- Cloud Firestore