פיתוח פונקציות באופן מקומי

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

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

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

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

פיתוח פונקציות באופן מקומי באמצעות Functions Framework

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

‫Cloud Run משתמש בספריות Functions Framework בקוד פתוח כדי לעטוף את הפונקציות שפרסתם באפליקציית HTTP מתמשכת.

אפשר להריץ את Functions Framework גם בכל פלטפורמה אחרת שתומכת בשפה עצמה, כולל במחשב המקומי, בשרתים מקומיים וב-Compute Engine.

התקנת יחסי תלות

בספרייה של הפונקציה, מתקינים את ספריית Functions Framework בשפה הרצויה:

Node.js

npm install --save-dev @google-cloud/functions-framework

Python

pip3 install functions-framework

Go

go install github.com/GoogleCloudPlatform/functions-framework-go/funcframework

Java

Maven

אם משתמשים ב-Maven, צריך להוסיף את הקוד הבא לקובץ pom.xml:

<dependency>
  <groupId>com.google.cloud.functions</groupId>
  <artifactId>functions-framework-api</artifactId>
  <version>1.1.0</version>
  <scope>provided</scope>
</dependency>

Gradle

אם משתמשים ב-Gradle, מוסיפים את הקוד הבא לקובץ build.gradle:

dependencies {
  // Every function needs this dependency to get the Functions Framework API.
  compileOnly 'com.google.cloud.functions:functions-framework-api:1.1.0'

  // To run function locally using Functions Framework's local invoker
  invoker 'com.google.cloud.functions.invoker:java-function-invoker:1.3.1'
}

מידע נוסף זמין בספריית Java Functions Framework.

C#‎

הפקודות הבאות משתמשות בתבניות של .NET כדי ליצור בסיס קוד חדש של פונקציית .NET עם ספריית.NET Functions Framework כתלות:

# HTTP functions
dotnet new gcf-http

# CloudEvent functions
dotnet new gcf-event

Ruby

ב-Ruby, צריך להוסיף את Functions Framework לתלות של הפונקציה כדי לפרוס אותה ב-Cloud Run:

bundle add functions_framework

PHP

composer require google/cloud-functions-framework

הגדרת Functions Framework

לפני שמריצים פונקציה באמצעות Functions Framework, צריך קודם לציין את הסוג והשם של הפונקציה שרוצים להריץ. אפשר לציין את המאפיינים האלה כדגל בממשק שורת הפקודה (CLI) או כמשתני סביבה.

סוגי הפונקציות הנתמכות

ה-Functions Framework תומך בשני סוגי הפונקציות שנתמכות על ידי פונקציות Cloud Run. כל סביבות זמן הריצה של השפות תומכות בסוגי החתימות http ו-cloudevent.

סוג הפונקציה סוג החתימה תיאור זמני ריצה נתמכים
פונקציות שמופעלות על ידי HTTP http פונקציות שמקבלות בקשות HTTP ומגיבות להן. כל סביבות זמן הריצה
פונקציות שמבוססות על אירועים cloudevent פורמט אירועים מקובל בתחום. כל סביבות זמן הריצה

ציון הפונקציה שרוצים להריץ

לפני שמריצים פונקציה באמצעות Functions Framework, צריך לציין איזו פונקציה בקוד רוצים להריץ. ברוב השפות, אפשר לעשות את זה על ידי ציון שם השיטה של פונקציית היעד, כמו שמוצג בטבלאות הבאות. שימו לב, יש חריגים לכלל הזה בסביבות זמן הריצה של Java ושל ‎.NET.

הוראות לפי שפה

בטבלה הבאה מפורטות אפשרויות ההגדרה שנתמכות בכל שפה.

Node.js

ארגומנט של CLI משתנה סביבה תיאור
--port PORT היציאה להאזנה לבקשות. (ברירת מחדל: 8080)
--target FUNCTION_TARGET השם של הפונקציה export שתופעל. (ברירת מחדל: function)
--signature-type FUNCTION_SIGNATURE_TYPE סוג החתימה שמשמש את הפונקציה. הערך יכול להיות http (ברירת המחדל) או cloudevent.

Python

ארגומנט של CLI משתנה סביבה תיאור
--port PORT היציאה להאזנה לבקשות. (ברירת מחדל: 8080)
--target FUNCTION_TARGET השם של הפונקציה export שתופעל. (ברירת מחדל: function)
--signature-type FUNCTION_SIGNATURE_TYPE סוג החתימה שמשמש את הפונקציה. הערך יכול להיות http (ברירת המחדל) או cloudevent.

Go

משתנה סביבה תיאור
PORT היציאה להאזנה לבקשות. (ברירת מחדל: 8080)

