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

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

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

d93345bfc235f81e.png

מה תלמדו

  • Cloud Run
  • Cloud Storage
  • Cloud Firestore
  • Eventarc

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

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

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

96a9c957bc475304.pngb9a10ebdf5b5a448.pnga1e3c01a38fa61c2.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, ולהעביר אותם ליעדים של 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.

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

חשבון השירות שמוגדר כברירת מחדל לחישוב ישמש בטריגרים. מקצים את התפקיד 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 או לפני כן, צריך להקצות לחשבון השירות של Pub/Sub את התפקיד iam.serviceAccountTokenCreator:

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 כדי לקרוא את 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 להשתמש ב-Google Cloud Buildpacks כדי ליצור את קובץ האימג' של הקונטיינר בלי Dockerfile. הדגל --no-allow-unauthenticated הופך את שירות Cloud Run לשירות פנימי שיופעל רק על ידי חשבונות שירות ספציפיים. בהמשך, תיצרו טריגר עם חשבון השירות שמוגדר כברירת מחדל בשביל שירותי מחשוב, עם התפקיד run.invoker, כדי לבצע קריאה לשירותי Cloud Run פנימיים.

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

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

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

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