Migrer des extensions Firebase vers un kit de fonctions créé par vous-même

Sélectionnez le chemin de migration : Migrer vers des kits de fonctions sur npm Migrer vers un kit de fonctions créé par vos soins

Si un éditeur n'a pas créé de kit de remplacement officiel distribué sur npm, ce guide vous explique comment forker son extension et la configurer en tant que kit de fonctions local.

Vérifier les limites de migration connues

Avant de commencer à migrer une instance d'extension, vérifiez si votre configuration utilise l'une des fonctionnalités suivantes qui nécessitent une solution de contournement ou ne sont pas encore compatibles avec les kits de fonctions :

  • Les dépôts Docker personnalisés et les clés KMS nécessitent une solution de contournement manuelle Cloud Functions for Firebase n'est pas compatible avec les paramètres système de remplacement pour configurer un dépôt Docker personnalisé ou une clé de chiffrement gérée par le client (clé KMS). Si votre extension configure l'un de ces paramètres, consultez la solution de contournement de la FAQ.

Avant de commencer

Vous devez configurer la CLI Firebase et initialiser un projet Firebase. Lorsque vous utilisez la CLI, assurez-vous d'utiliser la version >= 15.32.0 de firebase-tools, qui inclut les nouvelles commandes de migration et de kit de fonctions.

Autorisations et rôles requis pour le compte

Selon ce qui doit être créé et configuré par la CLI Firebase lors de la migration, le compte que vous utilisez pour vous authentifier auprès de Firebase et Google Cloud doit disposer des rôles suivants :

  • roles/firebaseextensions.editor
  • roles/cloudbuild.builds.editor
  • roles/artifactregistry.writer
  • roles/run.developer
  • roles/iam.serviceAccountUser
  • roles/iam.serviceAccountCreator
  • roles/cloudfunctions.admin (si vous devez effectuer setIamPermissions pour les points de terminaison publics)
  • roles/secretmanager.admin (si vous utilisez des secrets)
  • roles/serviceusage.serviceUsageAdmin (si vous devez activer de nouvelles API)

Nous vous recommandons d'utiliser un compte qui a déjà installé des extensions et déployé des fonctions, car la plupart de ces autorisations auront déjà été accordées. Si votre compte de migration a besoin de rôles supplémentaires, suivez les instructions Google Cloud IAM pour les ajouter.

Mettre à niveau l'instance de votre extension vers la dernière version

Vous devez mettre à jour votre extension vers la dernière version pour minimiser la différence entre votre instance d'extension et son kit de remplacement. Si votre extension n'est pas mise à niveau, il peut y avoir des changements majeurs et incompatibles entre votre instance d'extension et son kit de remplacement. La configuration exportée peut ne pas correspondre à ce que le kit attend en raison de modifications de paramètres entre les versions.

Utilisez l'une des options suivantes pour mettre à jour votre extension, selon l'endroit où elle a été installée :

  • Depuis la console Firebase
  • Depuis la CLI Firebase à l'aide de :
    • firebase ext:update <extension-instance-id> --project <project-id> firebase deploy --only extensions --project <project-id>

Si vous ignorez cette étape, la CLI vous invite à effectuer la mise à niveau lors de l'exportation de la configuration si votre extension n'est pas à la dernière version.

Dupliquer l'extension dans un kit de fonctions local

Avant de commencer à convertir une extension en kit de fonctions local, assurez-vous que le code source de l'extension se trouve dans votre projet Firebase. Pour ce faire, clonez le dépôt de l'extension depuis GitHub, créez un répertoire dans la racine de votre projet Firebase, puis copiez-y le dossier functions/ et le fichier extension.yaml de l'extension :

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

Suivez les étapes 1 à 8 du guide de migration pour les éditeurs afin de migrer le code source de votre extension vers une fonction de 2e génération. Passez ensuite aux étapes suivantes.

Rendre votre kit local compatible avec la région de la fonction exportée et les paramètres avancés

Dans un kit de fonctions local, la CLI Firebase ne génère pas de fichier index.ts pour configurer le package et le configurer afin qu'il utilise les paramètres système migrés. Pour utiliser la région de la fonction et les paramètres avancés configurés pour votre extension, configurez votre fichier index.ts afin de lire le format exporté par firebase ext:export --mode functions dans un fichier de variables d'environnement.

Plus précisément, dans le fichier index.ts de premier niveau qui exporte vos fonctions, définissez un paramètre pour FUNCTION_DEFAULT_REGION et appelez setGlobalOptions avec des variables d'environnement de la forme EXT_MIGRATED_SYSTEM_<GLOBAL_OPTION>, semblables au modèle index-kit-migration.ts utilisé par 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";

Tester votre kit avant la migration

Vous disposez désormais d'un kit de fonctions local qui, une fois déployé, se comporte de la même manière qu'une nouvelle installation de votre extension. L'étape suivante consiste à vérifier et à corriger les problèmes qui se sont glissés en cours de route avant de migrer vos instances d'extension de production vers celui-ci.

