תמונה יומית: שיעור Lab 5 – ניקוי לאחר מחיקת התמונה

1. סקירה כללית

בשיעור ה-Lab הזה, תיצרו שירות חדש של Cloud Run, image garbage collector, שיופעל על ידי Eventarc, שירות חדש לקבלת אירועים ב-Cloud Run. כשמוחקים תמונה ממאגר התמונות, השירות מקבל אירוע מ-Eventarc. לאחר מכן, התמונה נמחקת ממאגר התמונות הממוזערות ומוסרת גם מאוסף התמונות של Firestore.

d93345bfc235f81e.png

מה תלמדו

  • Cloud Run
  • Cloud Storage
  • Cloud Firestore
  • Eventarc

2. הגדרה ודרישות

הגדרת סביבה בקצב אישי

  1. נכנסים ל-מסוף Google Cloud ויוצרים פרויקט חדש או משתמשים בפרויקט קיים. אם עדיין אין לכם חשבון Gmail או Google Workspace, אתם צריכים ליצור חשבון.

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

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

מפעילים את Cloud Shell

אפשר להפעיל את Google Cloud מרחוק מהמחשב הנייד, אבל ב-codelab הזה תשתמשו ב-Google Cloud Shell, סביבת שורת פקודה שפועלת בענן.

ב-GCP Console, לוחצים על סמל Cloud Shell בסרגל הכלים שבפינה הימנית העליונה:

bce75f34b2c53987.png

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

f6ef2b5f13479f3a.png

המכונה הווירטואלית הזו כוללת את כל הכלים שדרושים למפתחים. יש בה ספריית בית בנפח מתמיד של 5GB והיא פועלת ב-Google Cloud, מה שמשפר מאוד את הביצועים והאימות ברשת. אפשר לבצע את כל העבודה ב-Lab הזה רק באמצעות דפדפן.

3. מבוא ל-Eventarc

‫Eventarc מאפשר לחבר בקלות שירותי Cloud Run לאירועים ממגוון מקורות. הוא מטפל בהטמעה, בשליחה, באבטחה, בהרשאה ובטיפול בשגיאות של אירועים.

776ed63706ca9683.png

אתם יכולים לשלוף אירועים ממקורות של Google Cloud ומאפליקציות בהתאמה אישית שמתפרסמות ב-Cloud Pub/Sub, ולהעביר אותם ליעדים (sinks) של Google Cloud Run.

אירועים ממגוון רחב של מקורות ב-Google Cloud מועברים באמצעות יומני הביקורת של Cloud. הזמן שחולף בין התרחשות האירוע לבין הדיווח עליו והזמינות של דיווח האירועים מהמקורות האלה קשורים לאלה של יומני הביקורת של Cloud. בכל פעם שמופעל אירוע ממקור ב-Google Cloud, נוצרת רשומה תואמת ביומן הביקורת של Cloud.

אפליקציות בהתאמה אישית שמפרסמות ב-Cloud Pub/Sub יכולות לפרסם הודעות בנושא ב-Pub/Sub שהן מציינות בכל פורמט.

טריגרים של אירועים הם מנגנון הסינון שמאפשר לציין אילו אירועים יועברו לאיזה יעד.

כל האירועים מועברים בפורמט CloudEvents v1.0 כדי לאפשר יכולת פעולה הדדית בין שירותים שונים.

4. לפני שמתחילים

הפעלת ממשקי ה-API

תצטרכו את שירות Eventarc כדי להפעיל את שירות Cloud Run. מוודאים שהיא מופעלת:

gcloud services enable eventarc.googleapis.com

הפעולה אמורה להסתיים בהצלחה:

Operation "operations/acf.5c5ef4f6-f734-455d-b2f0-ee70b5a17322" finished successfully.

הגדרת חשבונות שירות

הטריגרים ישתמשו בחשבון השירות שמוגדר כברירת מחדל ל-Compute. מקצים את התפקיד eventarc.eventReceiver לחשבון השירות שמוגדר כברירת מחדל ב-Compute:

PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format='value(projectNumber)')

gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
    --member serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com \
    --role roles/eventarc.eventReceiver

מקצים את התפקיד pubsub.publisher לחשבון השירות של Cloud Storage. ההרשאה הזו נדרשת לטריגר של Cloud Storage ב-Eventarc:

SERVICE_ACCOUNT=$(gsutil kms serviceaccount -p $PROJECT_NUMBER)

gcloud projects add-iam-policy-binding $PROJECT_NUMBER \
    --member serviceAccount:$SERVICE_ACCOUNT \
    --role roles/pubsub.publisher

אם הפעלתם את חשבון השירות של Pub/Sub ב-8 באפריל 2021 או לפני כן, צריך להקצות את התפקיד iam.serviceAccountTokenCreator לחשבון השירות של Pub/Sub:

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member serviceAccount:service-$PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com \
  --role roles/iam.serviceAccountTokenCreator

5. שיבוט הקוד

