1. מבוא
אפשר להשתמש בתהליכי עבודה כדי ליצור תהליכי עבודה ללא שרת (serverless) שמקשרים יחד סדרה של משימות ללא שרת (serverless), לפי סדר ההגדרה. ההגדרה הזו מאפשרת לשלב את העוצמה של ממשקי ה-API של Google Cloud, מוצרים ללא שרת (serverless) כמו Cloud Functions ו-Cloud Run, וקריאות לממשקי API חיצוניים כדי ליצור אפליקציות גמישות ללא שרת (serverless).
תהליכי עבודה לא דורשים ניהול תשתית ומתאימים אותם לעומס בצורה חלקה לפי הביקוש, כולל ירידה לאפס. במודל התמחור של תשלום לפי שימוש, אתה משלם רק על זמן הביצוע.
ב-Codelab הזה תלמדו איך לחבר בין שירותים שונים של Google Cloud וממשקי API חיצוניים של HTTP באמצעות Workflows. באופן ספציפי יותר, חיבור לתהליך העבודה שני שירותי Cloud Functions ציבוריים, שירות Cloud Run פרטי אחד ו-API חיצוני של HTTP.
מה תלמדו
- העקרונות הבסיסיים של תהליכי עבודה.
- איך מקשרים פונקציות ציבוריות של Cloud Functions עם Workflows.
- איך לחבר שירותים פרטיים של Cloud Run ל-Workflows.
- איך לחבר ממשקי API חיצוניים של HTTP ל-Workflows.
2. הגדרה ודרישות
הגדרת סביבה בקצב עצמאי
- נכנסים למסוף Cloud ויוצרים פרויקט חדש או עושים שימוש חוזר בפרויקט קיים. (אם עדיין אין לכם חשבון Gmail או G Suite, עליכם ליצור חשבון).
חשוב לזכור את מזהה הפרויקט, שם ייחודי לכל הפרויקטים ב-Google Cloud (השם שלמעלה כבר תפוס ולא מתאים לכם, סליחה). בהמשך ב-Codelab הזה, היא תיקרא PROJECT_ID
.
- בשלב הבא צריך להפעיל את החיוב במסוף Cloud כדי להשתמש במשאבים של Google Cloud.
מעבר ב-Codelab הזה לא אמור לעלות הרבה, אם בכלל. חשוב לבצע את כל ההוראות בקטע 'ניקוי' שמסביר איך להשבית משאבים כדי שלא תצברו חיובים מעבר למדריך הזה. משתמשים חדשים ב-Google Cloud זכאים להשתתף בתוכנית תקופת ניסיון בחינם בשווי 1,200 ש"ח.
הפעלת Cloud Shell
אומנם אפשר להפעיל את Google Cloud מרחוק מהמחשב הנייד, אבל ב-Codelab הזה משתמשים ב-Google Cloud Shell, סביבת שורת הפקודה שפועלת ב-Cloud.
ממסוף GCP, לוחצים על הסמל של Cloud Shell בסרגל הכלים שבפינה השמאלית העליונה:
נדרשים רק כמה דקות כדי להקצות את הסביבה ולהתחבר אליה. בסיום התהליך, אתם אמורים לראות משהו כזה:
למכונה הווירטואלית הזו נטען כל כלי הפיתוח הדרושים. יש בה ספריית בית בנפח מתמיד של 5GB והיא פועלת ב-Google Cloud, מה שמשפר משמעותית את ביצועי הרשת והאימות. כל העבודה בשיעור ה-Lab הזה יכולה להתבצע באמצעות דפדפן בלבד.
3. סקירה כללית של תהליכי עבודה
היסודות
תהליך עבודה מורכב מסדרה של שלבים שמתוארים באמצעות תחביר שמבוסס על YAML של Workflows. זוהי ההגדרה של תהליך העבודה. להסבר מפורט על התחביר של YAML של Workflows, תוכלו לעיין בדף העזר בנושא תחביר.
כשיוצרים תהליך עבודה, הוא נפרס ומוכן להפעלה. ביצוע הוא הרצה אחת של הלוגיקה שכלולה בהגדרה של תהליך עבודה. כל תהליכי העבודה הם בלתי תלויים, והמוצר תומך במספר רב של ביצוע בו-זמנית.
הפעלת שירותים
ב-Codelab הזה, יתבצע חיבור של שירותי Cloud Functions, שירותי Cloud Run ו-Workflows. תשתמשו גם ב-Cloud Build וב-Cloud Storage במהלך פיתוח השירותים.
מפעילים את כל השירותים הנחוצים:
gcloud services enable \ cloudfunctions.googleapis.com \ run.googleapis.com \ workflows.googleapis.com \ cloudbuild.googleapis.com \ storage.googleapis.com
בשלב הבא, מחברים שתי פונקציות Cloud Functions בתהליך עבודה.
4. פריסת הפונקציה הראשונה של Cloud Functions
הפונקציה הראשונה היא מחולל מספרים אקראיים ב-Python.
יוצרים ספרייה שבה מופיע קוד הפונקציה ועוברים אליה:
mkdir ~/randomgen cd ~/randomgen
יוצרים בספרייה קובץ main.py
עם התוכן הבא:
import random, json from flask import jsonify def randomgen(request): randomNum = random.randint(1,100) output = {"random":randomNum} return jsonify(output)
כשהיא מקבלת בקשת HTTP, הפונקציה הזו יוצרת מספר אקראי בין 1 ל-100 ומחזירה אל המתקשר בפורמט JSON.
הפונקציה מסתמכת על Flask לעיבוד HTTP, ואנחנו צריכים להוסיף זאת כתלות. יחסי התלות ב-Python מנוהלים באמצעות PIP ומבוטאים בקובץ מטא-נתונים שנקרא requirements.txt
.
יוצרים קובץ requirements.txt
באותה ספרייה עם התוכן הבא:
flask>=1.0.2
פורסים את הפונקציה עם טריגר HTTP ועם בקשות לא מאומתות שמותרות באמצעות הפקודה הבאה:
gcloud functions deploy randomgen \ --runtime python37 \ --trigger-http \ --allow-unauthenticated
אחרי שהפונקציה פרוסה, כתובת ה-URL של הפונקציה מופיעה בנכס httpsTrigger.url
שמוצגת במסוף או מוצגת באמצעות הפקודה gcloud functions describe
.
אפשר גם להיכנס לכתובת ה-URL הזו של הפונקציה באמצעות הפקודה הבאה curl
:
curl $(gcloud functions describe randomgen --format='value(httpsTrigger.url)')
הפונקציה מוכנה לתהליך העבודה.
5. פריסת הפונקציה השנייה של Cloud Functions
הפונקציה השנייה היא מכפיל. היא מכפילה את הקלט שהתקבל ב-2.
יוצרים ספרייה שבה מופיע קוד הפונקציה ועוברים אליה:
mkdir ~/multiply cd ~/multiply
יוצרים בספרייה קובץ main.py
עם התוכן הבא:
import random, json from flask import jsonify def multiply(request): request_json = request.get_json() output = {"multiplied":2*request_json['input']} return jsonify(output)
כשהיא מקבלת בקשת HTTP, הפונקציה מחלצת את input
מגוף ה-JSON, מכפילה אותו ב-2 ומחזירה אותו בפורמט JSON חזרה למבצע הקריאה.
יוצרים את אותו קובץ requirements.txt
באותה ספרייה עם התכנים הבאים:
flask>=1.0.2
פורסים את הפונקציה עם טריגר HTTP ועם בקשות לא מאומתות שמותרות באמצעות הפקודה הבאה:
gcloud functions deploy multiply \ --runtime python37 \ --trigger-http \ --allow-unauthenticated
אחרי שהפונקציה פרוסה, אפשר גם להיכנס לכתובת ה-URL של הפונקציה באמצעות הפקודה הבאה של curl
:
curl $(gcloud functions describe multiply --format='value(httpsTrigger.url)') \ -X POST \ -H "content-type: application/json" \ -d '{"input": 5}'
הפונקציה מוכנה לתהליך העבודה.
6. חיבור שתי פונקציות של Cloud Functions
בתהליך העבודה הראשון, מחברים את שתי הפונקציות יחד.
יצירת קובץ workflow.yaml
עם התכנים הבאים.
- randomgenFunction: call: http.get args: url: https://<region>-<project-id>.cloudfunctions.net/randomgen result: randomgenResult - multiplyFunction: call: http.post args: url: https://<region>-<project-id>.cloudfunctions.net/multiply body: input: ${randomgenResult.body.random} result: multiplyResult - returnResult: return: ${multiplyResult}
בתהליך העבודה הזה, מקבלים מספר אקראי מהפונקציה הראשונה ומעבירים אותו לפונקציה השנייה. התוצאה היא המספר האקראי המוכפל.
פורסים את תהליך העבודה הראשון:
gcloud workflows deploy workflow --source=workflow.yaml
מפעילים את תהליך העבודה הראשון:
gcloud workflows execute workflow
לאחר הרצת תהליך העבודה, תוכלו לראות את התוצאה על ידי העברת מזהה הביצוע בשלב הקודם:
gcloud workflows executions describe <your-execution-id> --workflow workflow
הפלט יכלול את result
ואת state
:
result: '{"body":{"multiplied":108},"code":200 ... } ... state: SUCCEEDED
7. חיבור ממשק API חיצוני של HTTP
בשלב הבא, תחבר את math.js בתור שירות חיצוני בתהליך העבודה.
ב-math.js, אפשר להעריך ביטויים מתמטיים כמו בדוגמה הבאה:
curl https://api.mathjs.org/v4/?'expr=log(56)'
הפעם תשתמשו ב-Cloud Console כדי לעדכן את תהליך העבודה שלנו. מוצאים את Workflows
במסוף Google Cloud:
מאתרים את תהליך העבודה ולוחצים על הכרטיסייה Definition
:
צריך לערוך את ההגדרה של תהליך העבודה ולכלול קריאה אל math.js
.
- randomgenFunction: call: http.get args: url: https://<region>-<project-id>.cloudfunctions.net/randomgen result: randomgenResult - multiplyFunction: call: http.post args: url: https://<region>-<project-id>.cloudfunctions.net/multiply body: input: ${randomgenResult.body.random} result: multiplyResult - logFunction: call: http.get args: url: https://api.mathjs.org/v4/ query: expr: ${"log(" + string(multiplyResult.body.multiplied) + ")"} result: logResult - returnResult: return: ${logResult}
תהליך העבודה מזין עכשיו את הפלט של פונקציית ההכפלה לקריאה של פונקציית יומן ב-math.js
.
ממשק המשתמש ינחה אתכם לערוך ולפרוס את תהליך העבודה. לאחר הפריסה, לוחצים על Execute
כדי להפעיל את תהליך העבודה. יוצגו פרטי הביצוע:
שימו לב לקוד הסטטוס 200
ול-body
עם הפלט של פונקציית היומן.
שילבת שירות חיצוני בתהליך העבודה שלנו, ממש מגניב!
8. פריסת שירות של Cloud Run
בחלק האחרון, סיימו את תהליך העבודה באמצעות קריאה לשירות Cloud Run פרטי. המשמעות היא שצריך לאמת את תהליך העבודה כדי לקרוא לשירות Cloud Run.
השירות Cloud Run מחזיר את הערך math.floor
של המספר שהועבר.
יוצרים ספרייה של קוד השירות ועוברים אליה:
mkdir ~/floor cd ~/floor
יוצרים בספרייה קובץ app.py
עם התוכן הבא:
import json import logging import os import math from flask import Flask, request app = Flask(__name__) @app.route('/', methods=['POST']) def handle_post(): content = json.loads(request.data) input = float(content['input']) return f"{math.floor(input)}", 200 if __name__ != '__main__': # Redirect Flask logs to Gunicorn logs gunicorn_logger = logging.getLogger('gunicorn.error') app.logger.handlers = gunicorn_logger.handlers app.logger.setLevel(gunicorn_logger.level) app.logger.info('Service started...') else: app.run(debug=True, host='0.0.0.0', port=int(os.environ.get('PORT', 8080)))
ב-Cloud Run המערכת פורסת קונטיינרים, לכן צריך Dockerfile
, והקונטיינר צריך להיות מקושר למשתנה env של 0.0.0.0
ו-PORT
, ולכן נוצר הקוד שלמעלה.
כשהיא מקבלת בקשת HTTP, הפונקציה הזו מחלצת את input
מגוף ה-JSON, קוראת ל-mat.floor ומחזירה את התוצאה חזרה למבצע הקריאה.
באותה ספרייה, יוצרים את קובץ ה-Dockerfile
הבא:
# Use an official lightweight Python image. # https://hub.docker.com/_/python FROM python:3.7-slim # Install production dependencies. RUN pip install Flask gunicorn # Copy local code to the container image. WORKDIR /app COPY . . # Run the web service on container startup. Here we use the gunicorn # webserver, with one worker process and 8 threads. # For environments with multiple CPU cores, increase the number of workers # to be equal to the cores available. CMD exec gunicorn --bind 0.0.0.0:8080 --workers 1 --threads 8 app:app
יוצרים את מאגר התגים:
export SERVICE_NAME=floor gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME}
לאחר יצירת הקונטיינר, פורסים אותו ב-Cloud Run. שימו לב לדגל no-allow-unauthenticated
. כך אפשר לוודא שהשירות מקבל רק קריאות מאומתות:
gcloud run deploy ${SERVICE_NAME} \ --image gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME} \ --platform managed \ --no-allow-unauthenticated
לאחר הפריסה, השירות מוכן לתהליך העבודה.
9. חיבור שירות Cloud Run
לפני שתוכלו להגדיר את Workflows לקריאה לשירות Cloud Run הפרטי, עליכם ליצור חשבון שירות שבו תוכלו להשתמש ב-Workflows:
export SERVICE_ACCOUNT=workflows-sa gcloud iam service-accounts create ${SERVICE_ACCOUNT}
מקצים לחשבון השירות את התפקיד run.invoker
. כך חשבון השירות יוכל לקרוא לשירותי Cloud Run מאומתים:
gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \ --member "serviceAccount:${SERVICE_ACCOUNT}@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \ --role "roles/run.invoker"
עדכון, הגדרת תהליך העבודה ב-workflow.yaml
כך שתכלול את שירות Cloud Run. שימו לב איך כוללים גם את השדה auth
, כדי לוודא ש-Workflows מעביר את אסימון האימות בקריאות שלו לשירות Cloud Run:
- randomgenFunction: call: http.get args: url: https://<region>-<project-id>.cloudfunctions.net/randomgen result: randomgenResult - multiplyFunction: call: http.post args: url: https://<region>-<project-id>.cloudfunctions.net/multiply body: input: ${randomgenResult.body.random} result: multiplyResult - logFunction: call: http.get args: url: https://api.mathjs.org/v4/ query: expr: ${"log(" + string(multiplyResult.body.multiplied) + ")"} result: logResult - floorFunction: call: http.post args: url: https://floor-<random-hash>.run.app auth: type: OIDC body: input: ${logResult.body} result: floorResult - returnResult: return: ${floorResult}
עדכון תהליך העבודה. המועד הזה עובר בחשבון השירות:
gcloud workflows deploy workflow \ --source=workflow.yaml \ --service-account=${SERVICE_ACCOUNT}@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com
מפעילים את תהליך העבודה:
gcloud workflows execute workflow
בעוד כמה שניות ניתן לבדוק את ביצוע תהליך העבודה כדי לראות את התוצאה:
gcloud workflows executions describe <your-execution-id> --workflow workflow
הפלט יכלול מספר שלם: result
ו-state
:
result: '{"body":"5","code":200 ... } ... state: SUCCEEDED
10. מעולה!
ברכות על השלמת ה-Codelab.
אילו נושאים דיברנו?
- העקרונות הבסיסיים של תהליכי עבודה.
- איך מקשרים פונקציות ציבוריות של Cloud Functions עם Workflows.
- איך לחבר שירותים פרטיים של Cloud Run ל-Workflows.
- איך לחבר ממשקי API חיצוניים של HTTP ל-Workflows.