กำหนดค่าสภาพแวดล้อม

ในหลายๆ กรณี คุณจะต้องกำหนดค่าเพิ่มเติมสำหรับฟังก์ชัน เช่น คีย์ API ของบุคคลที่สามหรือการตั้งค่าที่ปรับได้ SDK สำหรับ Cloud Functions มีการกำหนดค่าสภาพแวดล้อมในตัวเพื่อให้จัดเก็บและดึงข้อมูลประเภทนี้สำหรับโปรเจ็กต์ได้ง่ายFirebase

คุณสามารถเลือกตัวเลือกใดตัวเลือกหนึ่งต่อไปนี้

  • การกำหนดค่าแบบมีพารามิเตอร์ (แนะนำสำหรับสถานการณ์ส่วนใหญ่) ซึ่งให้การกำหนดค่าสภาพแวดล้อมแบบกำหนดประเภทอย่างเข้มงวดด้วยพารามิเตอร์ที่ได้รับการตรวจสอบความถูกต้องในเวลาที่ทำให้ใช้งานได้ ซึ่งจะช่วยป้องกันข้อผิดพลาดและทำให้การแก้ไขข้อบกพร่องง่ายขึ้น
  • การกำหนดค่าตัวแปรสภาพแวดล้อมแบบอิงตามไฟล์ ด้วยวิธีนี้ คุณจะต้องสร้างไฟล์ dotenv เพื่อโหลด ตัวแปรสภาพแวดล้อมด้วยตนเอง

เราขอแนะนำให้ใช้การกำหนดค่าแบบมีพารามิเตอร์สำหรับ Use Case ส่วนใหญ่ เนื่องจากวิธีนี้จะทำให้ค่าการกำหนดค่าพร้อมใช้งานทั้งในรันไทม์และเวลาที่ทำให้ใช้งานได้ และระบบจะบล็อกการทำให้ใช้งานได้หากพารามิเตอร์ทั้งหมดมีค่าไม่ถูกต้อง ในทางกลับกัน การกำหนดค่าด้วยตัวแปรสภาพแวดล้อมจะไม่พร้อมใช้งานในเวลาที่ทำให้ใช้งานได้

การกำหนดค่าแบบมีพารามิเตอร์

Cloud Functions for Firebase มีอินเทอร์เฟซสำหรับกำหนดพารามิเตอร์การกำหนดค่า แบบประกาศภายในฐานของโค้ด ค่าของพารามิเตอร์เหล่านี้จะพร้อมใช้งานทั้งในระหว่างการทำให้ฟังก์ชันใช้งานได้ เมื่อตั้งค่าตัวเลือกการทำให้ใช้งานได้และรันไทม์ รวมถึงในระหว่างการดำเนินการ ซึ่งหมายความว่า CLI จะบล็อกการทำให้ใช้งานได้หากพารามิเตอร์ทั้งหมดมีค่าไม่ถูกต้อง

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!')

เมื่อทำให้ฟังก์ชันที่มีตัวแปรการกำหนดค่าแบบมีพารามิเตอร์ใช้งานได้ Firebase CLI จะพยายามโหลดค่าจากไฟล์ .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() การเรียกกลับนี้จะทำงานก่อนที่ฟังก์ชันใดๆ จะทำงานในเวอร์ชันที่ใช้งานจริง แต่จะไม่ถูกเรียกในเวลาที่ทำให้ใช้งานได้ ดังนั้นจึงเป็นตำแหน่งที่ปลอดภัยในการเข้าถึงค่าของพารามิเตอร์

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)

หากใช้พารามิเตอร์ประเภท Secret โปรดทราบว่าพารามิเตอร์ดังกล่าวจะพร้อมใช้งานเฉพาะในกระบวนการของฟังก์ชันที่ผูกข้อมูลลับไว้เท่านั้น หากผูกข้อมูลลับไว้ในบางฟังก์ชันเท่านั้น ให้ตรวจสอบว่า secret.value() เป็นค่าเท็จก่อนที่จะใช้

กำหนดค่าลักษณะการทำงานของ CLI

คุณกำหนดค่าพารามิเตอร์ด้วยออบเจ็กต์ Options ที่ควบคุมวิธีที่ CLI จะแจ้งให้ป้อนค่าได้ ตัวอย่างต่อไปนี้แสดงการตั้งค่าตัวเลือกเพื่อตรวจสอบรูปแบบหมายเลขโทรศัพท์ เพื่อแสดงตัวเลือกการเลือกแบบง่าย และเพื่อป้อนตัวเลือกการเลือกจากโปรเจ็กต์ 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",
)

ประเภทพารามิเตอร์

