了解 2023 年 Google I/O 大会上介绍的 Firebase 亮点。了解详情

Configura il tuo ambiente


Spesso avrai bisogno di una configurazione aggiuntiva per le tue funzioni, come chiavi API di terze parti o impostazioni regolabili. Firebase SDK for Cloud Functions offre una configurazione dell'ambiente integrata per semplificare l'archiviazione e il recupero di questo tipo di dati per il tuo progetto.

Puoi scegliere tra tre opzioni:

  • Configurazione parametrizzata (consigliata per la maggior parte degli scenari). Ciò fornisce una configurazione dell'ambiente fortemente tipizzata con parametri che vengono convalidati al momento della distribuzione, prevenendo gli errori e semplificando il debug.
  • Configurazione basata su file delle variabili di ambiente . Con questo approccio, crei manualmente un file dotenv per caricare le variabili di ambiente.
  • Configurazione dell'ambiente di runtime con l'interfaccia a riga di comando di Firebase e functions.config (solo Cloud Functions (1a generazione)).

Per la maggior parte dei casi d'uso, si consiglia la configurazione parametrizzata. Questo approccio rende disponibili i valori di configurazione sia in fase di esecuzione che in fase di distribuzione e la distribuzione viene bloccata a meno che tutti i parametri non abbiano un valore valido. Al contrario, la configurazione con variabili di ambiente non è disponibile al momento della distribuzione.

Configurazione parametrizzata

Cloud Functions for Firebase fornisce un'interfaccia per definire i parametri di configurazione in modo dichiarativo all'interno della codebase. Il valore di questi parametri è disponibile sia durante la distribuzione della funzione, durante l'impostazione delle opzioni di distribuzione e runtime, sia durante l'esecuzione. Ciò significa che la CLI bloccherà la distribuzione a meno che tutti i parametri non abbiano un valore valido.

Per definire i parametri nel tuo codice, segui questo modello:

const functions = require('firebase-functions');
const { defineInt, defineString } = require('firebase-functions/params');

// Define some parameters
const minInstancesConfig = defineInt('HELLO_WORLD_MININSTANCES');
const welcomeMessage = defineString('WELCOME_MESSAGE');

// To use configured parameters inside the config for a function, provide them
// directly. To use them at runtime, call .value() on them.
export const helloWorld = functions.runWith({ minInstances: minInstancesConfig}).https.onRequest(
  (req, res) => {
    res.send(`${welcomeMessage.value()}! I am a function.`);
  }
);

Quando si distribuisce una funzione con variabili di configurazione parametrizzate, l'interfaccia a riga di comando di Firebase tenta prima di caricare i relativi valori dai file .env locali. Se non sono presenti in quei file e non è impostato alcun valore default , la CLI richiederà i valori durante la distribuzione, quindi li salverà automaticamente in un file .env denominato .env.<project_ID> nella tua directory functions/ /:

$ firebase deploy
i  functions: preparing codebase default for deployment
? Enter a string value for ENVIRONMENT: prod
i  functions: Writing new parameter values to disk: .env.projectId
…
$ firebase deploy
i  functions: Loaded environment variables from .env.projectId

A seconda del flusso di lavoro di sviluppo, potrebbe essere utile aggiungere il file .env.<project_ID> generato al controllo della versione.

Configura il comportamento della CLI

I parametri possono essere configurati con un oggetto Options che controlla il modo in cui la CLI richiederà i valori. L'esempio seguente imposta le opzioni per convalidare il formato di un numero di telefono, per fornire una semplice opzione di selezione e per popolare automaticamente un'opzione di selezione dal progetto Firebase:

const { defineString } = require('firebase-functions/params');

const welcomeMessage = defineString('WELCOME_MESSAGE', {default: 'Hello World',
description: 'The greeting that is returned to the caller of this function'});

