Konfigurowanie środowiska

Często funkcje wymagają dodatkowej konfiguracji, np. kluczy interfejsu API innej firmy lub ustawień, które można dostosować. Pakiet Firebase SDK dla Cloud Functions oferuje wbudowaną konfigurację środowiska, która ułatwia przechowywanie i pobieranie tego typu danych w projekcie.

Możesz wybrać jedną z tych opcji:

  • Konfiguracja sparametryzowana (zalecana w większości przypadków). Zapewnia ona silnie typizowaną konfigurację środowiska z parametrami, które są weryfikowane podczas wdrażania, co zapobiega błędom i upraszcza debugowanie.
  • Konfiguracja zmiennych środowiskowych na podstawie pliku. W tym przypadku ręcznie tworzysz plik dotenv, aby wczytać zmienne środowiskowe.

W większości przypadków zalecamy konfigurację sparametryzowaną. Dzięki temu wartości konfiguracji są dostępne zarówno w czasie wykonywania, jak i wdrażania, a wdrożenie jest blokowane, dopóki wszystkie parametry nie mają prawidłowej wartości. Z kolei konfiguracja ze zmiennymi środowiskowymi nie jest dostępna w czasie wdrażania.

Konfiguracja sparametryzowana

Cloud Functions for Firebase udostępnia interfejs do deklaratywnego definiowania parametrów konfiguracji w bazie kodu. Wartość tych parametrów jest dostępna zarówno podczas wdrażania funkcji, gdy ustawiasz opcje wdrożenia i środowiska wykonawczego, jak i podczas wykonywania. Oznacza to, że interfejs wiersza poleceń zablokuje wdrożenie, dopóki wszystkie parametry nie będą miały prawidłowej wartości.

Node.js

const { onRequest } = require('firebase-functions/v2/https');
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 = onRequest(
  { minInstances: minInstancesConfig },
(req, res) => {
    res.send(`${welcomeMessage.value()}! I am a function.`);
  }
);

Python

from firebase_functions import https_fn
from firebase_functions.params import IntParam, StringParam

MIN_INSTANCES = IntParam("HELLO_WORLD_MIN_INSTANCES")
WELCOME_MESSAGE = StringParam("WELCOME_MESSAGE")

# To use configured parameters inside the config for a function, provide them
# directly. To use them at runtime, call .value() on them.
@https_fn.on_request(min_instances=MIN_INSTANCES)
def hello_world(req):
    return https_fn.Response(f'{WELCOME_MESSAGE.value()}! I am a function!')

Podczas wdrażania funkcji ze sparametryzowanymi zmiennymi konfiguracji wiersz poleceń Firebase najpierw próbuje wczytać ich wartości z lokalnych plików .env. Jeśli nie ma ich w tych plikach i nie ustawiono wartości default, interfejs wiersza poleceń poprosi o wartości podczas wdrażania, a następnie automatycznie zapisze je w pliku .env o nazwie .env.<project_ID> w katalogu 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

W zależności od przepływu pracy dewelopera może być przydatne dodanie wygenerowanego pliku .env.<project_ID> do systemu kontroli wersji.

Używanie parametrów w zakresie globalnym

Podczas wdrażania kod funkcji jest wczytywany i sprawdzany, zanim parametry uzyskają rzeczywiste wartości. Oznacza to, że pobieranie wartości parametrów w zakresie globalnym powoduje niepowodzenie wdrożenia. Jeśli chcesz użyć parametru do zainicjowania wartości globalnej, użyj wywołania zwrotnego inicjowania onInit(). To wywołanie zwrotne jest wykonywane przed uruchomieniem jakichkolwiek funkcji w środowisku produkcyjnym, ale nie jest wywoływane podczas wdrażania, dlatego jest bezpiecznym miejscem na dostęp do wartości parametru.

Node.js

const { GoogleGenerativeAI } = require('@google/generative-ai');
const { defineSecret } = require('firebase-functions/params');
const { onInit } = require('firebase-functions/v2/core');

const apiKey = defineSecret('GOOGLE_API_KEY');

let genAI;
onInit(() => {
  genAI = new GoogleGenerativeAI(apiKey.value());
})