การกำหนดค่าแบบมีพารามิเตอร์จะกำหนดประเภทอย่างเข้มงวดสำหรับค่าพารามิเตอร์ และยังรองรับข้อมูลลับจาก Secret Manager ของ Cloud ด้วย ประเภทที่รองรับมีดังนี้

  • ข้อมูลลับ
  • สตริง
  • บูลีน
  • จำนวนเต็ม
  • ทศนิยม
  • รายการ (Node.js)
  • ข้อมูลลับ JSON (Node.js)

ดูข้อมูลเกี่ยวกับฟังก์ชันสำหรับการกำหนดพารามิเตอร์ได้ที่ข้อมูลอ้างอิงเนมสเปซ params

ค่าและนิพจน์ของพารามิเตอร์

Firebase จะประเมินพารามิเตอร์ทั้งในเวลาที่ทำให้ใช้งานได้และขณะที่ฟังก์ชันกำลังทำงาน เนื่องจากมีสภาพแวดล้อม 2 แบบ คุณจึงต้องระมัดระวังเป็นพิเศษเมื่อ เปรียบเทียบค่าพารามิเตอร์และเมื่อใช้ค่าเหล่านั้นเพื่อตั้งค่าตัวเลือกการรันไทม์ สำหรับฟังก์ชัน

หากต้องการส่งพารามิเตอร์ไปยังฟังก์ชันเป็นตัวเลือกการรันไทม์ ให้ส่งพารามิเตอร์โดยตรงดังนี้

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):
    ...

นอกจากนี้ หากคุณต้องเปรียบเทียบกับพารามิเตอร์เพื่อดูว่าควรเลือกตัวเลือกใด คุณจะต้องใช้ตัวเปรียบเทียบในตัวแทนการตรวจสอบค่า

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):
    ...

คุณเข้าถึงพารามิเตอร์และนิพจน์ของพารามิเตอร์ที่ใช้ในรันไทม์เท่านั้นได้ด้วยฟังก์ชัน 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!')

พารามิเตอร์ในตัว

Cloud Functions SDK มีพารามิเตอร์ที่กำหนดไว้ล่วงหน้า 3 รายการ ซึ่งพร้อมใช้งานจากแพ็กเกจย่อย firebase-functions/params

Node.js

  • projectID คือโปรเจ็กต์ที่อยู่ในระบบคลาวด์ที่ฟังก์ชันทำงานอยู่
  • databaseURL คือ URL ของอินสแตนซ์ Realtime Database ที่เชื่อมโยงกับฟังก์ชัน (หากเปิดใช้ในโปรเจ็กต์ Firebase)
  • storageBucket คือบัคเก็ต Cloud Storage ที่เชื่อมโยงกับฟังก์ชัน (หากเปิดใช้ในโปรเจ็กต์ Firebase)

Python

  • PROJECT_ID คือโปรเจ็กต์ที่อยู่ในระบบคลาวด์ที่ฟังก์ชันทำงานอยู่
  • DATABASE_URL คือ URL ของอินสแตนซ์ Realtime Database ที่เชื่อมโยงกับฟังก์ชัน (หากเปิดใช้ในโปรเจ็กต์ Firebase)
  • STORAGE_BUCKET คือบัคเก็ต Cloud Storage ที่เชื่อมโยงกับฟังก์ชัน (หากเปิดใช้ในโปรเจ็กต์ Firebase)

ฟังก์ชันเหล่านี้ทำงานเหมือนพารามิเตอร์สตริงที่ผู้ใช้กำหนดในทุกๆ ด้าน ยกเว้นว่าเนื่องจาก Firebase CLI ทราบค่าของพารามิเตอร์เหล่านี้เสมอ ระบบจึงจะไม่แจ้งให้ป้อนค่าเมื่อทำให้ใช้งานได้และจะไม่บันทึกค่าลงในไฟล์ .env

พารามิเตอร์ข้อมูลลับ

พารามิเตอร์ประเภท Secret ที่กำหนดโดยใช้ defineSecret() แสดงถึงพารามิเตอร์สตริง ที่มีค่าจัดเก็บไว้ใน Secret Manager ของ Cloud พารามิเตอร์ข้อมูลลับจะตรวจสอบการมีอยู่ของข้อมูลลับใน Secret Manager ของ Cloud และแจ้งให้ป้อนค่าของข้อมูลลับใหม่แบบโต้ตอบในระหว่างการทำให้ใช้งานได้ แทนที่จะตรวจสอบกับไฟล์ .env ในเครื่องและเขียนค่าใหม่ลงในไฟล์หากไม่มี