משכפלים את הקוד, אם עדיין לא עשיתם את זה בסדנת הקוד הקודמת:

git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop

אחר כך עוברים לספרייה שמכילה את השירות:

cd serverless-photosharing-workshop/services/garbage-collector/nodejs

הפריסה של הקובץ בשירות תהיה כזו:

services
 |
 ├── garbage-collector
      |
      ├── nodejs
           |
           ├── index.js
           ├── package.json

בתוך התיקייה יש 3 קבצים:

  • index.js מכיל את קוד Node.js
  • package.json מגדיר את יחסי התלות של הפרויקט בספריות

6. הסבר על הקוד

תלות

בקובץ package.json מוגדרים יחסי התלות בספריות הנדרשות:

{
  "name": "garbage_collector_service",
  "version": "0.0.1",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "dependencies": {
    "cloudevents": "^4.0.1",
    "express": "^4.17.1",
    "@google/events": "^3.1.0",
    "@google-cloud/firestore": "^4.9.9",
    "@google-cloud/storage": "^5.8.3"
  }
}

אנחנו מסתמכים על ספריית Cloud Storage כדי למחוק תמונות ב-Cloud Storage. אנחנו מגדירים תלות ב-Cloud Firestore, כדי למחוק גם את המטא-נתונים של התמונות ששמרנו קודם. בנוסף, אנחנו מסתמכים על CloudEvents SDK ועל ספריות Google Events כדי לקרוא את CloudEvents שנשלחים על ידי Eventarc. ‫Express היא מסגרת אינטרנט של JavaScript / Node. ‫Bluebird משמש לטיפול בהבטחות.

index.js

בואו נבחן את הקוד index.js:

const express = require('express');
const {Storage} = require('@google-cloud/storage');
const Firestore = require('@google-cloud/firestore');
const { HTTP } = require("cloudevents");
const {toStorageObjectData} = require('@google/events/cloud/storage/v1/StorageObjectData');

אנחנו צריכים את התלות השונות שנדרשות להפעלת התוכנית שלנו: Express הוא מסגרת האינטרנט של Node שבה נשתמש, Bluebird היא ספרייה לטיפול בהבטחות של JavaScript, ‏ Storage ו-Firestore משמשים לעבודה עם Google Cloud Storage (הקטגוריות של התמונות שלנו) ומאגר הנתונים של Cloud Firestore, בהתאמה. בנוסף, אנחנו דורשים מ-CloudEvent לקרוא את CloudEvent שנשלח על ידי Eventarc StoreObjectData מספריית Google Events כדי לקרוא את גוף האירוע של Cloud Storage ב-CloudEvent.

const app = express();
app.use(express.json());

app.post('/', async (req, res) => {
    try {
        const cloudEvent = HTTP.toEvent({ headers: req.headers, body: req.body });
        console.log(cloudEvent);


        /* ... */

    } catch (err) {
        console.log(`Error: ${err}`);
        res.status(500).send(err);
    }
});

למעלה אפשר לראות את המבנה של ה-handler של Node: האפליקציה שלנו מגיבה לבקשות HTTP POST. הפונקציה קוראת את CloudEvent מבקשת ה-HTTP, ואנחנו מבצעים טיפול בשגיאות למקרה שמשהו ישתבש. עכשיו נבדוק מה יש בתוך המבנה הזה.

השלב הבא הוא לאחזר ולנתח את גוף ה-CloudEvent ולאחזר את שם האובייקט:

const storageObjectData = toStorageObjectData(cloudEvent.data);
console.log(storageObjectData);

const objectName = storageObjectData.name;

אחרי שנדע את שם התמונה, נוכל למחוק אותה ממאגר התמונות הממוזערות:

try {
    await storage.bucket(bucketThumbnails).file(objectName).delete();
    console.log(`Deleted '${objectName}' from bucket '${bucketThumbnails}'.`);
}
catch(err) {
    console.log(`Failed to delete '${objectName}' from bucket '${bucketThumbnails}': ${err}.`);
}

בשלב האחרון, מוחקים גם את המטא-נתונים של התמונה מהאוסף ב-Firestore:

try {
    const pictureStore = new Firestore().collection('pictures');
    const docRef = pictureStore.doc(objectName);
    await docRef.delete();

    console.log(`Deleted '${objectName}' from Firestore collection 'pictures'`);
}
catch(err) {
    console.log(`Failed to delete '${objectName}' from Firestore: ${err}.`);
}

res.status(200).send(`Processed '${objectName}'.`);

עכשיו צריך לגרום לסקריפט Node להאזין לבקשות נכנסות. כדאי גם לבדוק שמשתני הסביבה הנדרשים מוגדרים:

app.listen(PORT, () => {
    if (!bucketThumbnails) throw new Error("BUCKET_THUMBNAILS not set");
    console.log(`Started service on port ${PORT}`);
});

7. בדיקה מקומית

בודקים את הקוד באופן מקומי כדי לוודא שהוא פועל לפני הפריסה לענן.

