設定環境


通常,您需要針對函式進行其他設定,例如第三方 API 金鑰或可調整的設定。Firebase SDK for Cloud Functions 提供內建的環境設定,可讓您輕鬆為專案儲存和擷取這類資料。

您可以選擇以下三種選項:

  • 參數化設定 (適用於大多數情境)。如此一來,您就能使用在部署時驗證的參數來提供強型類型的環境設定,避免發生錯誤並簡化偵錯作業。
  • 環境變數的檔案型設定。使用這個方法時,您必須手動建立 dotenv 檔案來載入環境變數。
  • 執行階段環境設定只能使用 Firebase CLI 和 functions.config (Cloud Functions (第 1 代))。

在大多數用途中,建議採用參數化設定。此方法會在執行階段和部署時間提供設定值。此外,除非所有參數都具備有效的值,否則系統會封鎖部署作業。相反地,在部署時無法使用具有環境變數的設定。

參數化設定

Cloud Functions for Firebase 提供的介面可讓您在程式碼集中,以宣告的方式定義設定參數。在函式部署期間、設定部署和執行階段選項,以及執行期間,皆可使用這些參數值。這表示除非所有參數都具備有效值,否則 CLI 會封鎖部署。

如要在程式碼中定義參數,請遵循以下模型:

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.`);
  }
);

部署具有參數化設定變數的函式時,Firebase CLI 會先嘗試從本機 .env 檔案載入其值。如果這些檔案沒有出現在這些檔案中,而且未設定 default,CLI 會在部署期間提示輸入值,然後自動將這些值儲存到 functions/ 目錄中名為 .env.<project_ID>.env 檔案:

$ 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> 檔案新增至版本管控或許會有幫助。

設定 CLI 行為

您可以使用 Options 物件設定參數,控制 CLI 如何提示值。下例將設定驗證電話號碼格式、提供簡單的選取選項,以及自動填入 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 的密鑰。支援的類型如下:

  • 密鑰
  • 字串
  • 布林值
  • 整數
  • 浮點值

參數值和運算式

Firebase 會在部署時和函式執行時評估參數。由於這些雙重環境,在比較參數值,以及使用這些值設定函式的執行階段選項時,您都必須特別留意。

如要將參數做為執行階段選項傳遞至函式,請直接將其傳遞:

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) => {
    //…

此外,如果您需要與參數比較,才能得知要選擇的選項,您將需要使用內建比較器,而不是檢查值:

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) => {
    //…

您可以透過 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.`);
  }
);

內建參數

Cloud Functions SDK 提供三個預先定義的參數,可從 firebase-functions/params 子套件取得:

  • projectID:執行函式的 Cloud 專案。
  • databaseURL:與函式相關聯的即時資料庫執行個體網址 (如果在 Firebase 專案中啟用的話)。
  • storageBucket:與函式相關聯的 Cloud Storage 值區 (如果在 Firebase 專案中啟用的話)。

這些函式在各種方面都會像使用者定義的字串參數一樣,但其值一律是 Firebase CLI 知道的值,因此在部署時,系統一律不會提示其值,也不會儲存至 .env 檔案。

密鑰參數

Secret 類型的參數 (使用 defineSecret() 定義) 代表已在 Cloud Secret Manager 中儲存值的字串參數。如果缺少,則密鑰參數會檢查 Cloud Secret Manager 中是否存在,而不是檢查本機 .env 檔案並將新值寫入檔案,並在部署期間以互動方式提示輸入新密鑰的值。

以這種方式定義的 Secret 參數必須繫結至應可存取這些參數的個別函式:

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();
    //…

由於密鑰的值在執行函式之前會隱藏,因此無法在設定函式時使用這些值。

環境變數

Cloud Functions for Firebase 支援 dotenv 檔案格式,將 .env 檔案中指定的環境變數載入至應用程式執行階段。部署完成後,您可以透過 process.env 介面讀取環境變數。

如要以這種方式設定環境,請在專案中建立 .env 檔案、新增需要的變數,然後進行部署:

  1. functions/ 目錄中建立 .env 檔案:

    # Directory layout:
    #   my-project/
    #     firebase.json
    #     functions/
    #       .env
    #       package.json
    #       index.js
    
  2. 開啟 .env 檔案進行編輯,並加入所需的金鑰。例如:

    PLANET=Earth
    AUDIENCE=Humans
    
  3. 部署函式並確認已載入環境變數:

    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=人類

AUDIENCE=Dev 人類 AUDIENCE=專業人類

考量到這些個別檔案中的值,以函式部署的環境變數組合會因目標專案而有所不同:

$ 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 CLI。

如何建立及使用密鑰:

  1. 在本機專案目錄的根目錄中執行下列指令:

    firebase functions:secrets:set SECRET_NAME

  2. 輸入 SECRET_NAME 的值。

    CLI 會回應成功訊息,並警告您必須部署函式,變更才會生效。

  3. 部署之前,請確認您的函式程式碼允許函式使用 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. 部署 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 管理密鑰。以這種方式管理密鑰時,請注意部分 CLI 變更需要您修改和/或重新部署相關函式。詳細說明:

  • 每次為密鑰設定新值時,您必須重新部署所有參照該密鑰的函式,以便取得最新的值。
  • 如果刪除密鑰,請確保您部署的函式均未參照該密鑰。如果函式使用已遭刪除的密鑰值,則函式會失敗,而且不會顯示相關通知。