Java

שם הארגומנט משתנה סביבה תיאור
run.port PORT היציאה להאזנה לבקשות. (ברירת מחדל: 8080)
run.functionTarget FUNCTION_TARGET השם של הפונקציה export שתופעל. (ברירת מחדל: function)

C#‎

ארגומנט של CLI משתנה סביבה תיאור
--port PORT היציאה להאזנה לבקשות. (ברירת מחדל: 8080)
--target (או הארגומנט היחיד) FUNCTION_TARGET שם המחלקה של הפונקציה שתופעל. (ברירת מחדל: function)

Ruby

ארגומנט של CLI משתנה סביבה תיאור
--port PORT היציאה להאזנה לבקשות. (ברירת מחדל: 8080)
--target FUNCTION_TARGET השם של הפונקציה export שתופעל. (ברירת מחדל: function)

PHP

משתנה סביבה תיאור
FUNCTION_TARGET השם של הפונקציה שתופעל. (ברירת מחדל: function)
FUNCTION_SIGNATURE_TYPE סוג החתימה שמשמש את הפונקציה. הערך יכול להיות http (ברירת המחדל) או cloudevent.

כדי להגדיר ולהריץ את Functions Framework:

Node.js

ב-Node.js Functions Framework אפשר לציין את השם של הפונקציה ואת סוג החתימה שלה כארגומנטים של שורת הפקודה או כמשתני סביבה.

אפשר גם לציין את הערכים האלה בקובץ buildfile‏ package.json על ידי הוספת סקריפט start עם ארגומנטים נדרשים של CLI, כמו בדוגמה שלמטה.

"scripts": {
"start": "npx functions-framework --target=YOUR_FUNCTION_NAME [--signature-type=YOUR_SIGNATURE_TYPE]"
}

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

"scripts": {
"start": "FUNCTION_TARGET=YOUR_FUNCTION_NAME FUNCTION_SIGNATURE_TYPE=YOUR_SIGNATURE_TYPE npx functions-framework"
}

מחליפים את YOUR_FUNCTION_NAME בשם השיטה של הפונקציה, ואת YOUR_SIGNATURE_TYPE (אם רלוונטי) בסוג החתימה של הפונקציה, כפי שמוצג בסוגי הפונקציות הנתמכים.

Python

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

Go

ב-Go Functions Framework נעשה שימוש ב-funcframework.RegisterHTTPFunctionContext כדי לציין את יעד הפונקציה ואת סוג החתימה.

Java

‫Java Functions Framework מקבל נתוני הגדרה משלושה מקורות שונים, לפי סדר העדיפות הבא (מהספציפי ביותר לפחות ספציפי):

  • ארגומנטים בשורת הפקודה
  • קבצים של Build
  • משתני סביבה

ארגומנטים בשורת הפקודה

Maven

כדי לציין את הפונקציה שרוצים להריץ, מוסיפים את הדגל הבא של ממשק שורת הפקודה (CLI) לפקודות mvn:

-Drun.functionTarget=YOUR_FUNCTION_NAME

אפשר גם לציין את יעד היציאה על ידי הוספת הדגל הבא של ה-CLI באופן דומה:

-Drun.port=12345

Gradle

הדגלים ב-CLI של Gradle כמעט זהים לאלה של Maven. השינוי היחיד ש-Gradle מבצע הוא החלפת התו -D שמופיע בתחילת כל דגל בתו -P, כמו שמוצג בדוגמה הבאה:

# Maven version

-Drun.functionTarget=...

# Gradle version

-Prun.functionTarget=...

קבצים של Build

אפשר גם לציין את הפונקציה שרוצים להפעיל בקובץ הבנייה של הפרויקט. ל-Maven ול-Gradle יש דגלים דומים ב-CLI, אבל הסעיפים בקובץ ה-build שונים מאוד.

Maven

שם קובץ ה-build של Maven הוא pom.xml. מוסיפים את הסעיף הבא לקובץ כדי לציין פונקציית יעד:

<plugin>
  <groupId>com.google.cloud.functions</groupId>
  <artifactId>function-maven-plugin</artifactId>
  <version>0.11.0</version>
  <configuration>
    <functionTarget>functions.HelloWorld</functionTarget>
  </configuration>
</plugin>

מחליפים את <functionTarget> בשם המחלקה של הפונקציה. לדוגמה, לפונקציה בחבילה functions עם שם המחלקה HelloCloudFunctions יהיה שם המחלקה functions.HelloCloudFunctions. הנתיב הזה הוא יחסי לקובץ ה-build הראשי – pom.xml או build.gradle.

Gradle

