Migra Extensiones de Firebase a un kit de funciones creado por ti

Selecciona la ruta de migración: Migra a kits de funciones en npm Migra a un kit de funciones creado por ti

Si un publicador no creó un kit de reemplazo oficial distribuido en npm, esta guía te explica los pasos para bifurcar su extensión y configurarla como un kit de funciones local.

Verifica si hay limitaciones conocidas de la migración

Antes de comenzar a migrar una instancia de extensión, verifica si tu configuración usa alguna de las siguientes funciones que requieren una solución alternativa o que aún no son compatibles con los kits de funciones:

  • Los repositorios de Docker personalizados y las claves de KMS requieren una solución manual Cloud Functions for Firebase no admite parámetros del sistema de reemplazo para configurar un repositorio de Docker personalizado o una clave de encriptación administrada por el cliente (clave de KMS). Si tu extensión configura alguno de estos parámetros, consulta la solución alternativa de las preguntas frecuentes.

Antes de comenzar

Debes configurar la CLI de Firebase y inicializar un proyecto de Firebase. Cuando uses la CLI, asegúrate de usar la versión >= 15.32.0 de firebase-tools, que tiene los nuevos comandos de migración y del kit de funciones.

Roles y permisos de la cuenta obligatorios

Según lo que deba crear y configurar la CLI de Firebase durante la migración, la cuenta que uses para autenticarte con Firebase y Google Cloud debe tener los siguientes roles:

  • roles/firebaseextensions.editor
  • roles/cloudbuild.builds.editor
  • roles/artifactregistry.writer
  • roles/run.developer
  • roles/iam.serviceAccountUser
  • roles/iam.serviceAccountCreator
  • roles/cloudfunctions.admin (si necesitas hacer setIamPermissions para los extremos públicos)
  • roles/secretmanager.admin (si se usan secretos)
  • roles/serviceusage.serviceUsageAdmin (si necesitas habilitar APIs nuevas)

Te recomendamos que uses una cuenta que ya haya instalado extensiones y funciones implementadas, ya que la mayoría de estos permisos ya se habrán otorgado. Si tu cuenta de migración necesita más roles, sigue las instrucciones de IAM de Google Cloud para agregarlos.

Actualiza la instancia de extensión a la versión más reciente

Debes actualizar tu extensión a la versión más reciente para minimizar la diferencia entre la instancia de extensión y el kit de reemplazo. Si tu extensión no se actualiza, es posible que haya cambios significativos y que interrumpan la compatibilidad entre tu instancia de extensión y su reemplazo de kit. Es posible que la configuración exportada no coincida con lo que espera el kit debido a los cambios de parámetros entre versiones.

Usa una de las siguientes opciones para actualizar tu extensión, según dónde se haya instalado:

  • Desde la consola de Firebase
  • Desde la CLI de Firebase, usa el siguiente comando:
    • firebase ext:update <extension-instance-id> --project <project-id> firebase deploy --only extensions --project <project-id>

Si omites este paso, la CLI te solicitará que actualices la configuración cuando exportes la configuración si tu extensión no está en la versión más reciente.

Crea una bifurcación de la extensión en un kit de funciones local

Antes de comenzar a convertir una extensión en un kit de funciones local, asegúrate de que el código fuente de la extensión esté dentro de tu proyecto de Firebase. Para ello, clona el repositorio de la extensión desde GitHub, crea un directorio dentro de la raíz del proyecto Firebase y copia la carpeta functions/ y extension.yaml de la extensión en él:

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/.

Sigue los pasos del 1 al 8 de la guía de migración para publicadores para migrar el código fuente de tu extensión a una función de 2ª gen. Luego, continúa con los siguientes pasos.

Haz que tu kit local admita la región de la función exportada y los parámetros avanzados

En un kit de funciones local, la CLI de Firebase no genera un archivo index.ts para configurar el paquete y configurarlo para que use parámetros del sistema migrados. Para usar la región de la función y los parámetros avanzados que se configuraron para tu extensión, configura tu archivo index.ts para que lea el formato que exporta firebase ext:export --mode functions en un archivo de variables de entorno.

Específicamente, en el archivo index.ts de nivel superior que exporta tus funciones, define un parámetro para FUNCTION_DEFAULT_REGION y llama a setGlobalOptions con variables de entorno del formato EXT_MIGRATED_SYSTEM_<GLOBAL_OPTION>, de manera similar a la plantilla index-kit-migration.ts que usa la 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";

Prueba tu kit antes de la migración

Ahora tienes un kit de funciones local que, cuando se implementa, se comporta de forma idéntica a una nueva instalación de tu extensión. El siguiente paso es verificar y corregir cualquier problema que se haya introducido accidentalmente en el proceso antes de migrar a ella las instancias de producción de tu extensión.