คุณต้องผูกพารามิเตอร์ข้อมูลลับกับฟังก์ชันแต่ละรายการที่ควรมีสิทธิ์เข้าถึงพารามิเตอร์ดังกล่าว

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

เนื่องจากระบบจะซ่อนค่าของข้อมูลลับไว้จนกว่าจะมีการดำเนินการฟังก์ชัน คุณจึงใช้ค่าเหล่านั้นไม่ได้ขณะกำหนดค่าฟังก์ชัน

ข้อมูลลับ JSON แบบมีโครงสร้าง

หากมีค่าการกำหนดค่าหลายค่าที่เกี่ยวข้องกับตรรกะ (เช่น การตั้งค่าสำหรับบริการของบุคคลที่สาม) คุณสามารถจัดเก็บค่าเหล่านั้นไว้ด้วยกันเป็นออบเจ็กต์ JSON แบบมีโครงสร้างภายในข้อมูลลับเดียวโดยใช้ defineJsonSecret() วิธีนี้ช่วยจัดระเบียบการกำหนดค่าและใช้ประโยชน์จากแพ็กเกจฟรีของ Secret Manager ของ Cloud ได้อย่างมีประสิทธิภาพมากขึ้นด้วยการจัดเก็บค่าการกำหนดค่าที่เกี่ยวข้องไว้ในข้อมูลลับเดียว

ค่าที่จัดเก็บไว้ใน Secret Manager ต้องเป็นสตริง JSON ที่ถูกต้อง SDK จะแยกวิเคราะห์สตริง JSON เป็นออบเจ็กต์ JavaScript โดยอัตโนมัติเมื่อคุณเข้าถึง .value()

ตัวอย่าง

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

หากต้องการสร้างข้อมูลลับ SOMEAPI_CONFIG คุณจะต้องตั้งค่าใน Secret Manager เป็นสตริง JSON เช่น

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

หากค่าข้อมูลลับไม่ใช่ JSON ที่ถูกต้อง การเข้าถึง someApiConfig.value() จะทำให้เกิดข้อผิดพลาดในรันไทม์

ตัวแปรสภาพแวดล้อม

Cloud Functions for Firebase รองรับรูปแบบไฟล์ dotenv สำหรับการโหลดตัวแปรสภาพแวดล้อมที่ระบุไว้ในไฟล์ .env ไปยังรันไทม์ของ แอปพลิเคชัน เมื่อทำให้ใช้งานได้แล้ว คุณจะอ่านตัวแปรสภาพแวดล้อมได้ผ่าน process.env อินเทอร์เฟซ (ในโปรเจ็กต์ที่ใช้ Node.js) หรือ os.environ (ใน โปรเจ็กต์ที่ใช้ Python)

หากต้องการกำหนดค่าสภาพแวดล้อมด้วยวิธีนี้ ให้สร้างไฟล์ .env ในโปรเจ็กต์ เพิ่มตัวแปรที่ต้องการ แล้วทำให้ใช้งานได้โดยทำดังนี้

  1. สร้างไฟล์ .env ในไดเรกทอรี functions/

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

เมื่อทำให้ตัวแปรสภาพแวดล้อมที่กำหนดเองใช้งานได้แล้ว โค้ดฟังก์ชันจะเข้าถึงตัวแปรเหล่านั้นได้โดยทำดังนี้

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')}"
    )

การทำให้ตัวแปรสภาพแวดล้อมหลายชุดใช้งานได้

หากต้องการตัวแปรสภาพแวดล้อมชุดอื่นสำหรับโปรเจ็กต์ Firebase (เช่น การจัดเตรียมเทียบกับเวอร์ชันที่ใช้งานจริง) ให้สร้างไฟล์ .env.<project or alias> แล้วเขียนตัวแปรสภาพแวดล้อมเฉพาะโปรเจ็กต์ไว้ในไฟล์นั้น ระบบจะรวมตัวแปรสภาพแวดล้อมจากไฟล์ .env และไฟล์ .env เฉพาะโปรเจ็กต์ (หากมี) ไว้ในฟังก์ชันทั้งหมดที่ทำให้ใช้งานได้

ตัวอย่างเช่น โปรเจ็กต์อาจมีไฟล์ 3 ไฟล์ต่อไปนี้ซึ่งมีค่าแตกต่างกันเล็กน้อยสำหรับการพัฒนาและเวอร์ชันที่ใช้งานจริง

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

