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 שלה כדי להפוך את הקוד מבוסס-callback לקוד ידידותי ל-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