const onlyPhoneNumbers = defineString('PHONE_NUMBER', {input: {text:
{validationRegex: /\d{3}-\d{3}-\d{4}/, validationErrorMessage: "Please enter
a phone number in the format XXX-YYY-ZZZZ"}}});

const selectedOption = defineString('PARITY', {input: {select: {options:
[{value: "odd"}, {value: "even"}]}}})

const storageBucket = defineString('BUCKET', {input: {resource: {type:
"storage.googleapis.com/Bucket"}}, description: "This will automatically
populate the selector field with the deploying Cloud Project’s
storage buckets"})

Tipi di parametro

La configurazione con parametri fornisce una tipizzazione forte per i valori dei parametri e supporta anche i segreti di Cloud Secret Manager. I tipi supportati sono:

  • Segreto
  • Corda
  • Booleano
  • Numero intero
  • Galleggiante

Valori ed espressioni dei parametri

Firebase valuta i tuoi parametri sia al momento della distribuzione sia durante l'esecuzione della tua funzione. A causa di questi doppi ambienti, è necessario prestare particolare attenzione quando si confrontano i valori dei parametri e quando li si utilizza per impostare le opzioni di runtime per le funzioni.

Per passare un parametro alla tua funzione come opzione di runtime, passalo direttamente:

const functions = require('firebase-functions');
const { defineInt} = require('firebase-functions/params');
const minInstancesConfig = defineInt('HELLO\_WORLD\_MININSTANCES');

export const helloWorld = functions.runWith({ minInstances: minInstancesConfig}).https.onRequest(
  (req, res) => {
    //…

Inoltre, se devi confrontare un parametro per sapere quale opzione scegliere, dovrai utilizzare comparatori integrati invece di controllare il valore:

const functions = require('firebase-functions');
const { defineBool } = require('firebase-functions/params');
const environment = params.defineString(‘ENVIRONMENT’, {default: ‘dev’});

// use built-in comparators
const minInstancesConfig =environment.equals('PRODUCTION').thenElse(10, 1);
export const helloWorld = functions.runWith({ minInstances: minInstancesConfig}).https.onRequest(
  (req, res) => {
    //…

È possibile accedere ai parametri e alle espressioni dei parametri che vengono utilizzati solo in fase di esecuzione con la loro funzione value :

const functions = require('firebase-functions');
const { defineString } = require('firebase-functions/params');
const welcomeMessage = defineString('WELCOME_MESSAGE');

// To use configured parameters inside the config for a function, provide them
// directly. To use them at runtime, call .value() on them.
export const helloWorld = functions.https.onRequest(
 (req, res) => {
    res.send(`${welcomeMessage.value()}! I am a function.`);
  }
);

Parametri incorporati

L'SDK di Cloud Functions offre tre parametri predefiniti, disponibili nel sottopacchetto firebase-functions/params :

  • projectId — il progetto Cloud in cui la funzione è in esecuzione.
  • databaseUrl : l'URL dell'istanza di Realtime Database associata alla funzione (se abilitata nel progetto Firebase).
  • storageBucket : il bucket Cloud Storage associato alla funzione (se abilitato nel progetto Firebase).

Questi funzionano come parametri stringa definiti dall'utente sotto tutti gli aspetti, tranne per il fatto che, poiché i loro valori sono sempre noti all'interfaccia a riga di comando di Firebase, i loro valori non verranno mai richiesti durante la distribuzione né salvati nei file .env .

Parametri segreti

I parametri di tipo Secret , definiti utilizzando defineSecret() , rappresentano parametri di stringa che hanno un valore archiviato in Cloud Secret Manager. Invece di controllare un file .env locale e scrivere un nuovo valore nel file se mancante, i parametri del segreto controllano l'esistenza in Cloud Secret Manager e richiedono in modo interattivo il valore di un nuovo segreto durante la distribuzione.

I parametri secret definiti in questo modo devono essere associati a singole funzioni che dovrebbero avervi accesso:

const functions = require('firebase-functions');
const { defineSecret } = require('firebase-functions/params');
const discordApiKey = defineSecret('DISCORD_API_KEY');

export const postToDiscord = functions.runWith({ secrets: [discordApiKey] }).https.onRequest(
  (req, res) => {
    const apiKey = discordApiKey.value();
    //…

Poiché i valori dei segreti sono nascosti fino all'esecuzione della funzione, non è possibile utilizzarli durante la configurazione della funzione.

Variabili ambientali

Cloud Functions for Firebase supporta il formato di file dotenv per il caricamento delle variabili di ambiente specificate in un file .env nel runtime dell'applicazione. Una volta distribuite, le variabili di ambiente possono essere lette tramite l'interfaccia process.env .

Per configurare il tuo ambiente in questo modo, crea un file .env nel tuo progetto, aggiungi le variabili desiderate e distribuisci:

  1. Crea un file .env nella tua directory functions/ :

    # Directory layout:
    #   my-project/
    #     firebase.json
    #     functions/
    #       .env
    #       package.json
    #       index.js
    
  2. Apri il file .env per la modifica e aggiungi le chiavi desiderate. Per esempio:

    PLANET=Earth
    AUDIENCE=Humans
    
  3. Distribuisci le funzioni e verifica che le variabili di ambiente siano state caricate:

    firebase deploy --only functions
    # ...
    # i functions: Loaded environment variables from .env.
    # ...
    

Una volta distribuite le variabili di ambiente personalizzate, il codice della funzione può accedervi con la sintassi process.env :

// Responds with "Hello Earth and Humans"
exports.hello = functions.https.onRequest((request, response) => {
  response.send(`Hello ${process.env.PLANET} and ${process.env.AUDIENCE}`);
});

Distribuzione di più set di variabili di ambiente

Se hai bisogno di un set alternativo di variabili di ambiente per i tuoi progetti Firebase (come staging o produzione), crea un .env. <project or alias > file e scrivi lì le variabili di ambiente specifiche del progetto. Le variabili di ambiente da .env e i file .env specifici del progetto (se esistono) verranno incluse in tutte le funzioni distribuite.

Ad esempio, un progetto potrebbe includere questi tre file contenenti valori leggermente diversi per lo sviluppo e la produzione:

.env .env.dev .env.prod
PIANETA=Terra

PUBBLICO=Umani

PUBBLICO=Sviluppatori Umani PUBBLICO=Prod Umani

Dati i valori in quei file separati, l'insieme di variabili di ambiente distribuite con le tue funzioni varierà a seconda del tuo progetto di destinazione:

$ firebase use dev
$ firebase deploy --only functions
i functions: Loaded environment variables from .env, .env.dev.
# Deploys functions with following user-defined environment variables:
#   PLANET=Earth
#   AUDIENCE=Dev Humans

$ firebase use prod
$ firebase deploy --only functions
i functions: Loaded environment variables from .env, .env.prod.
# Deploys functions with following user-defined environment variables:
#   PLANET=Earth
#   AUDIENCE=Prod Humans

Variabili d'ambiente riservate

Alcune chiavi delle variabili di ambiente sono riservate per uso interno. Non utilizzare nessuna di queste chiavi nei file .env :

  • Tutte le chiavi che iniziano con X_GOOGLE_
  • Tutte le chiavi che iniziano con EXT_
  • Tutte le chiavi che iniziano con FIREBASE_
  • Qualsiasi chiave dal seguente elenco:
  • CLOUD_RUNTIME_CONFIG
  • PUNTO D'ENTRATA
  • GCP_PROJECT
  • GCLOUD_PROJECT
  • PROGETTO_CLOUD_GOOGLE
  • FUNCTION_TRIGGER_TYPE
  • NOME_FUNZIONE
  • FUNCTION_MEMORY_MB
  • FUNCTION_TIMEOUT_SEC
  • IDENTITÀ_FUNZIONE
  • FUNZIONE_REGIONE
  • FUNZIONE_TARGET
  • FUNCTION_SIGNATURE_TYPE
  • K_SERVIZIO
  • K_REVISIONE
  • PORTA
  • K_CONFIGURAZIONE

Memorizza e accedi a informazioni di configurazione riservate

Le variabili di ambiente archiviate nei file .env possono essere utilizzate per la configurazione delle funzioni, ma non dovresti considerarle un modo sicuro per archiviare informazioni riservate come le credenziali del database o le chiavi API. Questo è particolarmente importante se controlli i tuoi file .env nel controllo del codice sorgente.

Per aiutarti a memorizzare informazioni di configurazione sensibili, Cloud Functions per Firebase si integra con Google Cloud Secret Manager . Questo servizio crittografato memorizza i valori di configurazione in modo sicuro, pur consentendo un facile accesso dalle tue funzioni quando necessario.

Crea e usa un segreto

Per creare un segreto, utilizza l'interfaccia a riga di comando di Firebase.

Per creare e utilizzare un segreto:

  1. Dalla radice della directory del progetto locale, esegui il seguente comando:

    firebase functions:secrets:set SECRET_NAME

  2. Inserisci un valore per SECRET_NAME .

    La CLI echeggia un messaggio di successo e avverte che è necessario distribuire le funzioni affinché la modifica abbia effetto.

  3. Prima della distribuzione, assicurati che il codice delle funzioni consenta alla funzione di accedere al segreto utilizzando il parametro runWith :

    exports.processPayment = functions
      // Make the secret available to this function
      .runWith({ secrets: ["SECRET_NAME"] })
      .onCall((data, context) => {
        const myBillingService = initializeBillingService(
          // reference the secret value
          process.env.SECRET_NAME
        );
        // Process the payment
      });
  4. Distribuisci le funzioni cloud:

    firebase deploy --only functions

Ora sarai in grado di accedervi come qualsiasi altra variabile d'ambiente. Al contrario, se un'altra funzione che non specifica il segreto in runWith tenta di accedere al segreto, riceve un valore indefinito:

  exports.anotherEndpoint = functions.https.onRequest((request, response) => {
    response.send(`The secret API key is ${process.env.SECRET_NAME}`);
    // responds with "The secret API key is undefined" because the `runWith` parameter is missing
  });

Una volta che la tua funzione è stata distribuita, avrà accesso al valore segreto. Solo le funzioni che includono specificamente un segreto nel parametro runWith avranno accesso a quel segreto come variabile di ambiente. In questo modo puoi assicurarti che i valori dei segreti siano disponibili solo dove sono necessari, riducendo il rischio di divulgazione accidentale di un segreto.

Gestire i segreti

Utilizza l'interfaccia a riga di comando di Firebase per gestire i tuoi secret. Durante la gestione dei segreti in questo modo, tieni presente che alcune modifiche alla CLI richiedono di modificare e/o ridistribuire le funzioni associate. Nello specifico:

  • Ogni volta che imposti un nuovo valore per un segreto, devi ridistribuire tutte le funzioni che fanno riferimento a quel segreto affinché raccolgano il valore più recente.
  • Se elimini un segreto, assicurati che nessuna delle tue funzioni distribuite faccia riferimento a quel segreto. Le funzioni che utilizzano un valore segreto che è stato eliminato avranno esito negativo in modo invisibile all'utente.

Ecco un riepilogo dei comandi della CLI di Firebase per la gestione dei segreti:

# Change the value of an existing secret
firebase functions:secrets:set SECRET_NAME

# View the value of a secret
functions:secrets:access SECRET_NAME

# Destroy a secret
functions:secrets:destroy SECRET_NAME

# View all secret versions and their state
functions:secrets:get SECRET_NAME

# Automatically clean up all secrets that aren't referenced by any of your functions
functions:secrets:prune

Per i comandi access e destroy , è possibile fornire il parametro version facoltativo per gestire una particolare versione. Per esempio:

functions:secrets:access SECRET_NAME[@VERSION]

Per ulteriori informazioni su queste operazioni, passare -h con il comando per visualizzare la guida della CLI.

Modalità di fatturazione dei segreti

Secret Manager consente 6 versioni segrete attive senza alcun costo. Ciò significa che puoi avere 6 segreti al mese in un progetto Firebase senza alcun costo.

Per impostazione predefinita, l'interfaccia a riga di comando di Firebase tenta di distruggere automaticamente le versioni segrete inutilizzate ove appropriato, ad esempio quando distribuisci funzioni con una nuova versione del segreto. Inoltre, puoi attivamente ripulire i segreti inutilizzati usando functions:secrets:destroy e functions:secrets:prune .

Secret Manager consente 10.000 operazioni di accesso mensili non fatturate su un segreto. Le istanze della funzione leggono solo i segreti specificati nel relativo parametro runWith ogni volta che si avviano a freddo. Se hai molte istanze di funzioni che leggono molti segreti, il tuo progetto potrebbe superare questa tolleranza, a quel punto ti verranno addebitati $ 0,03 per 10.000 operazioni di accesso.

Per ulteriori informazioni, consulta Prezzi di Secret Manager .

Supporto dell'emulatore

La configurazione dell'ambiente con dotenv è progettata per interagire con un emulatore di funzioni cloud locale.

Quando utilizzi un emulatore locale di Cloud Functions, puoi eseguire l'override delle variabili di ambiente per il tuo progetto impostando un file .env.local . I contenuti di .env.local hanno la precedenza su .env e sul file .env specifico del progetto.

Ad esempio, un progetto potrebbe includere questi tre file contenenti valori leggermente diversi per lo sviluppo e il test locale:

.env .env.dev .env.local
PIANETA=Terra

PUBBLICO=Umani

PUBBLICO=Sviluppatori Umani PUBBLICO=Umani locali

Quando viene avviato nel contesto locale, l'emulatore carica le variabili di ambiente come mostrato:

  $ firebase emulators:start
  i  emulators: Starting emulators: functions
  # Starts emulator with following environment variables:
  #  PLANET=Earth
  #  AUDIENCE=Local Humans

Segreti e credenziali nell'emulatore di Cloud Functions

L'emulatore di Cloud Functions supporta l'utilizzo di secret per archiviare e accedere a informazioni di configurazione riservate . Per impostazione predefinita, l'emulatore tenterà di accedere ai segreti di produzione utilizzando le credenziali predefinite dell'applicazione . In alcune situazioni, come gli ambienti CI, l'emulatore potrebbe non riuscire ad accedere ai valori segreti a causa di restrizioni di autorizzazione.

Analogamente al supporto dell'emulatore Cloud Functions per le variabili di ambiente, puoi eseguire l'override dei valori dei segreti impostando un file .secret.local . Ciò semplifica il test delle funzioni in locale, soprattutto se non si ha accesso al valore segreto.

Migrazione dalla configurazione dell'ambiente

Se hai utilizzato la configurazione dell'ambiente con functions.config , puoi migrare la configurazione esistente come variabili di ambiente (in formato dotenv ). L'interfaccia a riga di comando di Firebase fornisce un comando di esportazione che restituisce la configurazione di ogni alias o progetto elencato nel file .firebaserc della tua directory (nell'esempio seguente, local , dev e prod ) come file .env .

Per eseguire la migrazione, esporta le configurazioni dell'ambiente esistente utilizzando il comando firebase functions:config:export :

firebase functions:config:export
i  Importing configs from projects: [project-0, project-1]
⚠  The following configs keys could not be exported as environment variables:

⚠  project-0 (dev):
    1foo.a => 1FOO\_A (Key 1FOO\_A must start with an uppercase ASCII letter or underscore, and then consist of uppercase ASCII letters, digits, and underscores.)

Enter a PREFIX to rename invalid environment variable keys: CONFIG\_
✔  Wrote functions/.env.prod
✔  Wrote functions/.env.dev
✔  Wrote functions/.env.local
✔  Wrote functions/.env

Tieni presente che, in alcuni casi, ti verrà chiesto di inserire un prefisso per rinominare le chiavi delle variabili di ambiente esportate. Questo perché non tutte le configurazioni possono essere trasformate automaticamente poiché potrebbero non essere valide o potrebbero essere una variabile di ambiente riservata key .

Si consiglia di esaminare attentamente il contenuto dei file .env generati prima di distribuire le funzioni o di controllare i file .env nel controllo del codice sorgente. Se qualche valore è sensibile e non dovrebbe essere trapelato, rimuovilo dai tuoi file .env e archivialo invece in modo sicuro in Secret Manager .

Dovrai anche aggiornare il codice delle funzioni. Tutte le funzioni che usano functions.config dovranno ora usare invece process.env , come mostrato in Upgrade to 2nd gen .

Configurazione dell'ambiente

Prima che il supporto delle variabili di ambiente fosse rilasciato in firebase-functions v3.18.0 , l'utilizzo functions.config() era l'approccio consigliato per la configurazione dell'ambiente. Questo approccio è ancora supportato, ma consigliamo a tutti i nuovi progetti di utilizzare invece le variabili di ambiente, poiché sono più semplici da utilizzare e migliorano la portabilità del codice.

Impostare la configurazione dell'ambiente con la CLI

Per archiviare i dati dell'ambiente, puoi utilizzare il comando firebase functions:config:set nell'interfaccia a riga di comando di Firebase . A ogni chiave può essere assegnato uno spazio dei nomi utilizzando i punti per raggruppare insieme la configurazione correlata. Tieni presente che solo i caratteri minuscoli sono accettati nelle chiavi ; i caratteri maiuscoli non sono consentiti.

Ad esempio, per memorizzare l'ID client e la chiave API per "Alcuni servizi", potresti eseguire:

firebase functions:config:set someservice.key="THE API KEY" someservice.id="THE CLIENT ID"

Recupera la configurazione dell'ambiente corrente

Per ispezionare ciò che è attualmente memorizzato nella configurazione dell'ambiente per il tuo progetto, puoi utilizzare firebase functions:config:get . Produrrà JSON qualcosa del genere:

{
  "someservice": {
    "key":"THE API KEY",
    "id":"THE CLIENT ID"
  }
}

Questa funzionalità si basa sull'API di configurazione di Google Cloud Runtime .

Utilizzare functions.config per accedere alla configurazione dell'ambiente in una funzione

Alcune configurazioni vengono fornite automaticamente nello spazio dei nomi firebase riservato. La configurazione dell'ambiente è resa disponibile all'interno della funzione in esecuzione tramite functions.config() . Per utilizzare la configurazione sopra, il tuo codice potrebbe essere simile a questo:

const functions = require('firebase-functions');
const request = require('request-promise');

exports.userCreated = functions.database.ref('/users/{id}').onWrite(event => {
  let email = event.data.child('email').val();

  return request({
    url: 'https://someservice.com/api/some/call',
    headers: {
      'X-Client-ID': functions.config().someservice.id,
      'Authorization': `Bearer ${functions.config().someservice.key}`
    },
    body: {email: email}
  });
});

Utilizzare la configurazione dell'ambiente per inizializzare un modulo

Alcuni moduli Node sono pronti senza alcuna configurazione. Altri moduli richiedono una configurazione aggiuntiva per essere inizializzati correttamente. Ti consigliamo di archiviare questa configurazione nelle variabili di configurazione dell'ambiente anziché codificarla a livello hardware. Questo ti aiuta a mantenere il tuo codice molto più portabile, il che ti consente di rendere open source la tua applicazione o di passare facilmente dalla versione di produzione a quella di staging.

Ad esempio, per utilizzare il modulo Slack Node SDK , potresti scrivere quanto segue:

const functions = require('firebase-functions');
const IncomingWebhook = require('@slack/client').IncomingWebhook;
const webhook = new IncomingWebhook(functions.config().slack.url);

Prima della distribuzione, imposta la variabile di configurazione dell'ambiente slack.url :

firebase functions:config:set slack.url=https://hooks.slack.com/services/XXX

Comandi ambientali aggiuntivi

  • firebase functions:config:unset key1 key2 rimuove le chiavi specificate dal file config
  • firebase functions:config:clone --from <fromProject> clona l'ambiente di un altro progetto nel progetto attualmente attivo.

Variabili di ambiente popolate automaticamente

Esistono variabili di ambiente che vengono popolate automaticamente nel runtime delle funzioni e nelle funzioni emulate localmente. Questi includono quelli popolati da Google Cloud , nonché una variabile di ambiente specifica di Firebase:

process.env.FIREBASE_CONFIG : Fornisce le seguenti informazioni di configurazione del progetto Firebase:

{
  databaseURL: 'https://databaseName.firebaseio.com',
  storageBucket: 'projectId.appspot.com',
  projectId: 'projectId'
}

Questa configurazione viene applicata automaticamente quando si inizializza l'SDK Firebase Admin senza argomenti. Se stai scrivendo funzioni in JavaScript, inizializza in questo modo:

const admin = require('firebase-admin');
admin.initializeApp();

Se stai scrivendo funzioni in TypeScript, inizializza in questo modo:

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import 'firebase-functions';
admin.initializeApp();

Se devi inizializzare Admin SDK con la configurazione predefinita del progetto utilizzando le credenziali dell'account di servizio, puoi caricare le credenziali da un file e aggiungerle a FIREBASE_CONFIG in questo modo:

serviceAccount = require('./serviceAccount.json');

const adminConfig = JSON.parse(process.env.FIREBASE_CONFIG);
adminConfig.credential = admin.credential.cert(serviceAccount);
admin.initializeApp(adminConfig);