Часто для функций требуется дополнительная настройка, например ключи сторонних API или регулируемые параметры. В Firebase SDK для Cloud Functions есть встроенная конфигурация среды, которая позволяет легко хранить и извлекать данные для проекта.
Можно выбрать один из следующих вариантов:
- Конфигурация с параметрами (рекомендуется в большинстве случаев). Это позволяет задавать конфигурацию среды с помощью параметров, которые проверяются во время развертывания, что предотвращает ошибки и упрощает отладку.
- Настройка переменных среды на основе файлов. В этом случае вы вручную создаете файл dotenv для загрузки переменных среды.
В большинстве случаев рекомендуется использовать параметризованную конфигурацию. При таком подходе значения конфигурации доступны как во время выполнения, так и во время развертывания, и развертывание блокируется, если у всех параметров нет действительного значения. И наоборот, конфигурация с переменными среды недоступна во время развертывания.
Конфигурация с параметрами
Cloud Functions for Firebase предоставляет интерфейс для декларативного определения параметров конфигурации в коде. Значения этих параметров доступны как при развертывании функции, когда задаются параметры развертывания и выполнения, так и во время выполнения. Это означает, что CLI заблокирует развертывание, если хотя бы один параметр имеет недопустимое значение.
Чтобы задать параметры в коде, используйте следующую модель:
const functions = require('firebase-functions/v1');
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.`);
}
);
При развертывании функции с параметризованными переменными конфигурации интерфейс командной строки Firebase сначала пытается загрузить их значения из локальных файлов .env. Если их нет в этих файлах и не задано значение default, при развертывании CLI запросит значения, а затем автоматически сохранит их в файле .env с названием .env.<project_ID> в каталоге 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
В зависимости от рабочего процесса разработки может быть полезно добавить сгенерированный файл .env.<project_ID> в систему управления версиями.
Использование параметров в глобальной области действия
Во время развертывания код функций загружается и проверяется до того, как параметры получают фактические значения. Это означает, что получение значений параметров в глобальной области действия приводит к сбою развертывания. Если вы хотите использовать параметр для инициализации глобального значения, используйте обратный вызов инициализации onInit(). Этот обратный вызов выполняется до того, как в рабочей среде будут запущены какие-либо функции, но не вызывается во время развертывания, поэтому он является безопасным местом для доступа к значению параметра.
const { GoogleGenerativeAI } = require('@google/generative-ai');
const { defineSecret } = require('firebase-functions/params');
const { onInit } = require('firebase-functions/v1');
const apiKey = defineSecret('GOOGLE_API_KEY');
let genAI;
onInit(() => {
genAI = new GoogleGenerativeAI(apiKey.value());
})
Как настроить поведение CLI
Параметры можно настроить с помощью объекта Options, который определяет, как интерфейс командной строки будет запрашивать значения. В примере ниже показано, как задать параметры для проверки формата номера телефона, предоставить простой вариант выбора и автоматически заполнить вариант выбора из проекта 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"})
Типы параметров
Параметризованная конфигурация обеспечивает строгую типизацию значений параметров и поддерживает секреты из Cloud Secret Manager. Поддерживаются следующие типы:
- Секрет
- Строка
- Логическое значение
- Целое число
- Число с плавающей запятой
Информацию о функциях для определения параметров можно найти в справочнике по пространству имен params.
Значения параметров и выражения
Firebase оценивает параметры как во время развертывания, так и во время выполнения функции. Из-за этих двух сред при сравнении значений параметров и их использовании для настройки параметров выполнения функций нужно быть особенно внимательным.
Чтобы передать параметр в функцию в качестве параметра времени выполнения, передайте его напрямую:
const functions = require('firebase-functions/v1');
const { defineInt} = require('firebase-functions/params');
const minInstancesConfig = defineInt('HELLO_WORLD_MININSTANCES');
export const helloWorld = functions.runWith({ minInstances: minInstancesConfig}).https.onRequest(
(req, res) => {
//…
Кроме того, если вам нужно сравнить параметр, чтобы выбрать вариант, используйте встроенные компараторы вместо проверки значения:
const functions = require('firebase-functions/v1');
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) => {
//…
Параметры и выражения параметров, которые используются только во время выполнения, можно получить с помощью функции value:
const functions = require('firebase-functions/v1');
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.`);
}
);
Встроенные параметры
В SDK Cloud Functions есть три стандартных параметра, доступных из подпакета firebase-functions/params:
projectID– облачный проект, в котором выполняется функция.databaseURL– URL экземпляра Realtime Database, связанного с функцией (если он включен в проекте Firebase).storageBucket– сегмент Cloud Storage, связанный с функцией (если он включен в проекте Firebase).
Эти функции во всех отношениях работают как заданные пользователем строковые параметры, за исключением того, что их значения всегда известны интерфейсу командной строки Firebase, поэтому при развертывании они не запрашиваются и не сохраняются в файлах .env.
Параметры секрета
Параметры типа Secret, определенные с помощью defineSecret(), представляют собой строковые параметры, значения которых хранятся в Cloud Secret Manager. Вместо того чтобы проверять наличие секрета в локальном файле .env и записывать в него новое значение, если оно отсутствует, параметры секрета проверяют наличие секрета в Cloud Secret Manager и интерактивно запрашивают значение нового секрета во время развертывания.
Секретные параметры, определенные таким образом, должны быть связаны с отдельными функциями, которые должны иметь к ним доступ:
const functions = require('firebase-functions/v1');
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();
//…
Переменные среды
Cloud Functions for Firebase поддерживает формат файлов dotenv для загрузки переменных среды, указанных в файле .env, в среду выполнения приложения. После развертывания переменные среды можно прочитать через интерфейс process.env.
Чтобы настроить среду таким образом, создайте в проекте файл .env, добавьте нужные переменные и выполните развертывание:
Создайте файл
.envв каталогеfunctions/:# Directory layout: # my-project/ # firebase.json # functions/ # .env # package.json # index.jsОткройте файл
.envдля редактирования и добавьте нужные ключи. Пример:PLANET=Earth AUDIENCE=HumansРазверните функции и убедитесь, что переменные среды загружены:
firebase deploy --only functions # ... # i functions: Loaded environment variables from .env. # ...
После того как вы развернете пользовательские переменные среды, код функции сможет получить к ним доступ с помощью синтаксиса 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}`);
});
Как развернуть несколько наборов переменных среды
Если вам нужен альтернативный набор переменных среды для проектов Firebase (например, для подготовки и выпуска), создайте файл .env.<project or
alias> и запишите в него переменные среды для конкретного проекта. Переменные среды из файлов .env и .env (если они существуют) будут включены во все развернутые функции.
Например, проект может включать три файла с немного отличающимися значениями для разработки и производства:
.env
|
.env.dev
|
.env.prod
|
| PLANET=Earth
AUDIENCE=Humans |
AUDIENCE=Dev Humans | AUDIENCE=Prod Humans |
Учитывая значения в этих отдельных файлах, набор переменных среды, развернутых с вашими функциями, будет зависеть от целевого проекта:
$ 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
Зарезервированные переменные среды
Некоторые ключи переменных среды зарезервированы для внутреннего использования. Не используйте в файлах .env следующие ключи:
- Все ключи, начинающиеся с X_GOOGLE_
- Все ключи, начинающиеся с EXT_
- Все ключи, начинающиеся с FIREBASE_.
- Любая клавиша из следующего списка:
- 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
Хранение и доступ к конфиденциальной информации о конфигурации
Переменные среды, хранящиеся в файлах .env, можно использовать для настройки функций, но не следует считать их безопасным способом хранения конфиденциальной информации, такой как учетные данные базы данных или ключи API. Это особенно важно, если вы добавляете файлы .env в систему управления версиями.
Чтобы помочь вам хранить конфиденциальную информацию о конфигурации, Cloud Functions for Firebase интегрируется с Google Cloud Secret Manager. Этот зашифрованный сервис надежно хранит значения конфигурации и при этом позволяет функциям легко получать к ним доступ при необходимости.
Как создать и использовать секрет
Чтобы создать секрет, используйте интерфейс командной строки Firebase.
Чтобы создать и использовать секрет:
В корневом каталоге локального проекта выполните следующую команду:
firebase functions:secrets:set SECRET_NAME
Введите значение для параметра SECRET_NAME.
Интерфейс командной строки выводит сообщение об успешном выполнении и предупреждает, что для вступления изменений в силу необходимо развернуть функции.
Перед развертыванием убедитесь, что код функции позволяет ей получить доступ к секрету с помощью параметра
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 });Развертывание Cloud Functions:
firebase deploy --only functions
Теперь вы сможете получить к ней доступ, как к любой другой переменной среды.
Если другая функция, в которой секрет не указан в runWith, попытается получить доступ к секрету, она получит неопределенное значение:
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
});
После развертывания функции она получит доступ к значению секрета. Только функции, в параметре runWith которых указан секрет, будут иметь доступ к этому секрету как к переменной среды. Это позволяет убедиться, что секретные значения доступны только там, где они необходимы, и снижает риск случайной утечки.
Управление секретами
Для управления секретами используйте интерфейс командной строки Firebase. При управлении секретами таким образом помните, что некоторые изменения в CLI требуют изменения и/или повторного развертывания связанных функций. Таким образом, перестанут работать следующие функции:
- При каждом изменении значения секрета необходимо повторно развернуть все функции, которые ссылаются на него, чтобы они могли использовать новое значение.
- Если вы удалите секрет, убедитесь, что ни одна из развернутых функций не ссылается на него. Функции, использующие удаленный секретный код, будут завершаться без уведомлений.
Ниже приведены команды интерфейса командной строки Firebase для управления секретами.
# 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
Для команд access и destroy можно указать необязательный параметр version, чтобы управлять определенной версией. Пример:
functions:secrets:access SECRET_NAME[@VERSION]
Чтобы получить больше информации об этих операциях, передайте команду -h с командой для просмотра справки по интерфейсу командной строки.
Как оплачиваются секреты
Secret Manager позволяет бесплатно использовать до шести активных версий секретов. Это значит, что в проекте Firebase можно бесплатно хранить до шести секретов в месяц.
По умолчанию интерфейс командной строки Firebase пытается автоматически уничтожить неиспользуемые версии секретов, например при развертывании функций с новой версией секрета. Вы также можете активно удалять неиспользуемые секреты с помощью команд functions:secrets:destroy и functions:secrets:prune.
Secret Manager позволяет выполнять 10 000 неоплачиваемых операций доступа в месяц к секрету. Экземпляры функций считывают только секреты, указанные в их параметре secrets, каждый раз при холодном запуске. Если у вас много экземпляров функций, которые считывают много секретов, ваш проект может превысить это ограничение, после чего с вас будет взиматься плата в размере 0,03 долл.США за каждые 10 000 операций доступа.
Подробнее о ценах на Secret Manager…
Поддержка эмуляторов
Конфигурация среды с помощью dotenv предназначена для взаимодействия с локальным эмулятором Cloud Functions.
При использовании локального эмулятора Cloud Functions можно переопределить переменные среды для проекта, настроив файл .env.local. Содержимое файла .env.local имеет приоритет над файлами .env и .env, относящимися к определенному проекту.
Например, в проекте могут быть три файла с немного отличающимися значениями для разработки и локального тестирования:
.env
|
.env.dev
|
.env.local
|
| PLANET=Earth
AUDIENCE=Humans |
AUDIENCE=Dev Humans | AUDIENCE=Local Humans |
При запуске в локальном контексте эмулятор загружает переменные среды, как показано ниже.
$ firebase emulators:start
i emulators: Starting emulators: functions
# Starts emulator with following environment variables:
# PLANET=Earth
# AUDIENCE=Local Humans
Секреты и учетные данные в эмуляторе Cloud Functions
Эмулятор Cloud Functions поддерживает использование секретов для хранения конфиденциальной информации о конфигурации и доступа к ней. По умолчанию эмулятор попытается получить доступ к секретам рабочей среды, используя учетные данные по умолчанию. В некоторых ситуациях, например в средах CI, эмулятор может не получить доступ к секретным значениям из-за ограничений разрешений.
Как и в случае с поддержкой переменных среды в эмуляторе Cloud Functions, вы можете переопределить значения секретов, настроив файл .secret.local. Это позволяет легко тестировать функции локально, особенно если у вас нет доступа к секретному значению.
Перенос из конфигурации среды выполнения
Поддержка functions.config API прекратится в марте 2027 г.
После этой даты развертывания с использованием functions.config будут завершаться с ошибкой.
Чтобы избежать сбоев при развертывании, перенесите конфигурацию в Cloud Secret Manager с помощью интерфейса командной строки Firebase. Мы настоятельно рекомендуем использовать этот способ, так как он наиболее эффективен и безопасен.
Экспорт конфигурации с помощью интерфейса командной строки Firebase
Чтобы экспортировать существующую конфигурацию среды в новый секрет в Cloud Secret Manager, используйте команду
config export:$ 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```Как обновить код функции, чтобы привязать секреты
Чтобы использовать конфигурацию, хранящуюся в новом секрете в Cloud Secret Manager, используйте API
defineJsonSecretв источнике функции. Также убедитесь, что секреты привязаны ко всем функциям, которым они нужны.До
const functions = require("firebase-functions/v1"); exports.myFunction = functions.https.onRequest((req, res) => { const apiKey = functions.config().someapi.key; // ... });После
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; // ... });Как развернуть функции
Разверните обновленные функции, чтобы применить изменения и привязать разрешения для секрета.
firebase deploy --only functions:<your-function-name>
Автоматически заполняемые переменные среды
В среде выполнения функций и в локально эмулируемых функциях автоматически заполняются переменные среды. К ним относятся те, которые заполняются Google Cloud, а также переменная среды, относящаяся к Firebase:
process.env.FIREBASE_CONFIG: предоставляет следующую информацию о конфигурации проекта Firebase:
{
databaseURL: 'https://DATABASE_NAME.firebaseio.com',
storageBucket: 'PROJECT_ID.firebasestorage.app ',
projectId: 'PROJECT_ID'
}
Обратите внимание, что значения в вашей конфигурации Firebase могут отличаться в зависимости от ресурсов, предоставленных в вашем проекте.
Эта конфигурация применяется автоматически при инициализации Firebase Admin SDK без аргументов. Если вы пишете функции на JavaScript, инициализируйте их следующим образом:
const admin = require('firebase-admin');
admin.initializeApp();
Если вы пишете функции на TypeScript, инициализируйте их следующим образом:
import * as functions from 'firebase-functions/v1';
import * as admin from 'firebase-admin';
import 'firebase-functions/v1';
admin.initializeApp();
Если вам нужно инициализировать Admin SDK с конфигурацией проекта по умолчанию, используя учетные данные сервисного аккаунта, вы можете загрузить их из файла и добавить в FIREBASE_CONFIG следующим образом:
serviceAccount = require('./serviceAccount.json');
const adminConfig = JSON.parse(process.env.FIREBASE_CONFIG);
adminConfig.credential = admin.credential.cert(serviceAccount);
admin.initializeApp(adminConfig);