1. מבוא

אתם יכולים להשתמש ב-Workflows כדי ליצור תהליכי עבודה ללא שרת שמקשרים בין סדרה של משימות ללא שרת בסדר שאתם מגדירים. אתם יכולים לשלב בין היכולות של ממשקי ה-API של Google Cloud, מוצרים בלי שרת (serverless) כמו Cloud Functions ו-Cloud Run, וקריאות לממשקי API חיצוניים כדי ליצור אפליקציות גמישות בלי שרת (serverless).
הם לא דורשים ניהול של תשתית, וניתן להרחיב אותם בצורה חלקה בהתאם לביקוש, כולל צמצום עד לאפס. במודל התמחור של תשלום לפי שימוש, אתם משלמים רק על זמן הביצוע.
ב-codelab הזה תלמדו איך לקשר בין שירותים שונים של Google Cloud וממשקי HTTP API חיצוניים לבין Workflows. באופן ספציפי, תחברו לתהליך עבודה שני שירותים ציבוריים של Cloud Functions, שירות פרטי של Cloud Run ו-API חיצוני ציבורי מבוסס-HTTP.
מה תלמדו
- היכרות עם תהליכי עבודה.
- איך מקשרים Cloud Functions ציבורי ל-Workflows.
- איך מחברים שירותים פרטיים של Cloud Run ל-Workflows.
- איך מחברים ממשקי HTTP API חיצוניים ל-Workflows.
2. הגדרה ודרישות
הגדרת סביבה בקצב אישי
- נכנסים אל Cloud Console ויוצרים פרויקט חדש או משתמשים בפרויקט קיים. (אם עדיין אין לכם חשבון Gmail או G Suite, אתם צריכים ליצור חשבון).
חשוב לזכור את מזהה הפרויקט, שהוא שם ייחודי בכל הפרויקטים ב-Google Cloud (השם שלמעלה כבר תפוס ולא יתאים לכם, מצטערים!). בהמשך ה-codelab הזה נתייחס אליו כאל PROJECT_ID.
- לאחר מכן, תצטרכו להפעיל את החיוב ב-Cloud Console כדי להשתמש במשאבים של Google Cloud.
העלות של התרגול הזה לא אמורה להיות גבוהה, ואולי אפילו לא תצטרכו לשלם בכלל. חשוב לפעול לפי ההוראות בקטע 'ניקוי' כדי להשבית את המשאבים, וכך לא תחויבו אחרי שתסיימו את המדריך הזה. משתמשים חדשים ב-Google Cloud זכאים לתוכנית תקופת ניסיון בחינם בשווי 300$.
מפעילים את Cloud Shell
אפשר להפעיל את Google Cloud מרחוק מהמחשב הנייד, אבל ב-codelab הזה תשתמשו ב-Google Cloud Shell, סביבת שורת פקודה שפועלת בענן.
ב-GCP Console, לוחצים על סמל Cloud Shell בסרגל הכלים שבפינה הימנית העליונה:
יחלפו כמה רגעים עד שההקצאה והחיבור לסביבת העבודה יושלמו. בסיום התהליך, אמור להופיע משהו כזה:
המכונה הווירטואלית הזו כוללת את כל הכלים שדרושים למפתחים. יש בה ספריית בית בנפח מתמיד של 5GB והיא פועלת ב-Google Cloud, מה שמשפר מאוד את הביצועים והאימות ברשת. אפשר לבצע את כל העבודה ב-Lab הזה רק באמצעות דפדפן.
3. סקירה כללית על Workflows
היסודות
תהליך עבודה מורכב מסדרה של שלבים שמתוארים באמצעות תחביר מבוסס-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 python312 \
--trigger-http \
--allow-unauthenticated
אחרי פריסת הפונקציה, אפשר לראות את כתובת ה-URL שלה בנכס url שמוצג במסוף או באמצעות הפקודה gcloud functions describe.
אפשר גם להיכנס לכתובת ה-URL של הפונקציה באמצעות הפקודה curl הבאה:
curl $(gcloud functions describe randomgen --format='value(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 python312 \
--trigger-http \
--allow-unauthenticated
אחרי שפורסים את הפונקציה, אפשר גם להיכנס לכתובת ה-URL של הפונקציה באמצעות הפקודה curl הבאה:
curl $(gcloud functions describe multiply --format='value(url)') \
-X POST \
-H "content-type: application/json" \
-d '{"input": 5}'
הפונקציה מוכנה לתהליך העבודה.
6. חיבור בין שתי פונקציות Cloud
בתהליך העבודה הראשון, מחברים את שתי הפונקציות.
יוצרים קובץ 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 כדי לעדכן את תהליך העבודה. מחפשים את 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 והקונטיינר צריך להיות קשור ל-0.0.0.0 ולמשתנה הסביבה PORT, ומכאן הקוד שלמעלה.
כשהפונקציה מקבלת בקשת HTTP, היא מחלצת את input מגוף ה-JSON, מפעילה את הפונקציה math.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.
- איך מחברים ממשקי HTTP API חיצוניים ל-Workflows.