Commencez par ajouter votre fork en tant que kit local, configurez-le et déployez-le dans un projet de test. Les kits de fonctions locales doivent se trouver dans votre projet Firebase. Par conséquent, si le dépôt d'extensions cloné se trouve en dehors de votre projet Firebase, déplacez-le dans le répertoire du projet. Exécutez ensuite la commande d'installation du kit suivant pour l'installer en tant que kit local :

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

Cette commande vous aide à choisir un ID de kit, un ID d'instance et une configuration pour votre première instance de test. Il modifie ensuite votre fichier firebase.json pour enregistrer un kit local pointant vers votre répertoire dupliqué, avec des configurations pour chaque instance stockées dans un fichier .env à l'adresse function-kits/<kit-id>/config-<instance-id>.

Déployez votre kit local dans un projet de test avec les ressources appropriées pour tester son comportement. Si vous avez déjà configuré un projet de test lors du test de votre extension, exécutez la commande suivante :

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

Exemple concret : diffuser Cloud Firestore sur BigQuery (firestore-bigquery-export)

Vérifiez la synchronisation de bout en bout entre Cloud Firestore et BigQuery :

  1. Sur la page Cloud Firestore de la console Firebase, créez la collection que vous avez définie comme COLLECTION_PATH (users) si elle n'existe pas déjà.
  2. Créez un document nommé bigquery-mirror-test contenant des champs avec des valeurs.
  3. Sur la page BigQuery de la console Google Cloud, interrogez la table brute du journal des modifications. Elle doit contenir une seule ligne enregistrant la création du document :

    SELECT * FROM `PROJECT_ID.analytics.users_raw_changelog`
    
  4. Interrogez la dernière vue, qui devrait renvoyer le dernier événement de modification pour le seul document présent (bigquery-mirror-test) :

    SELECT * FROM `PROJECT_ID.analytics.users_raw_latest`
    
  5. Supprimez le document bigquery-mirror-test dans Cloud Firestore. Il disparaît de la vue "Dernières modifications", et un événement DELETE est ajouté au tableau du journal des modifications brutes.

    Vous pouvez inspecter l'historique complet d'un document avec :

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

Différences par rapport aux tests d'extension :

  • Le déclencheur est déployé en tant que kit-<kit-instance-id>-fsexportbigquery, et non ext-<instanceId>-fsexportbigquery. Recherchez ce nom dans le tableau de bord et les journaux Cloud Functions.
  • Votre code s'exécute dans Firebase Local Emulator Suite en tant que fonctions standards. Vous pouvez définir des valeurs de paramètre à utiliser dans l'émulateur avec .env.local. Vous pouvez également tester votre code à l'aide du SDK firebase-functions-test, comme décrit dans Tests unitaires de Cloud Functions.
  • Le provisionnement n'est plus géré par le runtime Extensions. Si le tableau du journal des modifications est manquant après le déploiement, réexécutez manuellement la tâche de configuration : firebase functions:lifecycle:run afterFirstDeploy <kit-instance-id>. La tâche est idempotente. Si vous l'exécutez à nouveau, l'ensemble de données, la table et les vues sont réconciliés.
  • Les valeurs des paramètres proviennent de .env plutôt que du formulaire d'installation. Par conséquent, les réexécutions de firebase deploy ne sont pas interactives une fois .env terminé.

(Facultatif) Nettoyer les données de test

Si vous souhaitez supprimer cette instance de test après l'avoir testée, désinstallez-la :

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

Cette opération supprime toutes les ressources cloud créées lors du déploiement du kit et supprime la configuration de son instance. Si vous ne disposez que d'une seule instance du kit, cela supprime également l'entrée du kit de firebase.json. Il ne supprime pas votre répertoire de code source local. Lorsque vous installez le kit pour votre migration en production, vous pouvez à nouveau choisir un ID de kit.

Migrer des extensions vers votre kit local

Maintenant que votre kit local est testé, vous pouvez migrer votre instance d'extension déployée en production.

1. Installer l'instance du kit de fonctions de remplacement

Installez votre kit de fonctions local en transmettant --no-configure pour ignorer la configuration manuelle. L'étape suivante pourra ainsi exporter votre configuration d'extension existante directement dans cette instance de kit :

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

2. Configurer l'instance du kit de fonctions de la même manière que l'extension

Vous devez personnaliser cette instance de kit avec une configuration identique à celle de l'extension qu'elle remplace. Vous pouvez exporter la configuration de votre instance d'extension dans un fichier .env, qui stocke les données de configuration des paramètres, des variables d'environnement et des références secrètes pour tous les Cloud Functions, y compris les kits. Pour l'exporter directement dans le fichier de configuration de votre kit, exécutez la commande suivante :

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