Python

from firebase_functions.core import init
from firebase_functions.params import StringParam, PROJECT_ID
import firebase_admin
import vertexai

location = StringParam("LOCATION")

x = "hello"

@init
def initialize():
  # Note: to write back to a global, you'll need to use the "global" keyword
  # to avoid creating a new local with the same name.
  global x
  x = "world"
  firebase_admin.initialize_app()
  vertexai.init(PROJECT_ID.value, location.value)

Jeśli używasz parametrów typu Secret, pamiętaj, że są one dostępne tylko w procesie funkcji, które mają powiązany obiekt tajny. Jeśli obiekt tajny jest powiązany tylko z niektórymi funkcjami, przed jego użyciem sprawdź, czy secret.value() ma wartość fałszywą.

Konfigurowanie działania interfejsu wiersza poleceń

Parametry można skonfigurować za pomocą obiektu Options, który określa, jak interfejs wiersza poleceń będzie prosić o wartości. Ten przykład ustawia opcje, które sprawdzają format numeru telefonu, udostępniają prostą opcję wyboru i automatycznie wypełniają opcję wyboru z projektu w Firebase:

Node.js

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: params.select(["odd", "even"])});

const memory = defineInt("MEMORY", {
  description: "How much memory do you need?",
  input: params.select({ "micro": 256, "chonky": 2048 }),
});

const extensions = defineList("EXTENSIONS", {
  description: "Which file types should be processed?",
  input: params.multiSelect(["jpg", "tiff", "png", "webp"]),
});

const storageBucket = defineString('BUCKET', {
  description: "This will automatically
populate the selector field with the deploying Cloud Project’s
storage buckets",
  input: params.PICK_STORAGE_BUCKET,
});

Python

from firebase_functions.params import (
    StringParam,
    ListParam,
    TextInput,
    SelectInput,
    SelectOptions,
    ResourceInput,
    ResourceType,
)

MIN_INSTANCES = IntParam("HELLO_WORLD_MIN_INSTANCES")

WELCOME_MESSAGE = StringParam(
    "WELCOME_MESSAGE",
    default="Hello World",
    description="The greeting that is returned to the caller of this function",
)

ONLY_PHONE_NUMBERS = StringParam(
    "PHONE_NUMBER",
    input=TextInput(
        validation_regex="\d{3}-\d{3}-\d{4}",
        validation_error_message="Please enter a phone number in the format XXX-YYY-XXX",
    ),
)

SELECT_OPTION = StringParam(
    "PARITY",
    input=SelectInput([SelectOptions(value="odd"), SelectOptions(value="even")]),
)

STORAGE_BUCKET = StringParam(
    "BUCKET",
    input=ResourceInput(type=ResourceType.STORAGE_BUCKET),
    description="This will automatically populate the selector field with the deploying Cloud Project's storage buckets",
)

Typy parametrów

Konfiguracja sparametryzowana zapewnia silne typowanie wartości parametrów, a także obsługuje obiekty tajne z usługi Cloud Secret Manager. Obsługiwane typy:

  • Obiekt tajny
  • Ciąg znaków
  • Wartość logiczna
  • Liczba całkowita
  • Liczba zmiennoprzecinkowa
  • Lista (Node.js)
  • Obiekt tajny JSON (Node.js)

Informacje o funkcjach definiowania parametrów znajdziesz w dokumentacji przestrzeni nazw params.

Wartości i wyrażenia parametrów

Firebase ocenia parametry zarówno podczas wdrażania, jak i podczas wykonywania funkcji. Ze względu na te 2 środowiska należy zachować szczególną ostrożność podczas porównywania wartości parametrów i używania ich do ustawiania opcji środowiska wykonawczego funkcji.

Aby przekazać parametr do funkcji jako opcję środowiska wykonawczego, przekaż go bezpośrednio:

Node.js

const { onRequest } = require('firebase-functions/v2/https');
const { defineInt } = require('firebase-functions/params');
const minInstancesConfig = defineInt('HELLO_WORLD_MININSTANCES');

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

Python

from firebase_functions import https_fn
from firebase_functions.params import IntParam

