תמונה יומית: מעבדה 6 – תזמור עם תהליכי עבודה

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

בשיעורי ה-Lab הקודמים, פיתחתם גרסה מבוססת-אירועים של אפליקציית Pic-a-daily שהשתמשה ב-Google Cloud Storage שהפעילה את הפונקציה של Cloud Functions עבור שירות ניתוח התמונות, GCS שהפעיל קונטיינר Cloud Run דרך Pub/Sub לשירות תמונות ממוזערות ו-Eventarc כדי להפעיל את השירות Image Garbage Collector ב-Cloud Run. הופעל גם שירות Cloud Scheduler ליצירת קולאז'ים:

d93345bfc235f81e.png

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

b763efcbf5589747.png

מה תלמדו

  • App Engine
  • Cloud Firestore
  • Cloud Functions
  • Cloud Run
  • תהליכי עבודה

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

הגדרת סביבה בקצב עצמאי

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

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

חשוב לזכור את מזהה הפרויקט, שם ייחודי לכל הפרויקטים ב-Google Cloud (השם שלמעלה כבר תפוס ולא מתאים לכם, סליחה). בהמשך ב-Codelab הזה, היא תיקרא PROJECT_ID.

  1. בשלב הבא צריך להפעיל את החיוב במסוף Cloud כדי להשתמש במשאבים של Google Cloud.

מעבר ב-Codelab הזה לא אמור לעלות הרבה, אם בכלל. חשוב לבצע את כל ההוראות בקטע 'ניקוי' שמסביר איך להשבית משאבים כדי שלא תצברו חיובים מעבר למדריך הזה. משתמשים חדשים ב-Google Cloud זכאים להצטרף לתוכנית תקופת ניסיון בחינם בשווי 1,200 ש"ח.

הפעלת Cloud Shell

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

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

bce75f34b2c53987.png

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

f6ef2b5f13479f3a.png

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

3. מבוא לתהליכי עבודה

90fcd42d556e310e.jpeg

אפשר להשתמש בתהליכי עבודה כדי ליצור תהליכי עבודה ללא שרת (serverless) שמקשרים יחד סדרה של משימות ללא שרת (serverless), לפי סדר ההגדרה. ההגדרה הזו מאפשרת לשלב את העוצמה של ממשקי ה-API של Google Cloud, מוצרים ללא שרת (serverless) כמו Cloud Functions ו-Cloud Run, וקריאות לממשקי API חיצוניים כדי ליצור אפליקציות גמישות ללא שרת (serverless).

כפי שאפשר לצפות מהתזמור, Workflows מאפשר להגדיר את זרימת הלוגיקה העסקית בשפה של הגדרת תהליך עבודה שמבוססת על YAML/JSON ומספק Workflows Execution API וממשק משתמש של Workflows כדי להפעיל את התהליכים האלה.

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

  • ביצוע גמיש של ניסיונות חוזרים וטיפול בשגיאות בין השלבים, כדי לבצע שלבים מהימנים.
  • ניתוח JSON והעברת משתנים בין שלבים כדי להימנע מקוד דבק.
  • נוסחאות ביטויים להחלטות מאפשרות ביצוע מותנים של שלבים.
  • תהליכי עבודה משניים לתהליכי עבודה מודולריים ולשימוש חוזר.
  • תמיכה בשירותים חיצוניים מאפשרת לתזמור שירותים מחוץ ל-Google Cloud.
  • תמיכה באימות ב-Google Cloud ובשירותים חיצוניים לביצוע שלבים מאובטחים.
  • מחברים לשירותי Google Cloud כמו Pub/Sub, Firestore, Tasks ו-Secret Manager, לשילוב קל יותר.

וכמעט שכחנו: Workflows הוא מוצר מנוהל ללא שרת (serverless). אין שרתים שאפשר להגדיר או לשנות את קנה המידה שלהם, ואתם משלמים רק על השימוש שלכם.

4. הפעלת ממשקי API

בשיעור ה-Lab הזה תחברו שירותים של Cloud Functions ו-Cloud Run ל-Workflows. תשתמשו גם ב-App Engine, ב-Cloud Build, ב-Vision API ובשירותים אחרים.

מוודאים שכל השירותים הנחוצים ב-Cloud Shell מופעלים:

gcloud services enable \
  appengine.googleapis.com \
  cloudbuild.googleapis.com \
  cloudfunctions.googleapis.com \
  compute.googleapis.com \
  firestore.googleapis.com \
  run.googleapis.com \
  vision.googleapis.com \
  workflows.googleapis.com \

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

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

5. קבל את הקוד

מקבלים את הקוד, אם עדיין לא עשיתם זאת ב-Code Labs הקודמות:

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

יהיה לכם את מבנה התיקיות הבא שרלוונטי לשיעור ה-Lab:

frontend
 |
workflows
 |
 ├── functions
 ├── |── trigger-workflow
 ├── |── vision-data-transform
 ├── services
 ├── |── collage
 ├── |── thumbnails
 ├── workflows.yaml

התיקיות הרלוונטיות:

  • frontend מכיל את הקצה הקדמי של App Engine שבו נעשה שימוש חוזר משיעור Lab 4.
  • functions מכיל את ה-Cloud Functions שנוצרו בשביל תהליך העבודה.
  • services מכיל את שירותי Cloud Run ששונו עבור תהליך העבודה.
  • workflows.yaml הוא קובץ ההגדרה של תהליך העבודה.

6. התנסות ב-YAML של תהליכי עבודה

workflows.yaml מגדיר את תהליך העבודה בסדרה של שלבים. בואו נעבור עליו כדי להבין אותו טוב יותר.

בתחילת תהליך העבודה, יש כמה פרמטרים שמועברים. הן יועברו על ידי שתי פונקציות Cloud Functions שמפעילות את תהליכי העבודה. נתייחס לפונקציות האלה מאוחר יותר, אבל כך מתחילים תהליכי העבודה:

d44a5e18aa9d4660.png

ב-YAML אפשר לראות שהפרמטרים האלה מוקצים למשתנים בשלב init, כמו שמות הקובץ והקטגוריות שהקפיצו את האירוע, וכתובות URL של חלק משירותי Cloud Functions ושירותי Cloud Run שה-Workflows יקרא:

main:
  params: [args]
  steps:
    - init:
        assign:
          - file: ${args.file}
          - bucket: ${args.bucket}
          - gsUri: ${"gs://" + bucket + "/" + file}
          - projectId: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
          - urls: ${args.urls}

בשלב הבא, תהליכי עבודה בודקים את סוג האירוע. יש 2 סוגי אירועים נתמכים: object.finalize (נוצר כשקובץ נשמר בקטגוריה של אחסון בענן) ו-object.delete (יצירה של קובץ שנמחק). כל שינוי אחר יוביל לביטול של אירוע שלא נתמך.

dd1f450983655619.png

זה השלב בהגדרת תהליך העבודה של YAML, שבו אנחנו בודקים את הסוג של אירוע אחסון הקובץ:

    - eventTypeSwitch:
        switch:
            - condition: ${args.eventType == "google.storage.object.finalize"}
              next: imageAnalysisCall
            - condition: ${args.eventType == "google.storage.object.delete"}
              next: pictureGarbageCollectionGCS
    - eventTypeNotSupported:
        raise: ${"eventType " + args.eventType + " is not supported"}
        next: end

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

בשלב הבא נסתכל על imageAnalysisCall. זו סדרה של קריאות שנשלחות מ-Workflows ל-Vision API כדי לנתח את התמונה, לבצע טרנספורמציה בנתוני התגובה של Vision API כדי למיין את התוויות של הדברים שזוהו בתמונה, לבחור את הצבעים הדומיננטיים, לבדוק אם התמונה בטוחה להצגה ואז לשמור את המטא-נתונים ב-Cloud Firestore.

שימו לב שהכול מתבצע ב-Workflows מלבד Vision Transform Cloud Functions (שנפרס מאוחר יותר):

ca2ad16b9cbb436.png