השם של קובצי ה-build של Gradle הוא build.gradle. מוסיפים את הסעיף הבא לקובץ הזה כדי לציין פונקציית יעד:

// Register a "runFunction" task to run the function locally
tasks.register("runFunction", JavaExec) {
  main = 'com.google.cloud.functions.invoker.runner.Invoker'
  classpath(configurations.invoker)
  inputs.files(configurations.runtimeClasspath, sourceSets.main.output)
  args(
    '--target', project.findProperty('run.functionTarget') ?: '',
    '--port', project.findProperty('run.port') ?: 8080
  )
  doFirst {
    args('--classpath', files(configurations.runtimeClasspath, sourceSets.main.output).asPath)
  }
}

C#‎

אם יוצרים את הפרויקט באמצעות dotnet new ואחת מהתבניות שצוינו קודם, ה-Functions Framework של ‎ .NET יזהה את הפונקציה באופן אוטומטי.

אם הפרויקט מכיל כמה פונקציות, בקטע הפעלת המסגרת מוסבר איך להפעיל פונקציה ספציפית.

Ruby

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

PHP

ב-PHP Functions Framework אפשר לציין משתני סביבה כארגומנטים בשורת הפקודה.

אפשר גם לציין את הערכים האלה בקובץ buildfile‏ composer.json על ידי הוספת סקריפט start, כמו בדוגמה הבאה.

"scripts": {
 "start": [
     "Composer\\Config::disableProcessTimeout",
     "FUNCTION_TARGET=YOUR_FUNCTION_NAME php -S localhost:${PORT:-8080} vendor/bin/router.php"
].
}

מחליפים את YOUR_FUNCTION_NAME בשם הפונקציה, ואת YOUR_SIGNATURE_TYPE (אם רלוונטי; הוא לא כלול בדוגמה שמוצגת כאן).

הפעלת הפונקציה

כדי להריץ את הפונקציה באמצעות Functions Framework, משתמשים בפקודה הבאה. כברירת מחדל, הפונקציה תהיה נגישה בכתובת localhost:8080, אלא אם תציינו במפורש ערך של PORT.

Node.js

npm start

Python

שימוש בארגומנטים בשורת הפקודה:

functions-framework --target=YOUR_FUNCTION_NAME

באמצעות משתני סביבה:

FUNCTION_TARGET=YOUR_FUNCTION_NAME functions-framework

מחליפים את YOUR_FUNCTION_NAME בשם השיטה של הפונקציה.

Go

קודם יוצרים קובץ cmd/main.go כמו שמתואר באתר Functions Framework for Go.

cd cmd
go build
./cmd

באמצעות משתני סביבה:

cd cmd
go build
PORT=8080 ./cmd

Java

Maven

כדי להריץ פונקציה שצוינה ב-pom.xml, משתמשים בפקודה הבאה:

mvn function:run

כדי להריץ פונקציה שצוינה בארגומנט של שורת הפקודה, משתמשים בפקודה הבאה:

mvn function:run -Drun.functionTarget=YOUR_FUNCTION_NAME

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

FUNCTION_TARGET=YOUR_FUNCTION_NAME mvn function:run

מחליפים את YOUR_FUNCTION_NAME בשם המחלקה של הפונקציה.

Gradle

כדי להריץ פונקציה שצוינה ב-build.gradle, משתמשים בפקודה הבאה:

./gradlew runFunction

כדי להריץ פונקציה שצוינה בארגומנט של שורת הפקודה, משתמשים בפקודה הבאה:

./gradlew runFunction -Prun.functionTarget=YOUR_FUNCTION_NAME

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

FUNCTION_TARGET=YOUR_FUNCTION_NAME ./gradlew runFunction

מחליפים את YOUR_FUNCTION_NAME בשם המחלקה של הפונקציה.

C#‎

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

dotnet run

אם פרויקט ‎ .NET מכיל כמה פונקציות, משתמשים בפקודה הבאה כדי להריץ פונקציה ספציפית. מחליפים את YOUR_FUNCTION_CLASSNAME בשם המחלקה של הפונקציה, כולל מרחב השמות.

dotnet run YOUR_FUNCTION_CLASSNAME

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

שימוש בארגומנטים בשורת הפקודה:

dotnet run --target YOUR_FUNCTION_CLASSNAME --port 8080

באמצעות משתני סביבה:

FUNCTION_TARGET=YOUR_FUNCTION_CLASSNAME PORT=8080 dotnet run

Ruby

שימוש בארגומנטים בשורת הפקודה:

bundle exec functions-framework-ruby --target YOUR_FUNCTION_NAME

באמצעות משתני סביבה:

FUNCTION_TARGET=YOUR_FUNCTION_NAME bundle exec functions-framework-ruby