בתיקייה garbage-collector/nodejs, מתקינים את יחסי התלות של npm ומפעילים את השרת:

export BUCKET_THUMBNAILS=thumbnails-$GOOGLE_CLOUD_PROJECT

npm install; npm start

אם הכול עבר בצורה חלקה, השרת אמור להתחיל לפעול ביציאה 8080:

Started service on port 8080

כדי לצאת, לוחצים על CTRL-C.

8. פיתוח ופריסה ב-Cloud Run

לפני שמבצעים פריסה ב-Cloud Run, צריך להגדיר את האזור ב-Cloud Run לאחד מהאזורים הנתמכים ואת הפלטפורמה ל-managed:

REGION=europe-west1
gcloud config set run/region $REGION
gcloud config set run/platform managed

כדי לבדוק שההגדרה מוגדרת:

gcloud config list

...
[run]
platform = managed
region = europe-west1

במקום ליצור ולפרסם את קובץ האימג' של הקונטיינר באופן ידני באמצעות Cloud Build, אפשר גם להסתמך על Cloud Run כדי ליצור את קובץ האימג' של הקונטיינר באמצעות Google Cloud Buildpacks.

מריצים את הפקודה הבאה כדי ליצור את קובץ האימג' של הקונטיינר באמצעות Google Cloud Buildpacks, ואז פורסים את קובץ האימג' של הקונטיינר ב-Cloud Run:

SERVICE_NAME=garbage-collector-service

gcloud run deploy $SERVICE_NAME \
    --source . \
    --no-allow-unauthenticated \
    --update-env-vars BUCKET_THUMBNAILS=$BUCKET_THUMBNAILS

שימו לב לדגל –-source. הדגל הזה מציין ל-Cloud Run להשתמש ב-Buildpacks של Google Cloud כדי ליצור את אימג' הקונטיינר בלי Dockerfile. הדגל --no-allow-unauthenticated הופך את שירות Cloud Run לשירות פנימי שיופעל רק על ידי חשבונות שירות ספציפיים. בהמשך, תיצרו טריגר עם חשבון השירות שמוגדר כברירת מחדל בשביל שירותי מחשוב, עם התפקיד run.invoker, כדי לקרוא לשירותי Cloud Run פנימיים.

9. יצירת טריגר

ב-Eventarc, טריגר מגדיר לאיזה שירות צריך להעביר אירועים מסוג מסוים. במקרה הזה, רוצים שהשירות יקבל אירועים כשקובץ נמחק מקטגוריה.

מגדירים את המיקום של ה-Trigger באותו אזור שבו נמצאת הקטגוריה של התמונות שהועלו:

gcloud config set eventarc/location eu

יוצרים טריגר AuditLog כדי לסנן אירועים מסוג storage.objects.delete ולשלוח אותם לשירות Cloud Run:

BUCKET_IMAGES=uploaded-pictures-$GOOGLE_CLOUD_PROJECT

gcloud eventarc triggers create trigger-$SERVICE_NAME \
  --destination-run-service=$SERVICE_NAME \
  --destination-run-region=$REGION \
  --event-filters="type=google.cloud.storage.object.v1.deleted" \
  --event-filters="bucket=$BUCKET_IMAGES" \
  --service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com

אפשר לבדוק שוב שגורם ההפעלה נוצר באמצעות הפקודה הזו:

gcloud eventarc triggers list

10. בדיקת השירות

כדי לבדוק אם השירות פועל, עוברים אל מאגר uploaded-pictures ומוחקים אחת מהתמונות. ברישומים של השירות אמורה להופיע הודעה על כך שהתמונה הרלוונטית נמחקה ממאגר thumbnails ושהמסמך שלה נמחק מאוסף pictures Firestore.

519abf90e7ea4d12.png

11. ניקוי (אופציונלי)

אם אתם לא מתכוונים להמשיך עם שאר המעבדות בסדרה, מומלץ לנקות את המשאבים כדי לחסוך בעלויות ולשמור על סביבת ענן נקייה. כדי לנקות משאבים בנפרד, פועלים לפי השלבים הבאים.

מוחקים את השירות:

gcloud run services delete $SERVICE_NAME -q

מחיקת הטריגר של Eventarc:

gcloud eventarc triggers delete trigger-$SERVICE_NAME -q

אפשר גם למחוק את כל הפרויקט:

gcloud projects delete $GOOGLE_CLOUD_PROJECT

12. מעולה!

מעולה! יצרתם שירות Cloud Run, מנקה קבצים זמניים של תמונות, שמופעל על ידי Eventarc, שירות חדש לקבלת אירועים ב-Cloud Run. כשמוחקים תמונה ממאגר התמונות, השירות מקבל אירוע מ-Eventarc. לאחר מכן, התמונה נמחקת ממאגר התמונות הממוזערות ומוסרת גם מאוסף התמונות של Firestore.

מה נכלל

  • Cloud Run
  • Cloud Storage
  • Cloud Firestore
  • Eventarc