MIN_INSTANCES = IntParam("HELLO_WORLD_MIN_INSTANCES")

@https_fn.on_request(min_instances=MIN_INSTANCES)
def hello_world(req):
    ...

Dodatkowo, jeśli musisz porównać parametr, aby wiedzieć, którą opcję wybrać, musisz użyć wbudowanych komparatorów zamiast sprawdzać wartość:

Node.js

const { onRequest } = require('firebase-functions/v2/https');
const environment = params.defineString(ENVIRONMENT, {default: 'dev'});

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

Python

from firebase_functions import https_fn
from firebase_functions.params import IntParam, StringParam

ENVIRONMENT = StringParam("ENVIRONMENT", default="dev")
MIN_INSTANCES = ENVIRONMENT.equals("PRODUCTION").then(10, 0)

@https_fn.on_request(min_instances=MIN_INSTANCES)
def hello_world(req):
    ...

Do parametrów i wyrażeń parametrów, które są używane tylko w czasie wykonywania, można uzyskać dostęp za pomocą funkcji value:

Node.js

const { onRequest } = require('firebase-functions/v2/https');
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 = onRequest(
(req, res) => {
    res.send(`${welcomeMessage.value()}! I am a function.`);
  }
);

Python

from firebase_functions import https_fn
from firebase_functions.params import StringParam

WELCOME_MESSAGE = StringParam("WELCOME_MESSAGE")

@https_fn.on_request()
def hello_world(req):
    return https_fn.Response(f'{WELCOME_MESSAGE.value()}! I am a function!')

Parametry wbudowane

Pakiet Cloud Functions SDK oferuje 3 predefiniowane parametry dostępne w podpakiecie firebase-functions/params:

Node.js

  • projectID – projekt w chmurze, w którym działa funkcja.
  • databaseURL – adres URL instancji Bazy danych czasu rzeczywistego powiązanej z funkcją (jeśli jest włączona w projekcie w Firebase).
  • storageBucket – zasobnik Cloud Storage powiązany z funkcją (jeśli jest włączony w projekcie w Firebase).

Python

  • PROJECT_ID – projekt w chmurze, w którym działa funkcja.
  • DATABASE_URL – adres URL instancji Bazy danych czasu rzeczywistego powiązanej z funkcją (jeśli jest włączona w projekcie w Firebase).
  • STORAGE_BUCKET – zasobnik Cloud Storage powiązany z funkcją (jeśli jest włączony w projekcie w Firebase).

Te funkcje są pod każdym względem podobne do zdefiniowanych przez użytkownika parametrów ciągu znaków, z tym wyjątkiem, że ich wartości są zawsze znane wierszowi poleceń Firebase, więc nie będą wyświetlane podczas wdrażania ani zapisywane w plikach .env.

Parametry obiektu tajnego

Parametry typu Secret zdefiniowane za pomocą defineSecret() reprezentują parametry ciągu znaków , których wartość jest przechowywana w usłudze Cloud Secret Manager. Zamiast sprawdzać lokalny plik .env i zapisywać w nim nową wartość, jeśli jej brakuje, parametry obiektu tajnego sprawdzają, czy obiekt tajny istnieje w usłudze Cloud Secret Manager, i interaktywnie proszą o wartość nowego obiektu tajnego podczas wdrażania.

Parametry obiektu tajnego muszą być powiązane z poszczególnymi funkcjami, które powinny mieć do nich dostęp:

Node.js

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

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

Python

from firebase_functions import https_fn
from firebase_functions.params import SecretParam

DISCORD_API_KEY = SecretParam('DISCORD_API_KEY')

@https_fn.on_request(secrets=[DISCORD_API_KEY])
def post_to_discord(req):
    api_key = DISCORD_API_KEY.value

Ponieważ wartości obiektów tajnych są ukryte do czasu wykonania funkcji, nie można ich używać podczas konfigurowania funkcji.

Obiekty tajne w formacie JSON