מחליפים את YOUR_FUNCTION_NAME בשם השיטה של הפונקציה.

PHP

export FUNCTION_TARGET=YOUR_FUNCTION_NAME
php -S localhost:8080 vendor/bin/router.php

מחליפים את YOUR_FUNCTION_NAME בשם הפונקציה.

התקשרות לפונקציה שפועלת באופן מקומי

בתרגילים שבקטע הזה מניחים שהגדרתם פונקציה שפועלת באופן מקומי ב-localhost באמצעות Functions Framework.

אפשר להפעיל פונקציות שפועלות באופן מקומי על ידי שליחת בקשות HTTP שמנותבות באמצעות תהליך מקומי של הגשת תוכן.

פונקציות HTTP

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

בדיקת פונקציות HTTP באמצעות Cloud Shell

אם אתם משתמשים ב-Cloud Shell כדי ליצור ולבדוק את הפונקציה, מפעילים את הפונקציה באופן מקומי בחלון הטרמינל של Cloud Shell, ואז מנפיקים את בקשת הטריגר HTTP מדפדפן או ממופע curl באופן הבא:

דפדפן

לוחצים על הסמל כפתור לתצוגה מקדימה של אתר בסרגל הכלים של Cloud Shell ובוחרים באפשרות port 8080 או באפשרות Change port כדי לבחור יציאה אחרת. ייפתח חלון דפדפן במערכת הנכונה ותישלח בקשת GET ליציאה שצוינה.

‫Curl

כדי לשלוט בפורמט של בקשת ה-HTTP או לראות את התשובה ללא פורמט, משתמשים ב-curl:

  1. לוחצים על הסמל + בסרגל התפריטים של Cloud Shell כדי לפתוח חלון טרמינל חדש באותה מערכת שבה הפונקציה פועלת.
  2. בחלון הזה, מריצים את הפקודה curl כדי להפעיל את הפונקציה. לדוגמה:

    curl localhost:8080
    

בדיקת פונקציות HTTP בשרת שולחני

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

דפדפן

פותחים חלון חדש או כרטיסייה חדשה בדפדפן ומקלידים http://localhost:8080 בסרגל הכתובות של הדפדפן. תיפתח כרטיסייה בדפדפן עם הכתובת localhost:8080 בשרת של שולחן העבודה כדי להפעיל את הפונקציה.

‫Curl

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

 curl localhost:8080

הפקודה curl שצוינה מופעלת כדי להפעיל את הפונקציה, והתשובה מוצגת ללא עיצוב.

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

אתם יכולים לשלוח אירועים לדוגמה אל פונקציות מבוססות-אירועים באמצעות curl. בדוגמאות הבאות של בקשות curl מוצגות דרכים לשלוח אירועים לדוגמה של Pub/Sub ושל Cloud Storage לפונקציה מבוססת-אירועים שפועלת בכתובת localhost:8080.

Pub/Sub

curl localhost:8080 \
  -X POST \
  -H "Content-Type: application/json" \
  -H "ce-id: 123451234512345" \
  -H "ce-specversion: 1.0" \
  -H "ce-time: 2020-01-02T12:34:56.789Z" \
  -H "ce-type: google.cloud.pubsub.topic.v1.messagePublished" \
  -H "ce-source: //pubsub.googleapis.com/projects/MY-PROJECT/topics/MY-TOPIC" \
  -d '{
        "message": {
          "data": "d29ybGQ=",
          "attributes": {
             "attr1":"attr1-value"
          }
        },
        "subscription": "projects/MY-PROJECT/subscriptions/MY-SUB"
      }'
    

Cloud Storage

curl localhost:8080 \
  -X POST \
  -H "Content-Type: application/json" \
  -H "ce-id: 123451234512345" \
  -H "ce-specversion: 1.0" \
  -H "ce-time: 2020-01-02T12:34:56.789Z" \
  -H "ce-type: google.cloud.storage.object.v1.finalized" \
  -H "ce-source: //storage.googleapis.com/projects/_/buckets/MY-BUCKET-NAME" \
  -H "ce-subject: objects/MY_FILE.txt" \
  -d '{
        "bucket": "MY_BUCKET",
        "contentType": "text/plain",
        "kind": "storage#object",
        "md5Hash": "...",
        "metageneration": "1",
        "name": "MY_FILE.txt",
        "size": "352",
        "storageClass": "MULTI_REGIONAL",
        "timeCreated": "2020-04-23T07:38:57.230Z",
        "timeStorageClassUpdated": "2020-04-23T07:38:57.230Z",
        "updated": "2020-04-23T07:38:57.230Z"
      }'
    

המאמרים הבאים