כך נראים השלבים ב-YAML:

    - imageAnalysisCall:
        call: http.post
        args:
          url: https://vision.googleapis.com/v1/images:annotate
          headers:
            Content-Type: application/json
          auth:
            type: OAuth2
          body:
            requests:
            - image:
                source:
                  gcsImageUri: ${gsUri}
              features:
              - type: LABEL_DETECTION
              - type: SAFE_SEARCH_DETECTION
              - type: IMAGE_PROPERTIES
        result: imageAnalysisResponse
    - transformImageAnalysisData:
        call: http.post
        args:
          url: ${urls.VISION_DATA_TRANSFORM_URL}
          auth:
            type: OIDC
          body: ${imageAnalysisResponse.body}
        result: imageMetadata
    - checkSafety:
        switch:
          - condition: ${imageMetadata.body.safe == true}
            next: storeMetadata
        next: end
    - storeMetadata:
        call: http.request
        args:
          url: ${"https://firestore.googleapis.com/v1/projects/" + projectId + "/databases/(default)/documents/pictures/" + file + "?updateMask.fieldPaths=color&updateMask.fieldPaths=labels&updateMask.fieldPaths=created"}
          auth:
            type: OAuth2
          method: PATCH
          body:
            name: ${"projects/" + projectId + "/databases/(default)/documents/pictures/" + file}
            fields:
              color:
                stringValue: ${imageMetadata.body.color}
              created:
                timestampValue: ${imageMetadata.body.created}
              labels:
                arrayValue:
                  values: ${imageMetadata.body.labels}
        result: storeMetadataResponse

לאחר ניתוח התמונה, שני השלבים הבאים הם יצירת התמונה הממוזערת של התמונה וקולאז' של התמונות האחרונות. לשם כך, פורסים 2 שירותי Cloud Run ומבצעים קריאות אליהם משלבים thumbnailCall ו-collageCall:

76f9179323c3144.png

שלבים ב-YAML:

   - thumbnailCall:
        call: http.post
        args:
          url: ${urls.THUMBNAILS_URL}
          auth:
            type: OIDC
          body:
              gcsImageUri: ${gsUri}
        result: thumbnailResponse
    - collageCall:
        call: http.get
        args:
          url: ${urls.COLLAGE_URL}
          auth:
            type: OIDC
        result: collageResponse

הסתעפות הביצוע מסתיימת בהחזרת קודי סטטוס מכל שירות בשלב finalizeCompleted:

    - finalizeCompleted:
        return:
          imageAnalysis: ${imageAnalysisResponse.code}
          storeMetadata: ${storeMetadataResponse.code}
          thumbnail: ${thumbnailResponse.code}
          collage: ${collageResponse.code}

ההסתעפות השנייה של הביצוע היא כאשר קובץ נמחק מקטגוריית האחסון הראשית, המכילה את הגרסאות ברזולוציה הגבוהה של התמונות. בהסתעפות הזו, אנחנו רוצים למחוק את התמונה הממוזערת של התמונה בקטגוריה שמכילה את התמונות הממוזערות ולמחוק את המטא-נתונים שלה מ-Firestore. שני המדדים האלה מתבצעים באמצעות קריאות HTTP מ-Workflows:

f172379274dcb3c2.png

שלבים ב-YAML:

    - pictureGarbageCollectionGCS:
        try:
          call: http.request
          args:
            url: ${"https://storage.googleapis.com/storage/v1/b/thumbnails-" + projectId + "/o/" + file}
            auth:
              type: OAuth2
            method: DELETE
          result: gcsDeletionResult
        except:
          as: e
          steps:
              - dummyResultInOutVar:
                  assign:
                      - gcsDeletionResult:
                          code: 200
                          body: "Workaround for empty body response"
    - pictureGarbageCollectionFirestore:
        call: http.request
        args:
          url: ${"https://firestore.googleapis.com/v1/projects/" + projectId + "/databases/(default)/documents/pictures/" + file}
          auth:
            type: OAuth2
          method: DELETE
        result: firestoreDeletionResult

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

    - deleteCompleted:
        return:
          gcsDeletion: ${gcsDeletionResult}
          firestoreDeletion: ${firestoreDeletionResult.code}

בשלבים הבאים ניצור את כל יחסי התלות החיצוניים של תהליכי העבודה: קטגוריות, Cloud Functions, שירותי Cloud Run ומסד הנתונים של Firestore.

7. יצירת הקטגוריות

צריך 2 קטגוריות לתמונות: אחת כדי לשמור תמונות מקוריות ברזולוציה גבוהה, ואחת כדי לשמור תמונות ממוזערות של התמונות.

באמצעות הכלי gsutil אפשר ליצור קטגוריה ציבורית אזורית (במקרה הזה באירופה) עם גישה אחידה למשתמשים כדי להעלות אליה תמונות:

export BUCKET_PICTURES=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}
gsutil mb -l EU gs://${BUCKET_PICTURES}
gsutil uniformbucketlevelaccess set on gs://${BUCKET_PICTURES}
gsutil iam ch allUsers:objectViewer gs://${BUCKET_PICTURES}

יצירת קטגוריה אזורית ציבורית נוספת לתמונות ממוזערות:

export BUCKET_THUMBNAILS=thumbnails-${GOOGLE_CLOUD_PROJECT}
gsutil mb -l EU gs://${BUCKET_THUMBNAILS}
gsutil uniformbucketlevelaccess set on gs://${BUCKET_THUMBNAILS}
gsutil iam ch allUsers:objectViewer gs://${BUCKET_THUMBNAILS}

אפשר לוודא שהקטגוריות נוצרות וגלויות לכולם בקטע Cloud Storage במסוף Cloud:

15063936edd72f06.png

8. טרנספורמציה של נתוני ראייה (פונקציה של Cloud Functions)

Workflows.yaml מתחיל ב-init, eventTypeSwitch, eventTypeNotSupported שלבים. כך מוודאים שהאירועים שמגיעים מקטגוריות מנותבים לשלבים הנכונים.

באירוע object.finalize, השלב imageAnalysisCall מבצע קריאה ל-Vision API כדי לחלץ מטא-נתונים של התמונה שנוצרה. את כל השלבים האלה עושים בתהליכי עבודה:

daaed43a22d2b0d3.png

בשלב הבא אנחנו צריכים לשנות את הנתונים שמוחזרים מ-Vision API כדי שנוכל לשמור אותם ב-Firestore. באופן ספציפי יותר, אנחנו צריכים:

  • רשימת התוויות שהוחזרו לתמונה.
  • אחזור הצבע הדומיננטי של התמונה.
  • בודקים אם התמונה בטוחה.

אפשר לעשות זאת בקוד בפונקציה של Cloud Functions, ו-Workflows פשוט קורא לפונקציה הזו:

5e120e70c67779cd.png

לעיון בקוד

הפונקציה של Cloud Functions נקראת vision-data-transform. ניתן לבדוק את הקוד המלא ב-index.js. כמו שאפשר לראות, המטרה היחידה של הפונקציה הזו היא לבצע טרנספורמציה של JSON ל-JSON, כדי לאחסן את המטא-נתונים של התמונה בצורה נוחה ב-Firestore.

פריסה ב-Cloud Functions

עוברים אל התיקייה:

cd workflows/functions/vision-data-transform/nodejs

מגדירים את האזור הרצוי:

export REGION=europe-west1
gcloud config set functions/region ${REGION}

פורסים את הפונקציה באמצעות:

export SERVICE_NAME=vision-data-transform
gcloud functions deploy ${SERVICE_NAME} \
  --source=. \
  --runtime nodejs10 \
  --entry-point=vision_data_transform \
  --trigger-http \
  --allow-unauthenticated

אחרי פריסת הפונקציה, השלב transformImageAnalysisData של תהליכי עבודה יוכל לקרוא לפונקציה הזו כדי לבצע את טרנספורמציה של הנתונים של Vision API.

9. הכנת מסד הנתונים

השלב הבא בתהליך העבודה הוא לבדוק את בטיחות התמונה בנתוני התמונה, ולאחר מכן לאחסן את המידע על התמונה שהוחזרה על ידי Vision API אל מסד הנתונים של Cloud Firestore – מסד נתונים מהיר, מנוהל ומבוסס-ענן מסוג NoSQL, ללא שרת (serverless):

6624c616bc7cd97f.png

שניהם מתבצעים ב-Workflows, אבל צריך ליצור את מסד הנתונים של Firestore כדי שאחסון המטא-נתונים יפעל.

קודם כול, יוצרים אפליקציית App Engine באזור שבו רוצים ליצור את מסד הנתונים של Firestore (דרישה ל-Firestore):

export REGION_FIRESTORE=europe-west2
gcloud app create --region=${REGION_FIRESTORE}

לאחר מכן, יוצרים את מסד הנתונים של Firestore באותו אזור:

gcloud firestore databases create --region=${REGION_FIRESTORE}