Primero, agrega tu bifurcación como un kit local, configúrala y, luego, impleméntala en un proyecto de prueba. Los kits de funciones locales deben residir dentro de tu proyecto de Firebase, por lo que, si el repositorio de extensiones clonado está fuera de tu proyecto de Firebase, muévelo dentro del directorio del proyecto. Luego, ejecuta el siguiente comando de instalación del kit para instalarlo como un kit local:

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

Este comando te guía para elegir un ID de kit, un ID de instancia y una configuración para tu primera instancia de prueba. Luego, modifica tu archivo firebase.json para registrar un kit local que apunte a tu directorio bifurcado, con configuraciones para cada instancia almacenadas en un archivo .env en function-kits/<kit-id>/config-<instance-id>.

Implementa tu kit local en un proyecto de prueba con los recursos adecuados para probar su comportamiento. Si ya tienes un proyecto de prueba configurado para probar tu extensión, ejecuta el siguiente comando:

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

Ejemplo práctico: Transmisión de Cloud Firestore a BigQuery (firestore-bigquery-export)

Verifica la sincronización de Cloud Firestore a BigQuery de extremo a extremo:

  1. En la página Cloud Firestore de la consola de Firebase, crea la colección que configuraste como COLLECTION_PATH (users) si aún no existe.
  2. Crea un documento llamado bigquery-mirror-test que contenga cualquier campo con cualquier valor.
  3. En la página BigQuery de la consola de Google Cloud, consulta la tabla sin procesar del registro de cambios. Debe contener un solo registro de la creación del documento:

    SELECT * FROM `PROJECT_ID.analytics.users_raw_changelog`
    
  4. Consulta la vista más reciente, que debería devolver el evento de cambio más reciente para el único documento presente (bigquery-mirror-test):

    SELECT * FROM `PROJECT_ID.analytics.users_raw_latest`
    
  5. Borra el documento bigquery-mirror-test en Cloud Firestore. Desaparece de la vista más reciente y se agrega un evento DELETE a la tabla del registro de cambios sin procesar.

    Puedes inspeccionar el historial completo de un solo documento con el siguiente comando:

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

Diferencias con respecto a las pruebas de la extensión:

  • El activador se implementa como kit-<kit-instance-id>-fsexportbigquery, no como ext-<instanceId>-fsexportbigquery. Busca ese nombre en el panel y los registros de Cloud Functions.
  • Tu código se ejecuta en Firebase Local Emulator Suite como funciones estándar. Puedes establecer valores de parámetros para usar en el emulador con .env.local. También puedes realizar pruebas de unidades en tu código con el SDK de firebase-functions-test, como se describe en Pruebas de unidades de Cloud Functions.
  • El aprovisionamiento ya no se basa en el tiempo de ejecución de las extensiones. Si falta la tabla de registro de cambios después de la implementación, vuelve a ejecutar la tarea de configuración de forma manual: firebase functions:lifecycle:run afterFirstDeploy <kit-instance-id>. La tarea es idempotente, por lo que volver a ejecutarla reconcilia el conjunto de datos, la tabla y las vistas.
  • Los valores de los parámetros provienen de .env en lugar del formulario de instalación, por lo que las repeticiones de firebase deploy no son interactivas una vez que se completa .env.

Limpia los datos de las pruebas (opcional)

Si deseas quitar esta instancia de prueba después de probarla, desinstálala:

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

Esto borra todos los recursos de la nube creados durante la implementación del kit y quita la configuración de la instancia. Si solo tienes una instancia del kit, esto también quitará la entrada del kit de firebase.json. No borra el directorio de código fuente local. Cuando instales el kit para la migración de producción, podrás volver a elegir un ID de kit.

Migra de extensiones a tu kit local

Ahora que probaste tu kit local, puedes migrar la instancia de extensión implementada en producción.

1. Instala la instancia del kit de funciones de reemplazo

Instala tu kit de funciones local y pasa --no-configure para omitir la configuración manual, de modo que el siguiente paso pueda exportar la configuración de extensión existente directamente a esta instancia del kit:

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

2. Configura la instancia del kit de funciones de forma idéntica a la extensión

Debes personalizar esta instancia del kit con una configuración idéntica a la de la extensión que reemplaza. Puedes exportar la configuración de la instancia de tu extensión a un archivo .env, que almacena datos de configuración de parámetros, variables de entorno y referencias a secretos para todos los Cloud Functions, incluidos los kits. Para exportarlo directamente al archivo de configuración de tu kit, ejecuta el siguiente comando:

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

