מבוא לתזמור ללא שרת (serverless) עם Workflows

מבוא לתזמור ללא שרתים באמצעות Workflows

מידע על Codelab זה

subjectהעדכון האחרון: מרץ 19, 2025
account_circleנכתב על ידי atamel

1.‏ מבוא

c9b0cc839df0bb8f.png

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

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

ב-codelab הזה תלמדו איך לחבר שירותים שונים של Google Cloud וממשקי API חיצוניים מסוג HTTP לתהליכי עבודה. באופן ספציפי יותר, תקשרו בין שני שירותי Cloud Functions ציבוריים, שירות Cloud Run פרטי אחד וממשק API חיצוני וציבורי מסוג HTTP לתהליך עבודה.

מה תלמדו

  • העקרונות הבסיסיים של תהליכי עבודה.
  • איך מחברים פונקציות ציבוריות של Cloud Functions לתהליכי עבודה.
  • איך לקשר שירותים פרטיים של Cloud Run ל-Workflows.
  • איך מחברים ממשקי HTTP API חיצוניים לתהליכי עבודה.

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

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

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

H_hgylo4zxOllHaAbPKJ7VyqCKPDUnDhkr-BsBIFBsrB6TYSisg6LX-uqmMhh4sXUy_hoa2Qv87C2nFmkg-QAcCiZZp0qtpf6VPaNEEfP_iqt29KVLD-gklBWugQVeOWsFnJmNjHDw

dcCPqfBIwNO4R-0fNQLUC4aYXOOZhKhjUnakFLZJGeziw2ikOxGjGkCHDwN5x5kCbPFB8fiOzZnX-GfuzQ8Ox-UU15BwHirkVPR_0RJwl0oXrhqZmMIvZMa_uwHugBJIdx5-bZ6Z8Q

jgLzVCxk93d6E2bbonzATKA4jFZReoQ-fORxZZLEi5C3D-ubnv6nL-eP-iyh7qAsWyq_nyzzuEoPFD1wFOFZOe4FWhPBJjUDncnTxTImT3Ts9TM54f4nPpsAp52O0y3Cb19IceAEgQ

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

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

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

הפעלת Cloud Shell

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

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

STgwiN06Y0s_gL7i9bTed8duc9tWOIaFw0z_4QOjc-jeOmuH2TBK8l4udei56CKPLoM_i1yEF6pn5Ga88eniJQoEh8cAiTH79gWUHJdKOw0oiBZfBpOdcEOl6p29i4mvPe_A6UMJBQ

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

r6WRHJDzL-GdB5VDxMWa67_cQxRR_x_xCG5xdt9Nilfuwe9fTGAwM9XSZbNPWvDSFtrZ7DDecKqR5_pIq2IJJ9puAMkC3Kt4JbN9jfMX3gAwTNHNqFmqOJ-3iIX5HSePO4dNVZUkNA

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

3.‏ סקירה כללית על תהליכי עבודה

היסודות

תהליך עבודה מורכב מסדרה של שלבים שמתוארים באמצעות תחביר מבוסס-YAML של תהליכי עבודה. זוהי ההגדרה של תהליך העבודה. הסבר מפורט על תחביר ה-YAML של תהליכי העבודה זמין בדף חומר עזר בנושא תחביר.

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

הפעלת שירותים

ב-codelab הזה תתחברו לשירותי Cloud Functions ו-Cloud Run באמצעות תהליכי עבודה. תשתמשו גם ב-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.‏ חיבור HTTP API חיצוני

בשלב הבא תתחברו ל-math.js כשירות חיצוני בתהליך העבודה.

ב-math.js אפשר להעריך ביטויים מתמטיים באופן הבא:

curl https://api.mathjs.org/v4/?'expr=log(56)'

הפעם נשתמש במסוף Cloud כדי לעדכן את תהליך העבודה שלנו. מחפשים את Workflows במסוף Google Cloud:

7608a7991b33bbb0.png

מאתרים את תהליך העבודה ולוחצים על הכרטיסייה Definition:

f3c8c4d3ffa49b1b.png

עורכים את הגדרת תהליך העבודה וכוללים קריאה ל-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 כדי להריץ את תהליך העבודה. יוצגו פרטי הביצוע:

b40c76ee43a1ce65.png

שימו לב לקוד הסטטוס 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 לתהליכי עבודה.
  • איך לקשר שירותים פרטיים של Cloud Run ל-Workflows.
  • איך מחברים ממשקי HTTP API חיצוניים לתהליכי עבודה.