À la fin de cette étape, les informations de configuration de cette instance sont stockées dans un fichier .env spécifique au projet, dans le répertoire de configuration de votre instance, par exemple : function-kits/<kit-name>/config-<instance-id>/.env.<project-id>

3. Déployer et vérifier le remplacement du kit

Maintenant que le kit est installé et disponible en tant qu'ensemble de fonctions, vous pouvez déployer le kit de remplacement. Les kits de fonctions fonctionnent comme des fonctions standards, où chaque instance de kit agit comme une base de code distincte pour organiser vos fonctions. Vous pouvez choisir de déployer toutes vos fonctions ou seulement une instance de kit spécifique. Lorsque vous migrez une seule instance d'extension, ne déployez que cette instance de kit.

Si votre kit utilise de nouveaux paramètres qui n'étaient pas présents dans l'instance d'extension à partir de laquelle vous avez migré, la CLI Firebase vous les demande au début du processus de déploiement. Ce n'est pas prévu dans cet exemple pratique à partir d'une extension firestore-bigquery-export à jour, mais de nombreux kits demandent un nouveau paramètre pour toute source de déclencheur d'événement utilisée par le kit. Dans le cadre de cette migration, les kits mis à jour utilisent des fonctions de 2e génération, alors que les extensions utilisaient auparavant des fonctions de 1re génération. Dans la 2e génération, les fonctions sont situées à proximité de leurs sources d'événements et ajoutées en tant que paramètre supplémentaire. Dans les prochaines mises à jour, si de nouveaux paramètres sont ajoutés, la CLI vous y invite lors du prochain déploiement.

Exemple :

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

Résultat :

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

Pour vérifier que le firebase deploy du kit ne comporte aucune erreur, consultez les journaux de déploiement pour voir si des hooks de cycle de vie ont été déclenchés. Les extensions populaires, telles que Stream Cloud Firestore à BigQuery, utilisent des hooks de cycle de vie. Voici un exemple de hook de cycle de vie lorsqu'il est déclenché :

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

Ces messages de journal confirment les points suivants :

  • Un hook de cycle de vie a été trouvé et exécuté.
  • Une tâche a été mise en file d'attente dans la file d'attente des tâches associée au hook de cycle de vie.
  • Un lien vers Cloud Logging vous a été fourni pour vous permettre de vérifier que la tâche s'est terminée sans erreur.

Suivez le lien vers les journaux de la console Google Cloud pour vérifier qu'il n'y a pas d'erreurs dans les journaux et que l'événement de votre file d'attente de tâches a bien été traité. Si l'événement de cycle de vie ne s'est pas exécuté correctement, vous pouvez le redéclencher en exécutant la commande suivante :

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

Si vous déployez une instance de kit de fonctions pour la première fois, exécutez la commande suivante :

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

Si, à un moment donné de la validation, vous décidez d'arrêter ou d'annuler cette migration, vous pouvez désinstaller le kit en suivant les instructions de la section Désinstaller l'extension.

4. Désinstaller l'extension

Une fois que vous avez vérifié votre kit de fonctions déployé, vous pouvez désinstaller votre extension afin de ne pas dupliquer son comportement une fois pour le kit et une fois pour l'extension. Vous pouvez désinstaller toutes les extensions de la CLI Firebase, quelle que soit la méthode d'installation, si vous transmettez l'indicateur --immediate :

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

Exemple :

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

Résultat :

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

Migrations avancées

Vous pouvez avoir des extensions dans plusieurs projets Firebase que vous souhaitez gérer avec une seule base de code. Par exemple, si vous déployez la même infrastructure dans un environnement testing et un environnement production, chacun disposant d'une instance documents Cloud Firestore que vous exportez vers BigQuery, vous pouvez avoir deux instances de l'extension firestore-bigquery-export installées :

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

Si vous avez migré ces deux instances d'extension vers deux instances de kit de fonctions dans un même code source lorsque vous travailliez avec la CLI Firebase et que vous avez déployé à l'aide de firebase deploy --project testing et firebase deploy --project production, chaque déploiement créera deux instances dans les environnements testing et production.

Remplacez plutôt les deux instances d'extension par une instance de kit de fonctions firestore-bigquery-export déployée dans plusieurs projets, où chaque projet possède sa propre configuration. Le répertoire de configuration de l'instance doit se présenter comme suit :

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

Chaque déploiement sur testing et production crée une instance de votre kit avec la configuration correspondante. Les commandes CLI existantes créent cette configuration à condition que vous transmettiez l'indicateur --project dans chaque appel de ext:migrate ou functions:kits:install.

Exemple :

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

Vous disposez désormais d'une seule instance de kit configurée pour le déploiement dans vos projets testing et production avec leurs configurations respectives. Si vous créez une instance dans le projet testing et exécutez la commande functions:kits:install pour le même package dans le projet production, vous êtes invité à réutiliser l'instance configurée pour testing ou à installer une deuxième instance.