המסמכים ייווצרו באופן פרוגרמטי באוסף שלנו ויכילו 4 שדות:

  • name (מחרוזת): שם הקובץ של התמונה שהועלתה, שהוא גם המפתח של המסמך
  • labels (מערך מחרוזות): התוויות של הפריטים המזוהים על ידי Vision API
  • color (מחרוזת): קוד הצבע ההקסדצימלי של הצבע הדומיננטי (כלומר, #ab12ef)
  • נוצר (תאריך): חותמת הזמן של התקופה שבה אוחסנו המטא-נתונים של התמונה
  • thumbnail (בוליאני): שדה אופציונלי שיוצג אם נוצרה תמונה ממוזערת לתמונה הזו

מכיוון שנחפש ב-Firestore כדי למצוא תמונות שיש להן תמונות ממוזערות זמינות, ונבצע מיון לאורך תאריך היצירה, נצטרך ליצור אינדקס חיפוש. ניתן ליצור את האינדקס באמצעות הפקודה הבאה:

gcloud firestore indexes composite create --collection-group=pictures \
  --field-config field-path=thumbnail,order=descending \
  --field-config field-path=created,order=descending

לתשומת ליבכם: יצירת האינדקס עשויה להימשך עד 10 דקות.

לאחר יצירת האינדקס, ניתן לראות אותו במסוף Cloud:

43af1f5103bf423.png

בשלב storeMetadata של תהליכי עבודה אפשר לשמור עכשיו את המטא-נתונים של התמונה ב-Firestore.

10. שירות תמונות ממוזערות (Cloud Run)

השלב הבא בשרשרת הוא ליצור תמונה ממוזערת של תמונה. הפעולה הזו מתבצעת בקוד בשירות של Cloud Run, ו-Workflows קורא לשירות הזה בשלב thumbnailCall:

84d987647f082b53.png

לעיון בקוד

שירות Cloud Run נקרא thumbnails. ניתן לבדוק את הקוד המלא ב-index.js.

פיתוח ופרסום של קובץ האימג' בקונטיינר

Cloud Run מפעיל קונטיינרים, אבל קודם צריך לפתח את קובץ האימג' של הקונטיינר (מוגדר ב-Dockerfile). אפשר להשתמש ב-Google Cloud Build כדי ליצור קובצי אימג' של קונטיינרים ולארח אותם ב-Google Container Registry.

עוברים אל התיקייה:

cd workflows/services/thumbnails/nodejs

גרסה:

export SERVICE_SRC=thumbnails
export SERVICE_NAME=${SERVICE_SRC}-service
gcloud builds submit \
  . \
  --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME}

אחרי דקה או שתיים, ה-build אמור להצליח והקונטיינר יופעל ב-Google Container Registry.

פריסה ב-Cloud Run

מגדירים כמה משתנים וסוגים נחוצים:

export BUCKET_THUMBNAILS=thumbnails-${GOOGLE_CLOUD_PROJECT}
export REGION=europe-west1
gcloud config set run/region ${REGION}
gcloud config set run/platform managed

פורסים באמצעות הפקודה הבאה:

gcloud run deploy ${SERVICE_NAME} \
    --image gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME} \
    --no-allow-unauthenticated \
    --memory=1Gi \
    --update-env-vars BUCKET_THUMBNAILS=${BUCKET_THUMBNAILS}

אחרי שהשירות נפרס, ניתן יהיה לקרוא לשירות הזה בשלב thumbnailCall של תהליכי עבודה.

11. שירות קולאז' (Cloud Run)

השלב הבא בשרשרת הוא ליצור קולאז' מהתמונות האחרונות. הפעולה הזו מתבצעת בקוד בשירות של Cloud Run, ו-Workflows קורא לשירות הזה בשלב collageCall:

591e36149066e1ba.png

לעיון בקוד

שירות Cloud Run נקרא collage. ניתן לבדוק את הקוד המלא ב-index.js.

פיתוח ופרסום של קובץ האימג' בקונטיינר

Cloud Run מפעיל קונטיינרים, אבל קודם צריך לפתח את קובץ האימג' של הקונטיינר (מוגדר ב-Dockerfile). אפשר להשתמש ב-Google Cloud Build כדי ליצור קובצי אימג' של קונטיינרים ולארח אותם ב-Google Container Registry.

עוברים אל התיקייה:

cd services/collage/nodejs

גרסה:

export SERVICE_SRC=collage
export SERVICE_NAME=${SERVICE_SRC}-service
gcloud builds submit \
  . \
  --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME}