Jeśli masz kilka wartości konfiguracji, które są logicznie powiązane (np. ustawienia usługi innej firmy), możesz je przechowywać razem jako uporządkowany obiekt JSON w jednym obiekcie tajnym za pomocą defineJsonSecret(). To podejście może pomóc w uporządkowaniu konfiguracji i efektywniejszym wykorzystaniu bezpłatnego pakietu Cloud Secret Manager, ponieważ umożliwia przechowywanie grupy powiązanych wartości konfiguracji w jednym obiekcie tajnym.

Wartość przechowywana w usłudze Secret Manager musi być prawidłowym ciągiem znaków JSON. Gdy uzyskasz dostęp do .value(), pakiet SDK automatycznie przeanalizuje ciąg znaków JSON i przekształci go w obiekt JavaScript.

Przykład:

const { onRequest } = require('firebase-functions/v2/https');
const { defineJsonSecret } = require('firebase-functions/params');

// Define a single secret to hold all configuration for some API
const someApiConfig = defineJsonSecret('SOMEAPI_CONFIG');

exports.myApi = onRequest(
  { secrets: [someApiConfig] },
  (req, res) => {
    // someApiConfig.value() automatically parses the JSON secret
    const { apiKey, webhookSecret, clientId } = someApiConfig.value();

    // Now you can use apiKey, webhookSecret, clientId
    // ...
  }
);

Aby utworzyć obiekt tajny SOMEAPI_CONFIG, ustaw jego wartość w usłudze Secret Manager na ciąg znaków JSON, np.:

{
  "apiKey": "key_...",
  "webhookSecret": "secret_...",
  "clientId": "client_..."
}

Jeśli wartość obiektu tajnego nie jest prawidłowym plikiem JSON, dostęp do someApiConfig.value() spowoduje błąd w czasie wykonywania.

Zmienne środowiskowe

Cloud Functions for Firebase obsługuje format pliku dotenv do wczytywania zmiennych środowiskowych określonych w pliku .env do środowiska wykonawczego aplikacji. Po wdrożeniu zmienne środowiskowe można odczytać za pomocą interfejsu process.env (w projektach opartych na Node.js) lub os.environ (w projektach opartych na Pythonie).

Aby skonfigurować środowisko w ten sposób, utwórz w projekcie plik .env, dodaj do niego odpowiednie zmienne i wdróż:

  1. Utwórz plik .env w katalogu functions/:

    # Directory layout:
    #   my-project/
    #     firebase.json
    #     functions/
    #       .env
    #       package.json
    #       index.js
    
  2. Otwórz plik .env do edycji i dodaj odpowiednie klucze. Przykład:

    PLANET=Earth
    AUDIENCE=Humans
    
  3. Wdróż funkcje i sprawdź, czy zmienne środowiskowe zostały wczytane:

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

Po wdrożeniu niestandardowych zmiennych środowiskowych kod funkcji może uzyskać do nich dostęp:

Node.js

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

Python

import os

@https_fn.on_request()
def hello(req):
    return https_fn.Response(
        f"Hello {os.environ.get('PLANET')} and {os.environ.get('AUDIENCE')}"
    )

Wdrażanie wielu zestawów zmiennych środowiskowych

Jeśli potrzebujesz alternatywnego zestawu zmiennych środowiskowych dla projektów Firebase (np. środowiska testowego i produkcyjnego), utwórz plik .env.<project or alias> i zapisz w nim zmienne środowiskowe specyficzne dla projektu. Zmienne środowiskowe z plików .env i .env specyficznych dla projektu (jeśli istnieją) zostaną uwzględnione we wszystkich wdrożonych funkcjach.

Na przykład projekt może zawierać te 3 pliki z nieco innymi wartościami na potrzeby programowania i środowiska produkcyjnego:

.env .env.dev .env.prod
PLANET=Earth

AUDIENCE=Humans

AUDIENCE=Dev Humans AUDIENCE=Prod Humans

Biorąc pod uwagę wartości w tych osobnych plikach, zestaw zmiennych środowiskowych wdrożonych z funkcjami będzie się różnić w zależności od projektu docelowego:

$ 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

Zarezerwowane zmienne środowiskowe

