העברת תוספים ל-Firebase לערכת פונקציות שנוצרה באופן עצמאי

בחירת מסלול ההעברה: העברה לערכות פונקציות ב-npm העברה לערכת פונקציות שנוצרה באופן עצמאי

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

בדיקה אם יש מגבלות ידועות על ההעברה

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

  • מאגרי Docker בהתאמה אישית ומפתחות KMS דורשים פתרון עקיף ידני Cloud Functions for Firebase לא תומך בהחלפת פרמטרים של המערכת להגדרת מאגר Docker בהתאמה אישית או מפתח הצפנה בניהול הלקוח (מפתח KMS). אם התוסף מגדיר אחד מהפרמטרים האלה, אפשר לעיין בפתרון הבעיה בשאלות הנפוצות.

לפני שמתחילים

צריך להגדיר את Firebase CLI ולאתחל פרויקט Firebase. כשמשתמשים ב-CLI, צריך לוודא שמשתמשים בגרסה firebase-tools >= 15.32.0, שכוללת את הפקודות החדשות של העברה וערכת פונקציות.

הרשאות ותפקידים נדרשים בחשבון

בהתאם למה שצריך ליצור ולהגדיר באמצעות Firebase CLI במהלך ההעברה, לחשבון שבו אתם משתמשים כדי לבצע אימות באמצעות Firebase ו-Google Cloud צריכים להיות התפקידים הבאים:

  • roles/firebaseextensions.editor
  • roles/cloudbuild.builds.editor
  • roles/artifactregistry.writer
  • roles/run.developer
  • roles/iam.serviceAccountUser
  • roles/iam.serviceAccountCreator
  • ‫roles/cloudfunctions.admin (אם צריך לעשות setIamPermissions לנקודות קצה ציבוריות)
  • ‫roles/secretmanager.admin (אם משתמשים בסודות)
  • roles/serviceusage.serviceUsageAdmin (אם צריך להפעיל ממשקי API חדשים)

מומלץ להשתמש בחשבון שבו כבר הותקנו תוספים והופעלו פונקציות, כי רוב ההרשאות האלה כבר ניתנו. אם החשבון שמעבירים צריך עוד תפקידים, פועלים לפי Google Cloud ההוראות בנושא IAM כדי להוסיף אותם.

שדרוג של מופע התוסף לגרסה העדכנית

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

אפשר להשתמש באחת מהאפשרויות הבאות כדי לעדכן את התוסף, בהתאם למקום שבו הוא הותקן:

  • ממסוף Firebase
  • מ-Firebase CLI באמצעות:
    • firebase ext:update <extension-instance-id> --project <project-id> firebase deploy --only extensions --project <project-id>

אם מדלגים על השלב הזה, ה-CLI יציג בקשה לשדרוג כשמייצאים את ההגדרה, אם התוסף לא בגרסה העדכנית.

ביצוע Fork של התוסף לערכת פונקציות מקומית

לפני שמתחילים להמיר תוסף לערכת פונקציות מקומית, צריך לוודא שקוד המקור של התוסף נמצא בפרויקט Firebase. כדי לעשות את זה, משכפלים את מאגר התוסף מ-GitHub, יוצרים ספרייה בתוך תיקיית השורש של פרויקט Firebase ומעתיקים אליה את התיקייה functions/ של התוסף ואת extension.yaml:

mkdir -p path/to/kit
cp -r /path/to/extension-source/functions/* path/to/kit/
cp /path/to/extension-source/extension.yaml path/to/kit/.

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

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

בערכת כלים מקומית לפונקציות, ה-CLI של Firebase לא יוצר קובץ index.ts כדי להגדיר את החבילה ולהגדיר אותה לשימוש בפרמטרים של מערכת שהועברו. כדי להשתמש באזור הפונקציה ובפרמטרים מתקדמים שהוגדרו לתוסף, צריך להגדיר את הקובץ index.ts כך שיקרא את הפורמט שיוצא על ידי firebase ext:export --mode functions לתוך קובץ של משתני סביבה.

באופן ספציפי, בקובץ index.ts ברמה העליונה שמייצא את הפונקציות, מגדירים פרמטר ל-FUNCTION_DEFAULT_REGION ומפעילים את setGlobalOptions עם משתני סביבה מהצורה EXT_MIGRATED_SYSTEM_<GLOBAL_OPTION>, בדומה לתבנית index-kit-migration.ts שבה נעשה שימוש ב-CLI:

import { setGlobalOptions } from "firebase-functions";
import { MemoryOption, VpcEgressSetting, IngressSetting } from "firebase-functions/v2/options";
import { defineString } from "firebase-functions/params";

export const regionParam = defineString("FUNCTION_DEFAULT_REGION", {
  input: { text: { nonEmpty: true } },
  description: "Global default region where functions should be deployed. Can be overridden per-function.",
});

setGlobalOptions({
  region: regionParam,
  memory: (process.env.EXT_MIGRATED_SYSTEM_MEMORY as MemoryOption) ?? undefined,
  timeoutSeconds: process.env.EXT_MIGRATED_SYSTEM_TIMEOUTSECONDS
    ? Number(process.env.EXT_MIGRATED_SYSTEM_TIMEOUTSECONDS)
    : undefined,
  vpcConnectorEgressSettings:
    process.env.EXT_MIGRATED_SYSTEM_VPCCONNECTOREGRESSSETTINGS &&
    process.env.EXT_MIGRATED_SYSTEM_VPCCONNECTOREGRESSSETTINGS !== "VPC_CONNECTOR_EGRESS_SETTINGS_UNSPECIFIED"
      ? (process.env.EXT_MIGRATED_SYSTEM_VPCCONNECTOREGRESSSETTINGS as VpcEgressSetting)
      : undefined,
  vpcConnector: process.env.EXT_MIGRATED_SYSTEM_VPCCONNECTOR ?? undefined,
  maxInstances: process.env.EXT_MIGRATED_SYSTEM_MAXINSTANCES
    ? Number(process.env.EXT_MIGRATED_SYSTEM_MAXINSTANCES)
    : undefined,
  minInstances: process.env.EXT_MIGRATED_SYSTEM_MININSTANCES
    ? Number(process.env.EXT_MIGRATED_SYSTEM_MININSTANCES)
    : undefined,
  ingressSettings: (process.env.EXT_MIGRATED_SYSTEM_INGRESSSETTINGS as IngressSetting) ?? undefined,
  // Parses a comma-separated string of key:value pairs into a key-value object
  // (for example, "key1:value1,key2:value2" -> { key1: "value1", key2: "value2" }).
  labels: process.env.EXT_MIGRATED_SYSTEM_LABELS
    ? process.env.EXT_MIGRATED_SYSTEM_LABELS.split(",").reduce<Record<string, string> | undefined>(
        (acc, curr) => {
          const [key, value] = curr.split(":");
          const trimmedKey = key?.trim();
          const trimmedValue = value?.trim();
          if (!trimmedKey || !trimmedValue) {
            return acc;
          }
          acc = acc ?? {};
          acc[trimmedKey] = trimmedValue;
          return acc;
        },
        undefined,
      )
    : undefined,
});

// Re-export all functions so the Firebase CLI can deploy them
export * from "./your-functions";

בדיקת הערכה לפני ההעברה

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

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

firebase functions:kits:install --directory <path-to-your-fork> --project <test-project-id>

הפקודה הזו תעזור לכם לבחור מזהה ערכה, מזהה מופע והגדרה למופע הבדיקה הראשון. לאחר מכן, הוא משנה את הקובץ firebase.json כדי לרשום ערכת כלים מקומית שמפנה לספרייה המפוצלת, עם הגדרות לכל מופע שמאוחסנות בקובץ .env במיקום function-kits/<kit-id>/config-<instance-id>.

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

firebase deploy --only functions:<kit-instance-id> --project <test-project-id>

דוגמה: סטרימינג של Cloud Firestore אל BigQuery (firestore-bigquery-export)

כדי לוודא שהסנכרון מ-Cloud Firestore ל-BigQuery מוצפן מקצה לקצה:

  1. בדף Cloud Firestore במסוף Firebase, יוצרים את האוסף שהגדרתם כ-COLLECTION_PATH (users) אם הוא עדיין לא קיים.
  2. יוצרים מסמך בשם bigquery-mirror-test שמכיל שדות עם ערכים כלשהם.
  3. בדף BigQuery במסוף Google Cloud, מריצים שאילתה בטבלת יומן השינויים הגולמי. הוא צריך להכיל שורה אחת שמתעדת את יצירת המסמך:

    SELECT * FROM `PROJECT_ID.analytics.users_raw_changelog`
    
  4. מריצים שאילתה על התצוגה האחרונה, שאמורה להחזיר את אירוע השינוי האחרון עבור המסמך היחיד שקיים (bigquery-mirror-test):

    SELECT * FROM `PROJECT_ID.analytics.users_raw_latest`
    
  5. מוחקים את המסמך bigquery-mirror-test ב-Cloud Firestore. הוא נעלם מהתצוגה האחרונה, ואירוע DELETE מצורף לטבלת יומן השינויים הגולמי.

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

    SELECT *
       FROM `PROJECT_ID.analytics.users_raw_changelog`
       WHERE document_name = "bigquery-mirror-test"
       ORDER BY timestamp ASC
    

ההבדלים מבדיקת התוסף:

  • הטריגר נפרס כ-kit-<kit-instance-id>-fsexportbigquery, ולא כ-ext-<instanceId>-fsexportbigquery. מחפשים את השם הזה בלוח הבקרה וברישומים של Cloud Functions.
  • הקוד שלכם פועל ב-Firebase Local Emulator Suite כפונקציות רגילות. אפשר להגדיר ערכי פרמטר לשימוש באמולטור באמצעות .env.local. אפשר גם לבצע בדיקות יחידה של הקוד באמצעות firebase-functions-test SDK כפי שמתואר במאמר בדיקות יחידה של Cloud Functions.
  • הקצאת ההרשאות כבר לא מתבצעת על ידי סביבת זמן הריצה של התוספים. אם טבלת יומן השינויים חסרה אחרי הפריסה, מריצים מחדש את משימת ההגדרה באופן ידני: firebase functions:lifecycle:run afterFirstDeploy <kit-instance-id>. המשימה היא אידמפוטנטית, ולכן הפעלה חוזרת שלה תתאים את מערך הנתונים, הטבלה והתצוגות.
  • ערכי הפרמטרים מגיעים מ-.env ולא מטופס ההתקנה, ולכן הפעלות חוזרות של firebase deploy הן לא אינטראקטיביות אחרי ש-.env מסתיים.

(אופציונלי) הסרת המשאבים שנוצרו במהלך הבדיקה

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

firebase functions:kits:uninstall --instance <kit-instance-id> --project <test-project-id>

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

מעבר מתוספים לערכת הכלים המקומית

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

1. התקנה של מופע של ערכת פונקציות להחלפה

מתקינים את ערכת הפונקציות המקומית ומעבירים את --no-configure כדי לדלג על ההגדרה הידנית, כך שבשלב הבא אפשר יהיה לייצא את הגדרת התוסף הקיימת ישירות למופע של ערכת הפונקציות:

firebase functions:kits:install --no-configure --directory <path-to-your-fork> --project <project-id>

2. מגדירים את מופע Function Kit באופן זהה לתוסף

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

firebase ext:export --mode functions --instance <extension-instance-id> --kit-instance <kit-instance-id> --project <project-id>

בסוף השלב הזה, פרטי ההגדרה של המופע הזה נשמרים בקובץ .env ספציפי לפרויקט בתיקיית ההגדרות של המופע, כמו: function-kits/<kit-name>/config-<instance-id>/.env.<project-id>

3. פריסה ואימות של החלפת הערכה

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

אם ערכת הכלים משתמשת בפרמטרים חדשים שלא היו קיימים במופע התוסף שממנו ביצעתם את ההעברה, ה-CLI‏ Firebase יבקש מכם אותם בתחילת תהליך הפריסה. לא צפוי שזה יקרה בדוגמה הזו מתוך תוסף firestore-bigquery-export מעודכן, אבל הרבה ערכות כלים מבקשות פרמטר חדש לכל מקור הפעלת אירוע שבו נעשה שימוש בערכת הכלים. כחלק מההעברה הזו, ערכות הכלים המעודכנות משתמשות בפונקציות מהדור השני, במקום בפונקציות מהדור הראשון שבהן השתמשו התוספים בעבר. בדור השני, הפונקציות ממוקמות ליד מקורות האירועים שלהן ומוספות כפרמטר נוסף. בעדכונים עתידיים, אם יתווספו פרמטרים חדשים, ה-CLI יציג לכם בקשה בהפריסה הבאה.

דוגמה:

firebase deploy --only functions:firestore-bigquery-export --project my-project

פלט:

=== Deploying to 'my-project'...
i  deploying functions
i  functions: Loaded environment variables from function-kits/firestore-bigquery-export/config-firestore-bigquery-export/.env.my-project
i  functions: ensuring required API bigquery.googleapis.com is enabled...
i  functions: ensuring required API cloudtasks.googleapis.com is enabled...
✔  functions: required APIs are enabled
i  functions: granting declarative IAM roles to managed service account:
   - BigQuery Data Editor
   - BigQuery User
   - Cloud Datastore User
   - Eventarc Event Receiver
   - roles/run.invoker
✔  functions: successfully granted IAM roles
i  functions: creating Node.js 22 (2nd Gen) function kit-firestore-bigquery-export-fsexportbigquery(us-central1)...
i  functions: creating Node.js 22 (2nd Gen) function kit-firestore-bigquery-export-initBigQuerySync(us-central1)...
i  functions: creating Node.js 22 (2nd Gen) function kit-firestore-bigquery-export-setupBigQuerySync(us-central1)...
✔  functions[kit-firestore-bigquery-export-fsexportbigquery(us-central1)] Successful create operation.
✔  functions[kit-firestore-bigquery-export-initBigQuerySync(us-central1)] Successful create operation.
✔  functions[kit-firestore-bigquery-export-setupBigQuerySync(us-central1)] Successful create operation.
i  functions: Executing afterFirstDeploy lifecycle hook targeting: kit-firestore-bigquery-export-initBigQuerySync...
✔  functions: Successfully queued task for lifecycle hook kit-firestore-bigquery-export-initBigQuerySync in queue projects/my-project/locations/us-central1/queues/kit-firestore-bigquery-export-initBigQuerySync.
✔  Deploy complete!

כדי לוודא שלא היו שגיאות ב-firebase deploy של ערכת הכלים, בודקים ביומני הפריסה אם הופעלו ווים של מחזור החיים. תוספים פופולריים, כמו Stream Cloud Firestore to BigQuery, משתמשים ב-lifecycle hooks. בדוגמה הבאה אפשר לראות איך נראה וו של מחזור חיים כשהוא מופעל:

i  functions: Executing afterFirstDeploy lifecycle hook targeting: kit-firestore-bigquery-export-initBigQuerySync...
✔  functions: Successfully queued task for lifecycle hook kit-firestore-bigquery-export-initBigQuerySync in queue projects/my-project/locations/europe-west1/queues/kit-firestore-bigquery-export-initBigQuerySync.
i  functions: View logs for afterFirstDeploy at: https://console.cloud.google.com/logs/query;query=resource.type%3D%22cloud_run_revision%22%0Aresource.labels.service_name%3D%22kit-firestore-bigquery-export--initbigquerysync%22%0Aresource.labels.location%3D%22europe-west1%22;project=my-project

הודעות היומן האלה מאשרות את הדברים הבאים:

  • נמצאה פונקציית Lifecycle Hook והיא הופעלה.
  • משימה הוכנסה לתור בתור המשימות שמשויך להוק (hook) של מחזור החיים.
  • סופק קישור ל-Cloud Logging כדי שתוכלו לוודא שהמשימה הושלמה ללא שגיאות.

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

firebase functions:lifecycle:run <hook-name> <codebase>

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

firebase functions:lifecycle:run afterFirstDeploy <kit-instance-id>

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

4. הסרת התוסף

אחרי שמאמתים את ערכת הפונקציות שנפרסה, אפשר להסיר את התוסף כדי שלא יהיה כפילות בהתנהגות שלו – פעם אחת עבור ערכת הפונקציות ופעם אחת עבור התוסף. אפשר להסיר את כל התוספים מ-FirebaseCLI בלי קשר לאופן ההתקנה שלהם, אם מעבירים את הדגל --immediate:

firebase ext:uninstall <extension-instance-id> --project <project-id> --immediate

דוגמה:

firebase ext:uninstall firestore-bigquery-export --project my-project --immediate

פלט:

i  extensions: uninstalling firestore-bigquery-export...
i  extensions: deleting extension instance resources in project my-project...
✔  extensions: successfully uninstalled firestore-bigquery-export

העברות מתקדמות

יכול להיות שיש לכם תוספים בכמה Firebase פרויקטים שאתם רוצים לנהל באמצעות בסיס קוד אחד. לדוגמה, אם פורסים את אותה התשתית בסביבת testing ובסביבת production, וכל אחת מהן כוללת מופע documents Cloud Firestore שמייצאים ל-BigQuery, יכול להיות שיהיו שני מופעים של התוסף firestore-bigquery-export:

  • export-documents-testing
  • export-documents-production

אם העברתם את שני מופעי התוספים האלה לשני מופעים של ערכת פונקציות בבסיס קוד יחיד כשעבדתם עם Firebase CLI ופרסתם באמצעות firebase deploy --project testing ו-firebase deploy --project production, כל פריסה תיצור שני מופעים בסביבות testing ו-production.

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

  • config-export-documents/
    • .env.testing
    • .env.production

כל פריסה ל-testing ול-production יוצרת מופע אחד של ערכת הכלים עם ההגדרה המתאימה. הפקודות הקיימות ב-CLI יוצרות את ההגדרה הזו כל עוד מעבירים את הדגל --project בכל הפעלה של ext:migrate או functions:kits:install.

דוגמה:

firebase functions:kits:install --package @firebase-function-kits/firestore-bigquery-export --project testing --no-configure --template migration
✔ What would you like to name this kit? firestore-bigquery-export
✔ What would you like to name this instance? export-documents
✔  Wrote function-kits/firestore-bigquery-export/source/package.json
✔  Wrote function-kits/firestore-bigquery-export/source/tsconfig.json
✔  Wrote function-kits/firestore-bigquery-export/source/.gitignore
✔  Wrote function-kits/firestore-bigquery-export/source/src/index.ts
i  functions: Running npm install
✔  Wrote configuration info to firebase.json
✔  functions: Function kit firestore-bigquery-export successfully installed.
‫
# This creates the export-documents instance with an empty .env.testing file
# for the testing project. Now populate it via export:
firebase ext:export --mode functions --instance export-documents-testing \
  --kit-instance export-documents --project testing

# Repeat the export for production into the same kit instance to create
# .env.production from the export-documents-prod instance:
firebase ext:export --mode functions --instance export-documents-prod \
  --kit-instance export-documents --project production

עכשיו יש לכם מופע יחיד של ערכת כלים שהוגדר לפריסה בפרויקטים testing ו-production עם ההגדרות המתאימות. אם יוצרים מכונה בפרויקט testing ומריצים את הפקודה functions:kits:install לאותו חבילה בפרויקט production, תוצג בקשה לבחור אם להשתמש מחדש במכונה שהוגדרה עבור testing או להתקין מכונה שנייה.