אחרי דקה או שתיים, ה-build אמור להצליח והקונטיינר יופעל ב-Google Container Registry.

פריסה ב-Cloud Run

מגדירים כמה משתנים וסוגים נחוצים:

export BUCKET_THUMBNAILS=thumbnails-${GOOGLE_CLOUD_PROJECT}
export REGION=europe-west1
gcloud config set run/region ${REGION}
gcloud config set run/platform managed

פריסה:

gcloud run deploy ${SERVICE_NAME} \
    --image gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME} \
    --no-allow-unauthenticated \
    --memory=1Gi \
    --update-env-vars BUCKET_THUMBNAILS=${BUCKET_THUMBNAILS}

אחרי שהשירות פרוס, ניתן לוודא ששני השירותים פועלים בקטע Cloud Run במסוף Cloud, ובשלב collageCall של תהליכי עבודה תהיה אפשרות לקרוא לשירות הזה:

3ae9873f4cbbf423.png

12. פריסה של תהליכי עבודה

פרסנו את כל יחסי התלות החיצוניים של Workflows. אפשר להשלים את כל השלבים הנותרים (finalizeCompleted, pictureGarbageCollectionGCS, pictureGarbageCollectionFirestore, deleteCompleted) על ידי Workflows עצמו.

הגיע הזמן לפרוס את תהליכי העבודה!

עוברים לתיקייה שמכילה את הקובץ workflows.yaml ופורסים אותו באמצעות:

export WORKFLOW_REGION=europe-west4
export WORKFLOW_NAME=picadaily-workflows
gcloud workflows deploy ${WORKFLOW_NAME} \
  --source=workflows.yaml \
  --location=${WORKFLOW_REGION}

בעוד כמה שניות, תהליך העבודה אמור להיפרס ואפשר יהיה לראות אותו בקטע Workflows במסוף Cloud:

94a720149e5df9c5.png

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

55441b158f6027f3.png

אפשר גם להפעיל את תהליך העבודה מ-Cloud Console באופן ידני עם הפרמטרים הנכונים. במקום זאת, נפעיל אותו באופן אוטומטי בתגובה לאירועים של Cloud Storage בשלב הבא.

13. טריגרים של תהליכי עבודה (Cloud Functions)

תהליך העבודה נפרס ומוכן. עכשיו צריך להפעיל את תהליכי העבודה כשקובץ נוצר או נמחק בקטגוריה של Cloud Storage. אלו אירועי storage.object.finalize ו-storage.object.delete בהתאמה.

לתהליכי עבודה יש ממשקי API וספריות לקוח שמיועדים ליצירה, לניהול ולביצוע של תהליכי עבודה שאפשר להשתמש בהם. במקרה כזה תצטרכו להשתמש ב-Workflows Execution API ובספריית הלקוח של Node.js כדי להפעיל את תהליך העבודה.

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

c4d79646de729e4.png

לעיון בקוד

הפונקציה של Cloud Functions נקראת trigger-workflow. ניתן לבדוק את הקוד המלא ב-index.js.

פריסה ב-Cloud Functions

עוברים אל התיקייה:

cd workflows/functions/trigger-workflow/nodejs

מגדירים כמה משתנים וסוגים נחוצים:

export BUCKET_PICTURES=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}
export REGION=europe-west1
export WORKFLOW_NAME=picadaily-workflows
export WORKFLOW_REGION=europe-west4
export COLLAGE_URL=$(gcloud run services describe collage-service --format 'value(status.url)')
export THUMBNAILS_URL=$(gcloud run services describe thumbnails-service --format 'value(status.url)')
export VISION_DATA_TRANSFORM_URL=$(gcloud functions describe vision-data-transform --format 'value(httpsTrigger.url)')
gcloud config set functions/region ${REGION}

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

export SERVICE_NAME=trigger-workflow-on-finalize
gcloud functions deploy ${SERVICE_NAME} \
  --source=. \
  --runtime nodejs10 \
  --entry-point=trigger_workflow \
  --trigger-resource=${BUCKET_PICTURES} \
  --trigger-event=google.storage.object.finalize \
  --allow-unauthenticated \
  --set-env-vars GOOGLE_CLOUD_PROJECT=${GOOGLE_CLOUD_PROJECT},WORKFLOW_REGION=${WORKFLOW_REGION},WORKFLOW_NAME=${WORKFLOW_NAME},THUMBNAILS_URL=${THUMBNAILS_URL},COLLAGE_URL=${COLLAGE_URL},VISION_DATA_TRANSFORM_URL=${VISION_DATA_TRANSFORM_URL}

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