Niektóre klucze zmiennych środowiskowych są zarezerwowane do użytku wewnętrznego. Nie używaj żadnego z tych kluczy w plikach .env:

  • Wszystkie klucze zaczynające się od X_GOOGLE_
  • Wszystkie klucze zaczynające się od EXT_
  • Wszystkie klucze zaczynające się od FIREBASE_
  • Dowolny klucz z tej listy:
  • CLOUD_RUNTIME_CONFIG
  • ENTRY_POINT
  • GCP_PROJECT
  • GCLOUD_PROJECT
  • GOOGLE_CLOUD_PROJECT
  • FUNCTION_TRIGGER_TYPE
  • FUNCTION_NAME
  • FUNCTION_MEMORY_MB
  • FUNCTION_TIMEOUT_SEC
  • FUNCTION_IDENTITY
  • FUNCTION_REGION
  • FUNCTION_TARGET
  • FUNCTION_SIGNATURE_TYPE
  • K_SERVICE
  • K_REVISION
  • PORT
  • K_CONFIGURATION

Przechowywanie poufnych informacji o konfiguracji i uzyskiwanie do nich dostępu

Zmienne środowiskowe przechowywane w plikach .env mogą być używane do konfiguracji funkcji, ale nie należy ich traktować jako bezpiecznego sposobu przechowywania informacji poufnych, takich jak dane logowania do bazy danych czy klucze interfejsu API. Jest to szczególnie ważne, jeśli pliki .env są sprawdzane w systemie kontroli wersji.

Aby ułatwić przechowywanie poufnych informacji o konfiguracji, Cloud Functions for Firebase integruje się z Google Cloud Secret Manager. Ta zaszyfrowana usługa bezpiecznie przechowuje wartości konfiguracji, a jednocześnie umożliwia łatwy dostęp do nich z funkcji w razie potrzeby.

Tworzenie obiektu tajnego i używanie go

Aby utworzyć obiekt tajny, użyj interfejsu Firebase CLI.

Aby utworzyć obiekt tajny i go używać:

  1. W katalogu głównym projektu lokalnego uruchom to polecenie:

    firebase functions:secrets:set SECRET_NAME

  2. Wpisz wartość dla SECRET_NAME.

    Interfejs wiersza poleceń wyświetli komunikat o powodzeniu i ostrzeżenie, że aby zmiana została zastosowana, musisz wdrożyć funkcje.

  3. Przed wdrożeniem upewnij się, że kod funkcji umożliwia jej dostęp do obiektu tajnego za pomocą opcji secrets:

    Node.js

    const { onRequest } = require('firebase-functions/v2/https');
    
    exports.processPayment = onRequest(
      { secrets: ["SECRET_NAME"] },
      (req, res) => {
        const myBillingService = initializeBillingService(
          // reference the secret value
          process.env.SECRET_NAME
        );
        // Process the payment
      }
    );

    Python

    import os
    from firebase_functions import https_fn
    
    @https_fn.on_request(secrets=["SECRET_NAME"])
    def process_payment(req):
        myBillingService = initialize_billing(key=os.environ.get('SECRET_NAME'))
        # Process the payment
        ...
    
  4. Wdróż Cloud Functions:

    firebase deploy --only functions

    Teraz możesz uzyskać do niego dostęp jak do każdej innej zmiennej środowiskowej. Z kolei jeśli inna funkcja, która nie określa obiektu tajnego, spróbuje uzyskać do niego dostęp, otrzyma wartość niezdefiniowaną:

    Node.js

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

    Python

    @https_fn.on_request()
    def another_endpoint(req):
        return https_fn.Response(f"The secret API key is {os.environ.get("SECRET_NAME")}")
        # Responds with "The secret API key is None" because the `secrets` parameter is missing.
    

Po wdrożeniu funkcja będzie mieć dostęp do wartości obiektu tajnego. Tylko funkcje, które wyraźnie uwzględniają obiekt tajny w opcji secrets, będą mieć do niego dostęp jako do zmiennej środowiskowej. Pomaga to zapewnić, że wartości obiektów tajnych są dostępne tylko tam, gdzie są potrzebne, co zmniejsza ryzyko przypadkowego ujawnienia obiektu tajnego.

Zarządzanie obiektami tajnymi