Al final de este paso, la información de configuración de esta instancia se almacena en un archivo .env específico del proyecto en el directorio de configuración de la instancia, como el siguiente: function-kits/<kit-name>/config-<instance-id>/.env.<project-id>

3. Implementa y verifica el reemplazo del kit

Ahora que el kit está instalado y disponible como un conjunto de funciones, puedes implementar el reemplazo del kit. Los kits de funciones funcionan como las funciones estándar, en las que cada instancia del kit actúa como una base de código independiente para organizar tus funciones. Puedes elegir implementar todas tus funciones o solo una instancia de kit específica. Cuando migres una sola instancia de extensión, implementa solo esa instancia del kit.

Si tu kit usa parámetros nuevos que no estaban presentes en la instancia de extensión desde la que migraste, la CLI de Firebase te los solicitará al comienzo del proceso de implementación. Esto no se espera en este ejemplo práctico de una extensión firestore-bigquery-export actualizada, pero muchos kits solicitan un parámetro nuevo para cualquier fuente de activación de eventos que use el kit. Como parte de esta migración, los kits actualizados usan funciones de 2ª gen. en los casos en que las extensiones usaban funciones de 1ª gen. En la 2ª gen., las funciones se ubican cerca de sus fuentes de eventos y se agregan como un parámetro adicional. En futuras actualizaciones, si se agregan parámetros nuevos, la CLI te solicitará que los ingreses en la próxima implementación.

Ejemplo sobre el que se trabajó:

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

Resultado:

=== 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!

Para verificar que el firebase deploy del kit no haya tenido errores, consulta los registros de implementación para ver si se activó algún gancho de ciclo de vida. Las extensiones populares, como Stream Cloud Firestore a BigQuery, usan hooks de ciclo de vida. El siguiente es un ejemplo de cómo se ve un hook de ciclo de vida cuando se activa:

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

Estos mensajes de registro confirman lo siguiente:

  • Se encontró y ejecutó un hook de ciclo de vida.
  • Se puso en cola una tarea en la lista de tareas en cola asociada del gancho de ciclo de vida.
  • Se proporcionó un vínculo a Cloud Logging para que puedas validar que la tarea se completó sin errores.

Sigue el vínculo de registros a la consola de Google Cloud para validar que no haya errores en los registros y que el evento de la lista de tareas en cola se haya procesado correctamente. Si el evento de ciclo de vida no se ejecutó correctamente, puedes volver a activarlo con el siguiente comando:

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

Si es la primera vez que implementas una instancia de Function Kit, ejecuta el siguiente comando:

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

Si en algún momento durante la validación decides que quieres detener o deshacer esta migración, puedes desinstalar el kit siguiendo las instrucciones que se indican en Cómo desinstalar la extensión.

4. Desinstala la extensión

Cuando hayas verificado el kit de funciones implementado, puedes desinstalar la extensión para no duplicar su comportamiento una vez para el kit y otra para la extensión. Puedes desinstalar todas las extensiones de la CLI de Firebase, independientemente de cómo las hayas instalado, si pasas la marca --immediate:

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

Ejemplo sobre el que se trabajó:

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

Resultado:

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

Migraciones avanzadas

Puedes tener extensiones en varios proyectos de Firebase que desees administrar con una sola base de código. Por ejemplo, si implementas la misma infraestructura en un entorno testing y en un entorno production, cada uno de los cuales tiene una instancia de documents Cloud Firestore que exportas a BigQuery, es posible que tengas dos instancias de la extensión firestore-bigquery-export instaladas:

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

Si migraste estas dos instancias de extensión a dos instancias del kit de funciones en una sola base de código cuando trabajabas con la CLI de Firebase y realizaste la implementación con firebase deploy --project testing y firebase deploy --project production, cada implementación crearía dos instancias en los entornos de testing y production.

En su lugar, reemplaza las dos instancias de la extensión por una instancia del kit de funciones de firestore-bigquery-export implementada en varios proyectos, en la que cada proyecto tenga su propia configuración. El directorio de configuración de la instancia debería verse de la siguiente manera:

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

Cada implementación en testing y production crea una instancia de tu kit con la configuración correspondiente. Los comandos de la CLI existentes crean esta configuración siempre que pases la marca --project en cada invocación de ext:migrate o functions:kits:install.

Ejemplo sobre el que se trabajó:

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

Ahora tienes una sola instancia del kit configurada para implementarse en tus proyectos testing y production con sus respectivas configuraciones. Si creas una instancia en el proyecto testing y ejecutas el comando functions:kits:install para el mismo paquete en el proyecto production, se te solicitará que reutilices la instancia configurada para testing o que instales una segunda instancia.