export SERVICE_NAME=trigger-workflow-on-delete
gcloud functions deploy ${SERVICE_NAME} \
  --source=. \
  --runtime nodejs10 \
  --entry-point=trigger_workflow \
  --trigger-resource=${BUCKET_PICTURES} \
  --trigger-event=google.storage.object.delete \
  --allow-unauthenticated \
  --set-env-vars GOOGLE_CLOUD_PROJECT=${GOOGLE_CLOUD_PROJECT},WORKFLOW_REGION=${WORKFLOW_REGION},WORKFLOW_NAME=${WORKFLOW_NAME},THUMBNAILS_URL=${THUMBNAILS_URL},COLLAGE_URL=${COLLAGE_URL},VISION_DATA_TRANSFORM_URL=${VISION_DATA_TRANSFORM_URL}

בסיום הפריסה, תוכלו לראות את שתי הפונקציות במסוף Cloud:

7d60c8b7851f39f5.png

14. Frontend (App Engine)

בשלב הזה, תיצרו ממשק אינטרנט ב-Google App Engine מ-Pic-a-daily: Lab 4 – יצירת ממשק קצה באינטרנט שיאפשר למשתמשים להעלות תמונות מאפליקציית האינטרנט, וגם לעיין בתמונות שהועלו ובתמונות הממוזערות שלהם.

223fb2281614d053.png

תוכלו לקבל מידע נוסף על App Engine ולקרוא את תיאור הקוד במאמר Pic-a-daily: Lab 4 – Create a web frontend.

לעיון בקוד

אפליקציית App Engine נקראת frontend. ניתן לבדוק את הקוד המלא ב-index.js.

פריסה ל-App Engine

עוברים אל התיקייה:

cd frontend

מגדירים את האזור הרצוי ומחליפים את GOOGLE_CLOUD_PROJECT ב-app.yaml במזהה הפרויקט בפועל:

export REGION=europe-west1
gcloud config set compute/region ${REGION}
sed -i -e "s/GOOGLE_CLOUD_PROJECT/${GOOGLE_CLOUD_PROJECT}/" app.yaml

פריסה:

gcloud app deploy app.yaml -q

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

Beginning deployment of service [default]...
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 8 files to Google Cloud Storage                ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [default]...done.
Setting traffic split for service [default]...done.
Deployed service [default] to [https://GOOGLE_CLOUD_PROJECT.appspot.com]
You can stream logs from the command line by running:
  $ gcloud app logs tail -s default
To view your application in the web browser run:
  $ gcloud app browse

אפשר גם להיכנס לקטע App Engine במסוף Cloud כדי לראות אם האפליקציה פרוסה ולגלות תכונות של App Engine כמו ניהול גרסאות ופיצול תנועה:

f4bd5f4de028bd83.png

15. בדיקת תהליכי העבודה

כדי לבדוק זאת, יש לעבור לכתובת ה-URL של App Engine המוגדרת כברירת מחדל לאפליקציה (https://<YOUR_PROJECT_ID>.appspot.com/). ממשק המשתמש של הקצה הקדמי פועל.

1649ac060441099.png

העלאת תמונה הפעולות האלה אמורות להפעיל את תהליכי העבודה, ואפשר יהיה לראות ביצוע של תהליך העבודה במצב Active במסוף Cloud:

b5a2a3d7a2bc094.png

בסיום תהליכי העבודה, אפשר ללחוץ על מזהה הביצוע ולראות את הפלט משירותים שונים:

8959df5098c21548.png

ניתן להעלות עוד 3 תמונות. בנוסף, אתם אמורים לראות שהתמונה הממוזערת והקולאז' של התמונות בקטגוריות של Cloud Storage ובממשק הקצה של App Engine יעודכנו:

d90c786ff664a5dc.png

16. הסרת המשאבים (אופציונלי)

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

gcloud projects delete ${GOOGLE_CLOUD_PROJECT} 

17. מעולה!

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

אילו נושאים דיברנו?

  • App Engine
  • Cloud Firestore
  • Cloud Functions
  • Cloud Run
  • תהליכי עבודה