Do zarządzania obiektami tajnymi używaj interfejsu Firebase CLI. Podczas zarządzania obiektami tajnymi w ten sposób pamiętaj, że niektóre zmiany w interfejsie wiersza poleceń wymagają zmodyfikowania lub ponownego wdrożenia powiązanych funkcji. Więcej szczegółów:

  • Za każdym razem, gdy ustawisz nową wartość obiektu tajnego, musisz ponownie wdrożyć wszystkie funkcje, które się do niego odwołują, aby mogły one pobrać najnowszą wartość.
  • Jeśli usuniesz obiekt tajny, upewnij się, że żadna z wdrożonych funkcji się do niego nie odwołuje. Funkcje, które używają usuniętej wartości obiektu tajnego, będą się nie powodzić bez wyświetlania komunikatu.

Oto podsumowanie poleceń interfejsu Firebase CLI do zarządzania obiektami tajnymi:

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

# Set secret from file
firebase functions:secrets:set SECRET_NAME --data-file file.json

# Validate secret value as json
cat file.json | firebase functions:secrets:set SECRET_NAME --format=json

# Pipe from stdin and set secret
cat file.json | firebase functions:secrets:set SECRET_NAME --format=json

# 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

W przypadku poleceń access i destroy możesz podać opcjonalny parametr wersji, aby zarządzać konkretną wersją. Przykład:

functions:secrets:access SECRET_NAME[@VERSION]

Więcej informacji o tych operacjach znajdziesz, przekazując -h wraz z poleceniem, aby wyświetlić pomoc interfejsu wiersza poleceń.

Jak rozliczane są obiekty tajne

Secret Manager umożliwia bezpłatne korzystanie z 6 aktywnych wersji obiektów tajnych. Oznacza to, że w projekcie Firebase możesz mieć bezpłatnie 6 obiektów tajnych miesięcznie.

Domyślnie interfejs Firebase CLI próbuje automatycznie usuwać nieużywane wersje obiektów tajnych, np. gdy wdrażasz funkcje z nową wersją obiektu tajnego. Możesz też aktywnie usuwać nieużywane obiekty tajne za pomocą poleceń functions:secrets:destroy i functions:secrets:prune.

Secret Manager umożliwia 10 tys. bezpłatnych operacji dostępu do obiektu tajnego miesięcznie na secret. Instancje funkcji odczytują tylko obiekty tajne określone w opcji secrets za każdym razem, gdy następuje uruchomienie „na zimno”. Jeśli masz wiele instancji funkcji, które odczytują wiele obiektów tajnych, Twój projekt może przekroczyć ten limit. W takim przypadku zostanie naliczona opłata w wysokości 0,03 USD za 10 tys. operacji dostępu.

Więcej informacji znajdziesz w Secret Manager cenniku.

Obsługa emulatora

Konfiguracja środowiska za pomocą dotenv jest zaprojektowana tak, aby współpracować z lokalnym Cloud Functions emulatorem.

Gdy używasz lokalnego Cloud Functions emulatora, możesz zastąpić zmienne środowiskowe projektu, konfigurując plik .env.local. Zawartość pliku .env.local ma pierwszeństwo przed plikiem .env i plikiem .env specyficznym dla projektu.

Na przykład projekt może zawierać te 3 pliki z nieco innymi wartościami na potrzeby programowania i testowania lokalnego:

.env .env.dev .env.local
PLANET=Earth

AUDIENCE=Humans

AUDIENCE=Dev Humans AUDIENCE=Local Humans

Po uruchomieniu w kontekście lokalnym emulator wczytuje zmienne środowiskowe w ten sposób:

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

Obiekty tajne i dane logowania w emulatorze Cloud Functions

Emulator Cloud Functions obsługuje używanie obiektów tajnych do przechowywania poufnych informacji o konfiguracji i uzyskiwania do nich dostępu. Domyślnie emulator będzie próbował uzyskać dostęp do obiektów tajnych w środowisku produkcyjnym za pomocą domyślnych danych logowania aplikacji. W niektórych sytuacjach, np. w środowiskach CI, emulator może nie mieć dostępu do wartości obiektów tajnych z powodu ograniczeń uprawnień.