วิธีสร้างและใช้ข้อมูลลับ

  1. จากรูทของไดเรกทอรีโปรเจ็กต์ที่อยู่ในเครื่อง ให้เรียกใช้คำสั่งต่อไปนี้

    firebase functions:secrets:set SECRET_NAME

  2. ป้อนค่าสำหรับ SECRET_NAME

    CLI จะแสดงข้อความแสดงความสำเร็จและเตือนว่าคุณต้องทำให้ฟังก์ชันใช้งานได้เพื่อให้การเปลี่ยนแปลงมีผล

  3. ก่อนที่จะทำให้ใช้งานได้ โปรดตรวจสอบว่าโค้ดฟังก์ชันอนุญาตให้ฟังก์ชันเข้าถึงข้อมูลลับโดยใช้ตัวเลือก 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. ทำให้ Cloud Functions ใช้งานได้โดยทำดังนี้

    firebase deploy --only functions

    ตอนนี้คุณจะเข้าถึงข้อมูลลับได้เหมือนกับตัวแปรสภาพแวดล้อมอื่นๆ ในทางกลับกัน หากฟังก์ชันอื่นที่ไม่ได้ระบุข้อมูลลับพยายามเข้าถึงข้อมูลลับ ฟังก์ชันนั้นจะได้รับค่าที่ไม่ได้กำหนด

    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.
    

เมื่อทำให้ฟังก์ชันใช้งานได้แล้ว ฟังก์ชันนั้นจะมีสิทธิ์เข้าถึงค่าข้อมูลลับ เฉพาะ ฟังก์ชันที่รวมข้อมูลลับไว้ในตัวเลือก secrets โดยเฉพาะเท่านั้นที่จะ มีสิทธิ์เข้าถึงข้อมูลลับนั้นเป็นตัวแปรสภาพแวดล้อม ซึ่งจะช่วยให้มั่นใจได้ว่าค่าข้อมูลลับจะพร้อมใช้งานเฉพาะในที่ที่จำเป็นเท่านั้น จึงช่วยลดความเสี่ยงที่จะเกิดการรั่วไหลของข้อมูลลับโดยไม่ตั้งใจ

การจัดการข้อมูลลับ

ใช้ Firebase CLI เพื่อจัดการข้อมูลลับ ขณะจัดการข้อมูลลับด้วยวิธีนี้ โปรดทราบว่าการเปลี่ยนแปลง CLI บางอย่างกำหนดให้คุณต้องแก้ไขและ/หรือทำให้ฟังก์ชันที่เชื่อมโยงใช้งานได้อีกครั้ง โดยเฉพาะอย่างยิ่ง

  • เมื่อใดก็ตามที่คุณตั้งค่าใหม่สำหรับข้อมูลลับ คุณจะต้องทำให้ฟังก์ชันทั้งหมดที่อ้างอิงข้อมูลลับนั้นใช้งานได้อีกครั้งเพื่อให้ฟังก์ชันเหล่านั้นใช้ค่าล่าสุด
  • หากลบข้อมูลลับ โปรดตรวจสอบว่าไม่มีฟังก์ชันที่ทำให้ใช้งานได้อ้างอิงข้อมูลลับนั้น ฟังก์ชันที่ใช้ค่าข้อมูลลับที่ถูกลบจะล้มเหลวโดยไม่มีการแจ้งเตือน

ต่อไปนี้คือข้อมูลสรุปของคำสั่ง Firebase CLI สำหรับการจัดการข้อมูลลับ

# 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

สำหรับคำสั่ง access และ destroy คุณสามารถระบุพารามิเตอร์เวอร์ชันที่ไม่บังคับเพื่อจัดการเวอร์ชันที่เฉพาะเจาะจงได้ เช่น

functions:secrets:access SECRET_NAME[@VERSION]

ดูข้อมูลเพิ่มเติมเกี่ยวกับการดำเนินการเหล่านี้ได้โดยส่ง -h พร้อมกับคำสั่งเพื่อดูความช่วยเหลือของ CLI

วิธีเรียกเก็บเงินสำหรับข้อมูลลับ

Secret Manager อนุญาตให้ใช้ข้อมูลลับที่ใช้งานอยู่ 6 เวอร์ชัน โดยไม่มีค่าใช้จ่าย ซึ่งหมายความว่าคุณสามารถใช้ข้อมูลลับ 6 รายการต่อเดือนในโปรเจ็กต์ Firebase ได้โดยไม่มีค่าใช้จ่าย

โดยค่าเริ่มต้น Firebase CLI จะพยายามทำลายเวอร์ชันข้อมูลลับที่ไม่ได้ใช้โดยอัตโนมัติเมื่อเหมาะสม เช่น เมื่อคุณทำให้ฟังก์ชันใช้งานได้ด้วยข้อมูลลับเวอร์ชันใหม่ นอกจากนี้ คุณยังล้างข้อมูลลับที่ไม่ได้ใช้ได้อย่างมีประสิทธิภาพโดยใช้ functions:secrets:destroy และ functions:secrets:prune