以下摘要說明用於管理密鑰的 Firebase CLI 指令:

# 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

對於 accessdestroy 指令,您可以提供選用的版本參數來管理特定版本。例如:

functions:secrets:access SECRET_NAME[@VERSION]

如要進一步瞭解這些作業,請透過指令傳遞 -h,以查看 CLI 說明。

密鑰的計費方式

Secret Manager 可讓您免付費使用 6 個有效的密鑰versions。這代表您每個月可在 Firebase 專案中建立 6 組密鑰,無須額外付費。

根據預設,Firebase CLI 會在適當情況下嘗試自動刪除未使用的密鑰版本,例如使用新版密鑰部署函式時。此外,您也可以使用 functions:secrets:destroyfunctions:secrets:prune 主動清除未使用的密鑰。

Secret Manager 每個月允許對密鑰進行 10,000 次未計費的存取作業,每當函式執行個體冷啟動時,函式執行個體都只會讀取 runWith 參數中指定的密鑰。如果您有許多函式執行個體讀取大量密鑰,您的專案可能會超過這個上限,因此每 10,000 次存取作業必須支付 $0.03 美元。

詳情請參閱 Secret Manager 定價

模擬器支援

含有 dotenv 的環境設定是用來與本機 Cloud Functions 模擬器互通。

使用本機 Cloud Functions 模擬器時,您可以設定 .env.local 檔案來覆寫專案的環境變數。.env.local 的內容優先於 .env 和專案專屬的 .env 檔案。

舉例來說,專案可以包含以下三個檔案,其中含有用於開發和本機測試略有不同的值:

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

AUDIENCE=人類

AUDIENCE=Dev 人類 AUDIENCE=當地人力

在本機環境中啟動時,模擬器會載入環境變數,如下所示:

  $ 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 使用環境設定,可以將現有的設定以環境變數 (dotenv 格式) 的形式遷移。Firebase CLI 提供匯出指令,可將目錄 .firebaserc 檔案 (如下方範例中:localdevprod) 中所列的每個別名或專案設定輸出為 .env 檔案。

如要遷移,請使用 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

請注意,在某些情況下,系統會提示您輸入前置字串,以重新命名匯出的環境變數金鑰。這是因為部分設定可能無效,或可能為保留的環境變數金鑰,所以無法自動轉換。

部署函式或檢查 .env 檔案到來源控制項之前,建議您仔細查看產生的 .env 檔案的內容。如果有機密資料不應外洩,請將其從 .env 檔案中移除,並改儲存在 Secret Manager 中。

此外,您也需要更新函式程式碼。使用 functions.config 的所有函式現在都必須改用 process.env,如升級至第 2 代所示。

環境設定

firebase-functions v3.18.0 中發布環境變數支援之前,建議您使用 functions.config() 來設定環境。系統仍然支援這個方法,但建議所有新專案改用環境變數,因為這樣較容易使用,也能夠改善程式碼的可攜性。

使用 CLI 進行環境設定

如要儲存環境資料,您可以使用 Firebase CLI 中的 firebase functions:config:set 指令。每個鍵都可以使用半形句號進行命名空間,將相關的設定分類。請注意,鍵中只能使用小寫字元,而且不得使用大寫字母。

舉例來說,如要儲存「部分服務」的用戶端 ID 和 API 金鑰,可以執行:

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

擷取目前的環境設定

如要檢查目前儲存在專案環境設定中的內容,可使用 firebase functions:config:get。輸出 JSON 會如下所示:

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

這項功能以 Google Cloud Runtime Configuration API 為基礎。

使用 functions.config 存取函式中的環境設定

部分設定會自動在預留的 firebase 命名空間下提供。執行中的函式可以透過 functions.config() 提供環境設定。如要使用上述設定,您的程式碼可能會如下所示:

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}
  });
});

使用環境設定初始化模組

部分 Node 模組已就緒,無須進行任何設定。其他模組需要額外的設定才能正確初始化。建議您將這項設定儲存在環境變數變數中,而不要以硬式編碼的方式寫入。這有助於讓程式碼的可攜性更大,進而開放原始碼應用程式,或輕鬆在實際工作環境與測試版本之間切換。

舉例來說,如要使用 Slack Node SDK 模組,您可以編寫以下內容:

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

在部署之前,請先設定 slack.url 環境變數:

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

其他環境指令

  • firebase functions:config:unset key1 key2 會從設定中移除指定的鍵
  • firebase functions:config:clone --from <fromProject> 會將其他專案的環境複製到目前進行中的專案。

自動填入的環境變數

函式執行階段和本機模擬函式中都會自動填入各種環境變數。這些變數包括 Google Cloud 填入的資料,以及 Firebase 專用的環境變數:

process.env.FIREBASE_CONFIG:提供下列 Firebase 專案設定資訊:

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

在不使用引數的情況下初始化 Firebase Admin SDK 時,系統會自動套用這項設定。如要使用 JavaScript 編寫函式,請依以下方式初始化函式:

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

如要使用 TypeScript 編寫函式,請初始化如下:

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import 'firebase-functions';
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);