Podobnie jak w przypadku obsługi zmiennych środowiskowych w Cloud Functions emulatorze, możesz zastąpić wartości obiektów tajnych, konfigurując plik .secret.local. Ułatwia to testowanie funkcji lokalnie, zwłaszcza jeśli nie masz dostępu do wartości obiektu tajnego.

Migracja z konfiguracji środowiska wykonawczego

Interfejs functions.config API został wycofany i zostanie wyłączony w marcu 2027 r. Po tym terminie wdrożenia z functions.config będą się nie powodzić.

Aby zapobiec niepowodzeniom wdrożenia, przeprowadź migrację konfiguracji do usługi Cloud Secret Manager za pomocą interfejsu Firebase CLI. Jest to zdecydowanie zalecane jako najskuteczniejszy i najbezpieczniejszy sposób migracji konfiguracji.

  1. Eksportowanie konfiguracji za pomocą interfejsu Firebase CLI

    Użyj polecenia config export, aby wyeksportować dotychczasową konfigurację środowiska do nowego obiektu tajnego w usłudze Cloud Secret Manager:

    $ firebase functions:config:export
    i  This command retrieves your Runtime Config values (accessed via functions.config())
       and exports them as a Secret Manager secret.
    
    i  Fetching your existing functions.config() from your project...     Fetched your existing functions.config().
    
    i  Configuration to be exported:
    ⚠  This may contain sensitive data. Do not share this output.
    
    {
       ...
    } What would you like to name the new secret for your configuration? RUNTIME_CONFIG
    
    ✔  Created new secret version projects/project/secrets/RUNTIME_CONFIG/versions/1```
    
  2. Aktualizowanie kodu funkcji w celu powiązania obiektów tajnych

    Aby używać konfiguracji przechowywanej w nowym obiekcie tajnym w usłudze Cloud Secret Manager, użyj w kodzie funkcji interfejsu defineJsonSecret API. Upewnij się też, że obiekty tajne są powiązane ze wszystkimi funkcjami, które ich potrzebują.

    Przed

    const functions = require("firebase-functions/v1");
    
    exports.myFunction = functions.https.onRequest((req, res) => {
      const apiKey = functions.config().someapi.key;
      // ...
    });
    

    Po

    const { onRequest } = require("firebase-functions/v2/https");
    const { defineJsonSecret } = require("firebase-functions/params");
    
    const config = defineJsonSecret("RUNTIME_CONFIG");
    
    exports.myFunction = onRequest(
      // Bind secret to your function
      { secrets: [config] },
      (req, res) => {
        // Access secret values via .value()
        const apiKey = config.value().someapi.key;
        // ...
    });
    
  3. Wdrażanie funkcji

    Wdróż zaktualizowane funkcje, aby zastosować zmiany i powiązać uprawnienia do obiektu tajnego.

    firebase deploy --only functions:<your-function-name>
    

Automatycznie wypełniane zmienne środowiskowe

Istnieją zmienne środowiskowe, które są automatycznie wypełniane w środowisku wykonawczym funkcji i w funkcjach emulowanych lokalnie. Obejmują one zmienne wypełniane przez Google Cloud, a także zmienną środowiskową specyficzną dla Firebase:

process.env.FIREBASE_CONFIG: zawiera te informacje o konfiguracji projektu w Firebase:

{
  databaseURL: 'https://DATABASE_NAME.firebaseio.com',
  storageBucket: 'PROJECT_ID.firebasestorage.app',
  projectId: 'PROJECT_ID'
}

Pamiętaj, że wartości w rzeczywistej konfiguracji Firebase mogą się różnić w zależności od zasobów, które zostały udostępnione w projekcie.

Ta konfiguracja jest stosowana automatycznie, gdy inicjujesz pakiet Firebase Admin SDK bez argumentów. Jeśli piszesz funkcje w JavaScript, zainicjuj je w ten sposób:

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

Jeśli piszesz funkcje w TypeScript, zainicjuj je w ten sposób:

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

Jeśli musisz zainicjować pakiet Admin SDK z domyślną konfiguracją projektu przy użyciu danych logowania konta usługi, możesz wczytać dane logowania z pliku i dodać je do FIREBASE_CONFIG w ten sposób:

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

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