Secret Manager อนุญาตให้ดำเนินการเข้าถึงข้อมูลลับรายเดือนโดยไม่มีการเรียกเก็บเงิน 10,000 รายการบน ข้อมูลลับ อินสแตนซ์ของฟังก์ชันจะอ่านเฉพาะข้อมูลลับที่ระบุไว้ในตัวเลือก secrets ทุกครั้งที่เริ่มทำงานแบบ Cold Start หากคุณมีอินสแตนซ์ของฟังก์ชันจำนวนมากที่อ่านข้อมูลลับจำนวนมาก โปรเจ็กต์ของคุณอาจใช้สิทธิ์นี้เกินขีดจำกัด ซึ่งในกรณีนี้ระบบจะเรียกเก็บเงินคุณ $0.03 ต่อการดำเนินการเข้าถึง 10,000 รายการ

ดูข้อมูลเพิ่มเติมได้ที่ Secret Manager ราคา

การรองรับโปรแกรมจำลอง

การกำหนดค่าสภาพแวดล้อมด้วย dotenv ออกแบบมาให้ทำงานร่วมกับโปรแกรมจำลอง Cloud Functions ในเครื่องได้Cloud Functions

เมื่อใช้โปรแกรมจำลอง Cloud Functions ในเครื่อง คุณสามารถลบล้างตัวแปรสภาพแวดล้อม สำหรับโปรเจ็กต์ได้โดยการตั้งค่าไฟล์ .env.local เนื้อหาของ .env.local จะมีความสำคัญเหนือกว่า .env และไฟล์ .env เฉพาะโปรเจ็กต์

ตัวอย่างเช่น โปรเจ็กต์อาจมีไฟล์ 3 ไฟล์ต่อไปนี้ซึ่งมีค่าแตกต่างกันเล็กน้อยสำหรับการพัฒนาและการทดสอบในเครื่อง

.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 โปรแกรมจำลองอาจเข้าถึงค่าข้อมูลลับไม่สำเร็จเนื่องจากข้อจำกัดด้านสิทธิ์

คุณสามารถลบล้างค่าข้อมูลลับได้โดยการตั้งค่าไฟล์ .secret.local ซึ่งคล้ายกับการรองรับตัวแปรสภาพแวดล้อมของโปรแกรมจำลอง Cloud Functions คุณสามารถ วิธีนี้ช่วยให้คุณทดสอบฟังก์ชันในเครื่องได้ง่าย โดยเฉพาะอย่างยิ่งหากคุณไม่มีสิทธิ์เข้าถึงค่าข้อมูลลับ

ย้ายข้อมูลจากการกำหนดค่ารันไทม์

เราเลิกใช้งาน functions.config API แล้วและจะหยุดให้บริการในเดือนมีนาคม 2027 หลังจากวันที่ดังกล่าว การทำให้ใช้งานได้ด้วย functions.config จะล้มเหลว

หากต้องการป้องกันไม่ให้การทำให้ใช้งานได้ล้มเหลว ให้ย้ายข้อมูลการกำหนดค่าไปยัง Secret Manager ของ Cloud โดยใช้ Firebase CLI เราขอแนะนำให้ดำเนินการนี้อย่างยิ่งเนื่องจากเป็นวิธีที่มีประสิทธิภาพและปลอดภัยที่สุดในการย้ายข้อมูลการกำหนดค่า

  1. ส่งออกการกำหนดค่าด้วย Firebase CLI

    ใช้คำสั่ง config export เพื่อส่งออกการกำหนดค่าสภาพแวดล้อมที่มีอยู่ไปยังข้อมูลลับใหม่ใน Secret Manager ของ Cloud

    $ 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. อัปเดตโค้ดฟังก์ชันเพื่อผูกข้อมูลลับ

    หากต้องการใช้การกำหนดค่าที่จัดเก็บไว้ในข้อมูลลับใหม่ใน Secret Manager ของ Cloud ให้ใช้ defineJsonSecret API ในซอร์สของฟังก์ชัน นอกจากนี้ โปรดตรวจสอบว่าได้ผูกข้อมูลลับไว้กับฟังก์ชันทั้งหมดที่จำเป็น

    ก่อน

    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;
        // ...
    });
    
  3. ทำให้ฟังก์ชันใช้งานได้

    ทำให้ฟังก์ชันที่อัปเดตแล้วใช้งานได้เพื่อใช้การเปลี่ยนแปลงและผูกสิทธิ์ของข้อมูลลับ

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