透過 Terraform 設定及管理 Firebase 專案和產品

1. 簡介

目標

您可以使用 Terraform 設定及管理 Firebase 專案,包括基礎架構和 Firebase 產品的程式輔助設定。

本程式碼研究室會先說明如何建構 Terraform 設定檔來建立新的 Firebase 專案,隨後說明如何設定要在這項專案中使用的應用程式和 Firebase 產品。此外,我們還會介紹 Terraform 指令列的基本概念,例如預覽要進行的變更,然後實作。

如果您想瞭解如何使用 Terraform 設定及管理 Firebase 專案和產品,歡迎參考本程式碼研究室!

課程內容

  • 如何建立 Terraform 設定檔 (*.tf)
  • 如何使用 Terraform CLI 指令管理基礎架構
  • 如何修改設定,以更新資源和服務
  • 如何在真實網頁應用程式 (稱為友善即時通訊) 中套用設定
  • 如何在不同環境 (正式環境、測試環境等) 中定義平行 (和非同步) 設定

事前準備

如要順利使用本程式碼研究室,您必須具備基本能力,熟悉 Terraform 及其術語,包括下列必要條件:

本程式碼研究室提供真正的範例應用程式,方便您測試透過 Terraform 佈建的內容,並與之互動。為此,您需要符合以下條件:

  • 網頁應用程式的程式碼範例 - 在程式碼研究室的下一個步驟中下載這段程式碼
  • 套件管理員 npm (通常隨附於 Node.js) - 安裝這些工具
  • Firebase CLI - 安裝這個 CLI 並登入

2. 取得範例程式碼

在本程式碼研究室中,您可以使用實體網頁應用程式,測試透過 Terraform 佈建的內容。建議您採取這種做法,瞭解使用 Terraform 佈建資源的所有必要步驟。

從指令列複製程式碼研究室的 GitHub 存放區

git clone https://github.com/firebase/codelab-friendlychat-web

如果尚未安裝 Git,可以將存放區下載為 ZIP 檔案

3. 建立 Terraform 設定

設定 Terraform

  1. 在已下載範例應用程式的程式碼集中,前往 web 目錄的根目錄。
  2. 在該目錄的根目錄下,透過下列初始設定建立名為 main.tf 的 Terraform 設定檔:

    main.tf
    # Terraform configuration to set up providers by version.
    terraform {
      required_providers {
        google-beta = {
          source  = "hashicorp/google-beta"
          version = "~> 4.0"
        }
      }
    }
    
    # Configure the provider not to use the specified project for quota check.
    # This provider should only be used during project creation and initializing services.
    provider "google-beta" {
      alias                 = "no_user_project_override"
      user_project_override = false
    }
    
    # Configure the provider that uses the new project's quota.
    provider "google-beta" {
      user_project_override = true
    }
    

每個 google-beta 供應商都有一個名為 user_project_override 的屬性,用來決定 Terraform 作業的配額檢查方式。如要佈建大多數資源,請使用 user_project_override = true,這代表您的 Firebase 專案檢查配額。不過,如要設定新專案以便接受配額檢查,您必須先使用 user_project_override=false。Terraform alias 語法可讓您區分本程式碼研究室後續步驟中的兩種供應商設定。

在目錄中初始化 Terraform

首次建立新設定時,您必須下載設定中指定的提供者。

如要進行初始化作業,請在 main.tf 設定檔所在目錄的根目錄中執行下列指令:

terraform init

4. 透過 Terraform 建立 Firebase 專案

如要「建立 Firebase 專案」,請注意,每個 Firebase 專案實際上都是 Google Cloud 專案,只要啟用了 Firebase 服務即可。

新增基礎 Google Cloud 專案和 API 的區塊

  1. 首先,佈建基礎 Google Cloud 專案。

    main.tf 設定檔中,新增下列資源區塊。

    您必須指定自己的專案名稱 (例如 "Terraform FriendlyChat Codelab") 和自己的專案 ID (例如 "terraform-codelab-your-initials")。請注意,name 值只會用於 Firebase 介面中,不會向使用者顯示。不過,project_id 值是用來向 Google 識別專案的唯一識別碼,因此請務必指定不重複的值。,瞭解如何調查及移除這項存取權。 main.tf
    ...
    
    # Create a new Google Cloud project.
    resource "google_project" "default" {
      provider = google-beta.no_user_project_override
    
      name            = "<PROJECT_NAME_OF_YOUR_PROJECT>"
      project_id      = "<PROJECT_ID_OF_YOUR_PROJECT>"
    
      # Required for the project to display in any list of Firebase projects.
      labels = {
        "firebase" = "enabled"
      }
    }
    
  2. 接下來,您必須啟用必要的基礎 API:Service Usage API 和 Firebase Management API。

    當您透過 Firebase 控制台建立 Firebase 專案時,系統通常會在背景處理這項 API 啟用作業,但您必須明確告知 Terraform 才能完成啟用程序。

    請在 main.tf 設定檔中加入下列資源區塊:

    main.tf
    ...
    
    # Enable the required underlying Service Usage API.
    resource "google_project_service" "serviceusage" {
      provider = google-beta.no_user_project_override
    
      project = google_project.default.project_id
      service = "serviceusage.googleapis.com"
    
      # Don't disable the service if the resource block is removed by accident.
      disable_on_destroy = false
    }
    
    # Enable the required underlying Firebase Management API.
    resource "google_project_service" "firebase" {
      provider = google-beta.no_user_project_override
    
      project = google_project.default.project_id
      service = "firebase.googleapis.com"
    
      # Don't disable the service if the resource block is removed by accident.
      disable_on_destroy = false
    }
    
    敬上 啟用 Service Usage API 之後,新專案就能接受配額檢查!因此,對於所有後續資源佈建及啟用服務,供應商應「搭配」 使用 user_project_override (不需要別名)。

新增封鎖條件即可啟用 Firebase 服務

「建立 Firebase 專案」的最後一個步驟正在為專案啟用 Firebase 服務。

繼續在您的 main.tf 設定檔中新增以下資源區塊。

如前所述,請注意此資源區塊使用的是具有 user_project_override 的提供者 (不需要別名)。

main.tf

...

# Enable Firebase services for the new project created above.
resource "google_firebase_project" "default" {
  provider = google-beta

  project = google_project.default.project_id

  # Wait until the required APIs are enabled.
  depends_on = [
    google_project_service.firebase,
    google_project_service.serviceusage,
  ]
}

在上方的資源區塊中,您可能會注意到 depends_on 子句,該子句指示 Terraform 等待基礎 API 啟用完成。如果沒有這個子句,Terraform 就無法得知依附元件,因此在平行佈建資源時可能會發生錯誤。

套用設定

  1. 如要佈建新資源並啟用設定檔中指定的 API,請在與 main.tf 檔案相同的目錄 (應為 web) 的根目錄中執行下列指令:
    terraform apply
    
  2. Terraform 會在終端機中輸出要執行的操作計畫。

    如果一切正常,請輸入 yes 以核准動作。

    main.tf
    Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
      + create
    
    Terraform will perform the following actions:
    
      # google_firebase_project.default will be created
      + resource "google_firebase_project" "default" {
          + display_name   = (known after apply)
          + id             = (known after apply)
          + project        = "terraform-friendlychat-codelab"
          + project_number = (known after apply)
        }
    
      # google_project.default will be created
      + resource "google_project" "default" {
          + auto_create_network = true
          + id                  = (known after apply)
          + labels              = {
              + "firebase" = "enabled"
            }
          + name                = "Terraform FriendlyChat Codelab"
          + number              = (known after apply)
          + project_id          = "terraform-friendlychat-codelab"
          + skip_delete         = (known after apply)
        }
    
      # google_project_service.firebase will be created
      + resource "google_project_service" "firebase" {
          + disable_on_destroy = false
          + id                 = (known after apply)
          + project            = "terraform-friendlychat-codelab"
          + service            = "firebase.googleapis.com"
        }
    
      # google_project_service.serviceusage will be created
      + resource "google_project_service" "serviceusage" {
          + disable_on_destroy = false
          + id                 = (known after apply)
          + project            = "terraform-friendlychat-codelab"
          + service            = "serviceusage.googleapis.com"
        }
    
    Plan: 4 to add, 0 to change, 0 to destroy.
    
    Do you want to perform these actions?
      Terraform will perform the actions described above.
      Only 'yes' will be accepted to approve.
    
      Enter a value: yes # <----
    

請注意,如果您只需要在不套用的情況下預覽變更,可以改用 terraform plan 指令。

驗證變更

Terraform 執行完畢之後,您可以執行下列指令,檢查所有已啟用 Terraform 佈建資源和服務的狀態:

terraform show

以下是您應該輸出內容的範例。您的州/省會包含專案的專屬值。

# google_firebase_project.default:
resource "google_firebase_project" "default" {
    display_name   = "Terraform FriendlyChat Codelab"
    id             = "projects/terraform-friendlychat-codelab"
    project        = "terraform-friendlychat-codelab"
    project_number = "000000000"
}

# google_project.default:
resource "google_project" "default" {
    auto_create_network = true
    id                  = "projects/terraform-friendlychat-codelab"
    labels              = {
        "firebase" = "enabled"
    }
    name                = "Terraform FriendlyChat Codelab"
    number              = "000000000"
    project_id          = "terraform-friendlychat-codelab"
}

# google_project_service.firebase:
resource "google_project_service" "firebase" {
    disable_on_destroy = false
    id                 = "terraform-friendlychat-codelab/firebase.googleapis.com"
    project            = "terraform-friendlychat-codelab"
    service            = "firebase.googleapis.com"
}

# google_project_service.serviceusage:
resource "google_project_service" "serviceusage" {
    disable_on_destroy = false
    id                 = "terraform-friendlychat-codelab/serviceusage.googleapis.com"
    project            = "terraform-friendlychat-codelab"
    service            = "serviceusage.googleapis.com"
}

或者,您也可以在 Firebase 控制台查看專案,確認已建立專案。

在 Firebase 控制台中選取的 Terraform PreferenceChat Codelab 專案

5. 透過 Terraform 註冊 Firebase 應用程式

如要使用 Firebase,您必須在 Firebase 專案中註冊應用程式的各個平台變化版本。在本程式碼研究室中,您將使用實際應用程式來測試透過 Terraform 佈建的內容,並與之互動。這個應用程式是網頁應用程式,因此您必須要求 Terraform 在新建立的 Firebase 專案中註冊 Firebase 網頁應用程式。

新增區塊以註冊網頁應用程式

如要在 Firebase 專案中註冊網頁應用程式,請將 main.tf 檔案附加至下列資源區塊。

您必須為網頁應用程式指定自己的 display_name。請注意,這個名稱只會用於 Firebase 介面中,不會向使用者顯示。

main.tf

...

# Create a Firebase Web App in the new project created above.
resource "google_firebase_web_app" "default" {
  provider = google-beta

  project      = google_firebase_project.default.project
  display_name = "<DISPLAY_NAME_OF_YOUR_WEB_APP>"
  deletion_policy = "DELETE"
}

套用設定

  1. 如要佈建新資源,請從 main.tf 檔案所在的根目錄中執行下列指令 (應為 web)。
    terraform apply
    
    敬上 請注意,這個指令不會重新建立新的 Google Cloud 專案。Terraform 會偵測已有專案 ID 的專案,並將該專案目前的狀態與 .tf 檔案中的內容進行比對,並進行任何異動。
  2. 檢閱列印行動計畫。如果沒有任何問題,請輸入 yes 並按下 Enter 鍵,即可核准動作。

驗證變更

您可以執行下列指令,檢查新佈建資源的狀態:

terraform show

或者,您也可以前往 Firebase 控制台查看應用程式,確認是否已在專案中成功註冊。前往「專案設定,然後向下捲動至「您的應用程式」部分。

6. 設定 Firebase 驗證

驗證機制是所有應用程式的重要一環。如要允許使用者以 Google 帳戶登入您的網頁應用程式,您可以啟用 Firebase 驗證,並設定使用 Google 方法登入。

請注意,在本程式碼研究室中,我們提供兩種設定 Firebase 驗證的方式:

  • 方法 1 (建議):在控制台中設定 Firebase 驗證 (不需要 GCIP)。
    • 使用這個選項後,您「不必」將新專案連結至 Cloud Billing 帳戶。
  • 方法 2:使用 Google Cloud Identity Platform (GCIP) API 透過 Terraform 設定 Firebase 驗證。
    • 如果採用這個選項,您必須將新專案與 Cloud Billing 帳戶建立關聯,因為 GCIP 的專案必須採用 Blaze 定價方案。

選項 1:使用 Firebase 控制台設定驗證

如要透過 Firebase 控制台設定 Firebase 驗證,您的專案不一定要採用 Blaze 定價方案。

以下說明如何設定 Firebase 驗證並使用 Google 帳戶登入:

  1. Firebase 控制台,找到左側面板中的「建構」部分。
  2. 依序點選「驗證」和「開始使用」,然後點選「登入方式」分頁標籤 (或按這裡直接前往)。
  3. 按一下「新增供應商」,然後在「其他供應商」部分中選取「Google」
  4. 將「啟用」切換鈕撥到開啟狀態。
  5. 將應用程式的公開名稱設為 FriendlyChat 之類的名稱 (這個名稱不必在全域範圍內重複)。
  6. 在下拉式選單中選擇「專案支援電子郵件」,然後按一下「儲存」在 Firebase 控制台中設定 Firebase 驗證
  7. 您應該會看到 Google 是已啟用的登入服務供應商。Firebase 控制台「驗證」頁面:已啟用 Google 登入功能

選項 2:使用 Google Cloud Identity Platform (GCIP) API 透過 Terraform 設定驗證機制

如要透過 Terraform 設定 Firebase 驗證功能,您必須使用 GCIP API,這代表專案必須採用 Blaze 定價方案。只要將 Cloud Billing 帳戶連結至專案,即可升級 Firebase 專案使用 Blaze 方案。

透過 Terraform 啟用計費功能

  1. 如果您還沒有 Cloud Billing 帳戶,請先前往 Google Cloud 控制台建立新帳戶。輸入 ID 時,請記下「帳單帳戶 ID」,如要找出帳單帳戶 ID,請前往與專案相關聯的帳單帳戶 ID,在「帳單」頁面中找到這個 ID。使用 Google Cloud 控制台啟用帳單帳戶
  2. 如要透過 Terraform 在專案中啟用帳單功能,請在 main.tf 檔案中現有的 google_project 資源中加入 billing_account 屬性:

    main.tf
    ...
    
    # Create a new Google Cloud project.
    resource "google_project" "default" {
      provider = google-beta.no_user_project_override
    
      name            = "<PROJECT_NAME_OF_YOUR_PROJECT>"
      project_id      = "<PROJECT_ID_OF_YOUR_PROJECT>"
      billing_account = "<YOUR_BILLING_ACCOUNT_ID>" # Add this line with your Cloud Billing account ID
    
      # Required for the project to display in any list of Firebase projects.
      labels = {
        "firebase" = "enabled"
      }
    }
    
    ...
    

啟用 Firebase 驗證並透過 Terraform 登入 Google

  1. 如要透過 GCIP 佈建 Firebase 驗證,請以下列資源區塊附加 main.tf 檔案:

    main.tf
    ...
    
    # Enable the Identity Toolkit API.
    resource "google_project_service" "auth" {
      provider = google-beta
    
      project  = google_firebase_project.default.project
      service =  "identitytoolkit.googleapis.com"
    
      # Don't disable the service if the resource block is removed by accident.
      disable_on_destroy = false
    }
    
    # Create an Identity Platform config.
    # Also, enable Firebase Authentication using Identity Platform (if Authentication isn't yet enabled).
    resource "google_identity_platform_config" "auth" {
      provider = google-beta
      project  = google_firebase_project.default.project
    
      # For example, you can configure to auto-delete anonymous users.
      autodelete_anonymous_users = true
    
      # Wait for identitytoolkit.googleapis.com to be enabled before initializing Authentication.
      depends_on = [
        google_project_service.auth,
      ]
    }
    
  2. 您必須擁有 OAuth 用戶端,才能使用 Google 登入功能。前往 API 與Google Cloud 控制台的「服務」專區,即可進行這項設定。
  3. 由於這是您第一次建立這項專案的用戶端 ID,因此您必須設定 OAuth 同意畫面。
    1. 開啟 OAuth 同意畫面,然後選取您剛才建立的專案。
    2. 將「使用者類型」設為「外部」,然後按一下「建立」
    3. 在下一個畫面中,完成以下步驟,然後按一下「儲存並繼續」
      • 將應用程式公開的「應用程式名稱」設為 FriendlyChat 這類名稱 (不一定要是全域通用的名稱)。
      • 從下拉式選單中選取「使用者支援電子郵件」
      • 輸入「開發人員聯絡資訊」的電子郵件地址。
    4. 在下一個畫面中,完成下列步驟:
      • 接受「Scopes」頁面中的預設值,然後按一下「Save and Continue」
      • 在「測試使用者」頁面中接受預設值,然後按一下「儲存並繼續」
      • 查看摘要,然後按一下「返回資訊主頁」
      使用 Google Cloud 控制台設定 OAuth2 用戶端
  4. 請按照下列步驟操作,在「憑證」頁面設定 OAuth 用戶端:
    1. 按一下「建立憑證」,然後選取「OAuth 用戶端 ID」
    2. 在「應用程式類型」下拉式選單中,選取「網頁應用程式」
    3. 在「Name」欄位中輸入應用程式名稱,例如 FriendlyChat (名稱不必在全域範圍內重複)。
    4. 設定下列設定,允許應用程式的網址使用這個 OAuth 用戶端:
      • 在「Authorized JavaScript origins」(已授權的 JavaScript 來源) 下方,按一下「Add URI」,然後輸入
        https://<PROJECT_ID>.firebaseapp.com,其中 <PROJECT_ID> 是您在 main.tf 中設定的專案 ID。
      • 在「已授權的重新導向 URI」下方,按一下「新增 URI」,然後輸入
        https://<PROJECT_ID>.firebaseapp.com/__/auth/handler,其中 <PROJECT_ID> 是您在 main.tf 中設定的專案 ID。
    5. 按一下 [儲存]
    從 Google Cloud 控制台的「憑證」頁面取得 OAuth2 用戶端 ID 和密鑰
  5. 如要以您的 OAuth 用戶端 ID 和用戶端密鑰啟用 Google 登入功能,請加上 main.tf 檔案區塊,並加入下列區塊:

    main.tf
    ...
    
    variable "oauth_client_secret" {
      type = string
    
      description = "OAuth client secret. For this codelab, you can pass in this secret through the environment variable TF_VAR_oauth_client_secret. In a real app, you should use a secret manager service."
    
      sensitive = true
    }
    
    resource "google_identity_platform_default_supported_idp_config" "google_sign_in" {
      provider = google-beta
      project  = google_firebase_project.default.project
    
      enabled       = true
      idp_id        = "google.com"
      client_id     = "<YOUR_OAUTH_CLIENT_ID>"
      client_secret = var.oauth_client_secret
    
      depends_on = [
         google_identity_platform_config.auth
      ]
    }
    

套用設定

  1. 如要根據您的設定設定驗證,請從 main.tf 檔案所在的根目錄中執行下列指令 (應為 web):
    export TF_VAR_oauth_client_secret="<YOUR_OAUTH_CLIENT_SECRET>"
    
    terraform apply
    
    敬上 請注意,執行 terraform apply 不會重新建立新的 Google Cloud 專案。Terraform 會偵測出含有指定專案 ID 的專案,並將該專案目前的狀態與 .tf 檔案中的內容進行比對。它會用於偵測到的所有變更
  2. 檢閱列印行動計畫。如果沒有任何問題,請輸入 yes 並按下 Enter 鍵,即可核准動作。

驗證變更

  1. Firebase 控制台,找到左側面板中的「建構」部分。
  2. 點選「驗證」,然後點選「登入方式」分頁標籤 (或按這裡直接前往)。
  3. 您應該會看到 Google 是已啟用的登入服務供應商。Firebase 控制台「驗證」頁面:已啟用 Google 登入功能

7. 設定 Firestore 資料庫及其安全性規則

在本程式碼研究室的網頁應用程式中,您會將訊息儲存在 Firestore 資料庫中。

  1. 如要啟用必要的 API 並佈建資料庫執行個體,請使用下列資源區塊附加 main.tf 檔案:

    main.tf
    ...
    
    # Enable required APIs for Cloud Firestore.
    resource "google_project_service" "firestore" {
      provider = google-beta
    
      project  = google_firebase_project.default.project
      for_each = toset([
        "firestore.googleapis.com",
        "firebaserules.googleapis.com",
      ])
      service = each.key
    
      # Don't disable the service if the resource block is removed by accident.
      disable_on_destroy = false
    }
    
    # Provision the Firestore database instance.
    resource "google_firestore_database" "default" {
      provider                    = google-beta
    
      project                     = google_firebase_project.default.project
      name                        = "(default)"
      # See available locations:
      # https://firebase.google.com/docs/firestore/locations
      location_id                 = "<NAME_OF_DESIRED_REGION>"
      # "FIRESTORE_NATIVE" is required to use Firestore with Firebase SDKs,
      # authentication, and Firebase Security Rules.
      type                        = "FIRESTORE_NATIVE"
      concurrency_mode            = "OPTIMISTIC"
    
      depends_on = [
        google_project_service.firestore
      ]
    }
    
  2. <NAME_OF_DESIRED_REGION> 變更為您要存放資料庫的區域。

    在開發正式版應用程式時,建議將它設在使用者最接近使用者的地區,也應該位於 Cloud Functions 等其他 Firebase 服務中。在本程式碼研究室中,您可以使用 us-east1 (南卡羅來納州) 或最接近您所在位置的區域 (請參閱「Cloud Firestore 位置」)。
  3. 凡是可供 Firebase 存取的 Firestore 資料庫執行個體,都必須受到 Firebase 安全性規則保護。

    這個程式碼研究室的程式碼範例會在 firestore.rules 檔案中提供一組安全的 Firestore 規則,該檔案位於 web 目錄的根目錄。
  4. 附加 main.tf 檔案與下列資源區塊,以執行下列操作:
    • 透過本機 firestore.rules 檔案建立 Firebase 安全性規則的規則集。
    • 釋出 Firestore 執行個體的規則集。
    ,瞭解如何調查及移除這項存取權。 請注意,這些資源區塊等同於在 Firebase 控制台中點選「發布」按鈕,或是執行 firebase deploy --only firestore:rules.

    main.tf
    ...
    
    # Create a ruleset of Firestore Security Rules from a local file.
    resource "google_firebaserules_ruleset" "firestore" {
      provider = google-beta
    
      project  = google_firebase_project.default.project
      source {
        files {
          name = "firestore.rules"
          # Write security rules in a local file named "firestore.rules".
          # Learn more: https://firebase.google.com/docs/firestore/security/get-started
          content = file("firestore.rules")
        }
      }
    
      # Wait for Firestore to be provisioned before creating this ruleset.
      depends_on = [
        google_firestore_database.default,
      ]
    }
    
    # Release the ruleset for the Firestore instance.
    resource "google_firebaserules_release" "firestore" {
      provider     = google-beta
    
      name         = "cloud.firestore"  # must be cloud.firestore
      ruleset_name = google_firebaserules_ruleset.firestore.name
      project      = google_firebase_project.default.project
    
      # Wait for Firestore to be provisioned before releasing the ruleset.
      depends_on = [
        google_firestore_database.default,
      ]
    
      lifecycle {
        replace_triggered_by = [
          google_firebaserules_ruleset.firestore
        ]
      }
    }
    
  5. 執行 terraform apply,佈建 Firestore 資料庫並部署其安全性規則。
  6. 請確認資料庫已佈建完畢,且已部署其安全性規則:
    1. Firebase 控制台,找到左側面板中的「建構」部分。
    2. 前往「Firestore 資料庫」專區,然後按一下「規則」分頁標籤。
    使用 Firebase 控制台驗證 Cloud Firestore 規則

8. 設定 Cloud Storage 值區及其安全性規則

在本程式碼研究室的網頁應用程式中,您會將使用者共用的圖片儲存在 Cloud Storage 值區中。

  1. 如要啟用必要的 API 並佈建 Cloud Storage 預設值區,請附加 main.tf 檔案及下列資源區塊。

    請注意,專案的預設 Cloud Storage 值區是透過 Google App Engine 佈建,且必須與 Firestore 資料庫位於相同位置。詳情請參閱「App Engine 位置」。

    如要使用專案中的多個值區,請使用 google_storage_bucket 資源佈建這些值區 (本程式碼研究室不會顯示此資訊)。

    main.tf
    ...
    
    # Enable required APIs for Cloud Storage for Firebase.
    resource "google_project_service" "storage" {
      provider = google-beta
    
      project  = google_firebase_project.default.project
      for_each = toset([
        "firebasestorage.googleapis.com",
        "storage.googleapis.com",
      ])
      service = each.key
    
    
      # Don't disable the service if the resource block is removed by accident.
      disable_on_destroy = false
    }
    
    # Provision the default Cloud Storage bucket for the project via Google App Engine.
    resource "google_app_engine_application" "default" {
      provider    = google-beta
    
      project     = google_firebase_project.default.project
      # See available locations: https://firebase.google.com/docs/projects/locations#default-cloud-location
      # This will set the location for the default Storage bucket and the App Engine App.
      location_id = "<NAME_OF_DESIRED_REGION_FOR_DEFAULT_BUCKET>"  # Must be in the same location as Firestore (above)
    
      # Wait until Firestore is provisioned first.
      depends_on = [
        google_firestore_database.default
      ]
    }
    
    # Make the default Storage bucket accessible for Firebase SDKs, authentication, and Firebase Security Rules.
    resource "google_firebase_storage_bucket" "default-bucket" {
      provider  = google-beta
    
      project   = google_firebase_project.default.project
      bucket_id = google_app_engine_application.default.default_bucket
    }
    
  2. 凡是可供 Firebase 存取的 Cloud Storage 值區,都必須受到 Firebase 安全性規則保護。

    本程式碼研究室的程式碼範例會在 storage.rules 檔案中提供一組安全的 Firestore 規則,該檔案位於 web 目錄的根目錄。
  3. 附加 main.tf 檔案與下列資源區塊,以執行下列操作:
    • 從本機檔案建立 Firebase 安全性規則的規則集。
    • 釋出 Storage 值區的規則集。
    ,瞭解如何調查及移除這項存取權。 請注意,這些資源區塊等同於在 Firebase 控制台中點選「發布」按鈕,或是執行 firebase deploy --only storage.

    main.tf
    ...
    
    # Create a ruleset of Cloud Storage Security Rules from a local file.
    resource "google_firebaserules_ruleset" "storage" {
      provider = google-beta
    
      project  = google_firebase_project.default.project
      source {
        files {
          # Write security rules in a local file named "storage.rules".
          # Learn more: https://firebase.google.com/docs/storage/security/get-started
          name    = "storage.rules"
          content = file("storage.rules")
        }
      }
    
      # Wait for the default Storage bucket to be provisioned before creating this ruleset.
      depends_on = [
        google_firebase_storage_bucket.default-bucket,
      ]
    }
    
    # Release the ruleset to the default Storage bucket.
    resource "google_firebaserules_release" "default-bucket" {
      provider     = google-beta
    
      name         = "firebase.storage/${google_app_engine_application.default.default_bucket}"
      ruleset_name = "projects/${google_firebase_project.default.project}/rulesets/${google_firebaserules_ruleset.storage.name}"
      project      = google_firebase_project.default.project
    
      lifecycle {
        replace_triggered_by = [
          google_firebaserules_ruleset.storage
        ]
      }
    }
    
  4. 執行 terraform apply 來佈建預設 Cloud Storage 值區,並部署其安全性規則。
  5. 請確認值區已佈建完畢,且已部署其安全性規則:
    1. Firebase 控制台,找到左側面板中的「建構」部分。
    2. 前往「儲存空間」專區,然後按一下「規則」分頁標籤。
    使用 Firebase 控制台驗證安全性規則

9. 在本機執行應用程式

您現在可以首次執行網頁應用程式!您將使用 Firebase 代管模擬器,在本機提供應用程式。

  1. 開啟新的終端機視窗,然後從 web 目錄執行下列 Firebase CLI 指令,啟動模擬器:
    firebase emulators:start --project=<PROJECT_ID>
    
  2. 在瀏覽器中,透過 CLI 傳回的本機網址開啟網頁應用程式 (通常為 http://localhost:5000)。

您應該會看到 LoyaltyChat 應用程式的 UI,但目前尚無法正常運作。應用程式尚未連結至 Firebase,但只要完成本程式碼研究室的後續步驟,即可大功告成!

請注意,每次變更網頁應用程式時 (就像本程式碼研究室中的步驟一樣),請重新整理瀏覽器,以套用這些變更的本機網址。

10. 安裝、設定並初始化 Firebase

如要讓應用程式與 Firebase 搭配運作,你的應用程式必須具備 Firebase SDK 和 Firebase 專案的 Firebase 設定。

本程式碼研究室的程式碼範例已經是可運作的應用程式,具備所有依附元件和必要函式,可以在應用程式中使用各種 Firebase 產品。如要查看已完成的項目,可以在 web/package.jsonweb/src/index.js 中查看。

即使範例程式碼大部分都完成,您還是需要完成一些步驟,應用程式才會開始運作,包括:安裝 Firebase SDK、啟動版本、將 Firebase 設定新增至應用程式,最後將 Firebase 初始化。

安裝 Firebase SDK 並啟動 webpack 版本

您必須執行一些指令,才能啟動應用程式的建構。

  1. 開啟新的終端機視窗。
  2. 請確認您位於 web 目錄的根目錄。
  3. 執行 npm install 即可下載 Firebase SDK。
  4. 執行 npm update 以更新任何依附元件。
  5. 執行 npm run start 以啟動 webpack。

在程式碼研究室的其他部分,Webpack 現在會持續重新建構原始碼。

在應用程式中新增 Firebase 設定

此外,您必須將 Firebase 設定加進應用程式,Firebase SDK 才能知道您希望這些 SDK 採用哪個 Firebase 專案。

在這個程式碼研究室中,有兩種不同的方法來取得 Firebase 設定:

  • 方法 1:從 Firebase 控制台取得 Firebase 設定。
  • 方法 2:透過 Terraform 取得 Firebase 設定。

方法 1:從 Firebase 控制台取得設定並新增至程式碼集

  1. 在 Firebase 控制台中,前往「專案設定
  2. 向下捲動至「你的應用程式」資訊卡,然後選取網頁應用程式。
  3. 在「Firebase SDK 程式碼片段」窗格中選取「Config」,然後複製設定程式碼片段。
  4. 將設定貼到應用程式的 web/src/firebase-config.js 檔案中,如下所示:

    firebase-config.js
    ...
    
    const config = {
      apiKey: "<API_KEY>",
      authDomain: "<PROJECT_ID>.firebaseapp.com",
      projectId: "<PROJECT_ID>",
      storageBucket: "<PROJECT_ID>.appspot.com",
      messagingSenderId: "<SENDER_ID>",
      appId: "<APP_ID>",
      measurementId: "<G-MEASUREMENT_ID>",
    };
    
    ...
    

做法 2:透過 Terraform 取得設定並新增至程式碼集

或者,您也可以透過 Terraform 取得 Firebase 設定,做為 CLI 中的「輸出值」

  1. main.tf 檔案中,找出 google_firebase_web_app 資源區塊 (向專案註冊網頁應用程式的區塊)。
  2. 在該區塊之後,立即新增下列區塊:

    main.tf
    ...
    
    data "google_firebase_web_app_config" "default" {
      provider     = google-beta
      project      = google_firebase_project.default.project
      web_app_id   = google_firebase_web_app.default.app_id
    }
    
    output "friendlychat_web_app_config" {
      value = {
        projectId         = google_firebase_project.default.project
        appId             = google_firebase_web_app.default.app_id
        apiKey            = data.google_firebase_web_app_config.default.api_key
        authDomain        = data.google_firebase_web_app_config.default.auth_domain
        storageBucket     = lookup(data.google_firebase_web_app_config.default, "storage_bucket", "")
        messagingSenderId = lookup(data.google_firebase_web_app_config.default, "messaging_sender_id", "")
        measurementId     = lookup(data.google_firebase_web_app_config.default, "measurement_id", "")
      }
    }
    
    ...
    
  3. 由於 data 區塊和 output 區塊並非以任何方式修改基礎架構,因此只需執行下列指令即可。
    1. 如要將網頁應用程式的 Firebase 設定載入目錄的 Terraform 狀態,請執行下列指令:
      terraform refresh
      
    2. 如要列印 Firebase 設定值,請執行下列指令:
      terraform output –json
      
      敬上 以下是設定的輸出內容範例。列印輸出內容會包含專案和應用程式的值。
      {
        "friendlychat_web_app_config": {
          "sensitive": false,
          "type": [
            "object",
            {
              "apiKey": "string",
              "appId": "string",
              "authDomain": "string",
              "measurementId": "string",
              "messagingSenderId": "string",
              "projectId": "string",
              "storageBucket": "string"
            }
          ],
          "value": {
            "apiKey": "<API_KEY>",
            "appId": "<APP_ID>",
            "authDomain": "<PROJECT_ID>.firebaseapp.com",
            "measurementId": "<G-MEASUREMENT_ID>",
            "messagingSenderId": "<SENDER_ID>",
            "projectId": "<PROJECT_ID>",
            "storageBucket": "<PROJECT_ID>.appspot.com"
          }
        }
      }
      
  4. value 對應中複製值。
  5. 將這些值 (您的設定) 貼到應用程式的 web/src/firebase-config.js 檔案中,如下所示:

    firebase-config.js
    ...
    
    const config = {
      apiKey: "<API_KEY>",
      appId: "<APP_ID>",
      authDomain: "<PROJECT_ID>.firebaseapp.com",
      measurementId: "<G-MEASUREMENT_ID>",
      messagingSenderId: "<SENDER_ID>",
      projectId: "<PROJECT_ID>",
      storageBucket: "<PROJECT_ID>.appspot.com",
    };
    
    ...
    

在應用程式中初始化 Firebase

最後,如要初始化 Firebase,請附加以下內容的應用程式 web/src/index.js 檔案:

index.js

...

const firebaseAppConfig = getFirebaseConfig();
initializeApp(firebaseAppConfig);

試用應用程式

完成 Firebase 設定後,你可以開始試用功能正常的網頁應用程式了。

  1. 重新整理提供您應用程式的瀏覽器。
  2. 您現在應該可以使用 Google 帳戶登入,並開始在即時通訊中張貼訊息。如果有圖片檔,也可以上傳!

11. 跨環境複製設定

Terraform 擅長管理多個類似設定的基礎架構,例如設定類似實際工作環境專案的測試環境 Firebase 專案。

在本程式碼研究室中,您將建立第二個 Firebase 專案做為測試環境。

如要複製現有設定來建立這項測試專案,有兩種做法:

  • 方法 1:複製 Terraform 設定。
    這個選項可讓您在複製專案與來源專案的不同程度時,提供最具彈性的選擇。
  • 選項 2:透過 for_each 重複使用設定。
    如果每項專案不應有明顯差異,而您想一次全面套用變更,那麼使用這個選項就能提供更多程式碼重複使用。

做法 1:複製 Terraform 設定

這個選項最適合用於複製專案與來源專案的差異,例如採用不同的顯示名稱和階段推出版本。

  1. web 目錄的根目錄中,建立名為 main_staging.tf 的新 Terraform 設定檔。
  2. main.tf 檔案複製所有資源區塊 (terraformprovider 區塊除外),然後貼到 main_staging.tf 檔案中。
  3. 接著,您需要修改 main_staging.tf 中每個複製的資源區塊,才能讓這些資源區塊與測試專案搭配使用:
    • 資源標籤:使用新的名稱以避免衝突。例如將 resource "google_project" "default" 重新命名為 resource "google_project" "staging"
    • 資源參考資料:更新每個參考資料。例如將 google_firebase_project.default.project 更新為 google_firebase_project.staging.project
    ,瞭解如何調查及移除這項存取權。 您可以在本程式碼研究室的 GitHub 存放區中找到 main_staging.tf 檔案的完整設定:

    web/terraform-checkpoints/replicate-config/main_staging-copypaste.tf

    如要使用這項設定,請務必完成下列步驟:
    1. main_staging-copypaste.tf 複製設定,然後貼到 main_staging.tf 檔案中。
    2. main_staging.tf 檔案中執行下列操作:
      • google_project 資源區塊中更新 name 屬性、project-id 屬性,以及使用自有值設定 billing_account 屬性 (如果您是透過 Terraform 設定驗證)。
      • google_firebase_web_app 資源區塊中,將 display_name 屬性更新為您自己的值。
      • google_firestore_databasegoogle_app_engine_application 資源區塊中,將 location_id 屬性更新為您自己的值。
    ,瞭解如何調查及移除這項存取權。 main_staging.tf
    # Create a new Google Cloud project.
    resource "google_project" "staging" {
      provider = google-beta.no_user_project_override
    
      name            = "<PROJECT_NAME_OF_STAGING_PROJECT>"
      project_id      = "<PROJECT_ID_OF_STAGING_PROJECT"
      # Required if you want to set up Authentication via Terraform
      billing_account = "<YOUR_BILLING_ACCOUNT_ID>"
    
      # Required for the project to display in any list of Firebase projects.
      labels = {
        "firebase" = "enabled"
      }
    }
    
    # Enable the required underlying Service Usage API.
    resource "google_project_service" "staging_serviceusage" {
      provider = google-beta.no_user_project_override
    
      project = google_project.staging.project_id
      service = "serviceusage.googleapis.com"
    
      # Don't disable the service if the resource block is removed by accident.
      disable_on_destroy = false
    }
    
    # Enable the required underlying Firebase Management API.
    resource "google_project_service" "staging_firebase" {
      provider = google-beta.no_user_project_override
    
      project = google_project.staging.project_id
      service = "firebase.googleapis.com"
    
      # Don't disable the service if the resource block is removed by accident.
      disable_on_destroy = false
    }
    
    # Enable Firebase services for the new project created above.
    resource "google_firebase_project" "staging" {
      provider = google-beta
    
      project = google_project.staging.project_id
    
      # Wait until the required APIs are enabled.
      depends_on = [
        google_project_service.staging_serviceusage,
        google_project_service.staging_firebase,
      ]
    }
    
    # Create a Firebase Web App in the new project created above.
    resource "google_firebase_web_app" "staging" {
      provider = google-beta
    
      project      = google_firebase_project.staging.project
      display_name = "<DISPLAY_NAME_OF_YOUR_WEB_APP>"
      deletion_policy = "DELETE"
    }
    
  4. 執行 terraform apply 來佈建新的「測試環境」Firebase 專案及其所有資源,並啟用服務。
  5. 和先前一樣,前往 Firebase 控制台查看這些項目,確認所有項目都已按照預期完成佈建與啟用。

選項 2:透過 for_each 重複使用設定

如果各項專案之間不應有顯著差異,而且您想一次全面套用變更,那麼使用這個選項就能提供更多程式碼重複使用。這會使用 Terraform 語言中的 for_each 中繼引數。

  1. 開啟 main.tf 檔案。
  2. 在您要複製的每個資源區塊中,新增 for_each 中繼引數,例如:

    main.tf
    # Create new Google Cloud projects.
    resource "google_project" "default" {
      provider        = google-beta.no_user_project_override
      name            = each.value
      # Create a unique project ID for each project, with each ID starting with <PROJECT_ID>.
      project_id      = "<PROJECT_ID>-${each.key}"
      # Required if you want to set up Authentication via Terraform
      billing_account = "<YOUR_BILLING_ACCOUNT_ID>"
    
      # Required for the projects to display in any list of Firebase projects.
      labels = {
        "firebase" = "enabled"
      }
    
      for_each = {
        prod    = "<PROJECT_NAME_OF_PROD_PROJECT>"
        staging = "<PROJECT_NAME_OF_STAGING_PROJECT>"
      }
    }
    
    # Enable the required underlying Service Usage API.
    resource "google_project_service" "serviceusage" {
      provider = google-beta.no_user_project_override
      for_each = google_project.default
    
      project = each.value.project_id
      service = "serviceusage.googleapis.com"
    
      # Don't disable the service if the resource block is removed by accident.
      disable_on_destroy = false
    }
    
    # Enable the required underlying Firebase Management API.
    resource "google_project_service" "firebase" {
      provider = google-beta.no_user_project_override
      for_each = google_project.default
    
      project = each.value.project_id
      service = "firebase.googleapis.com"
    
      # Don't disable the service if the resource block is removed by accident.
      disable_on_destroy = false
    }
    
    # Enable Firebase services for each of the new projects created above.
    resource "google_firebase_project" "default" {
      provider = google-beta
      for_each = google_project.default
    
      project = each.value.project_id
    
      depends_on = [
        google_project_service.serviceusage,
        google_project_service.firebase,
      ]
    }
    
    # Create a Firebase Web App in each of the new projects created above.
    resource "google_firebase_web_app" "default" {
      provider = google-beta
      for_each = google_firebase_project.default
    
      project      = each.value.project
      # The Firebase Web App created in each project will have the same display name.
      display_name = "<DISPLAY_NAME_OF_YOUR_WEB_APP>"
      deletion_policy = "DELETE"
    }
    
    
    # NOTE: For this codelab, we recommend setting up Firebase Authentication
    # using the Firebase console. However, if you set up Firebase Authentication
    # using Terraform, copy-paste from your main.tf the applicable blocks.
    # Make sure to add the `for_each` meta-argument into each block.
    
    
    # Copy-paste from your main.tf file the applicable resource blocks
    # for setting up Cloud Firestore (including rules) and
    # for setting up Cloud Storage for Firebase (including rules).
    # Make sure to add the `for_each` meta-argument into each block.
    
    敬上 您可以在本程式碼研究室的 GitHub 存放區中找到使用 for_each 中繼引數的 main.tf 檔案完整設定:

    web/terraform-checkpoints/replicate-config/main-foreach.tf

    如要使用這項設定,請務必完成下列步驟:
    1. main-foreach.tf 複製設定,然後貼到 main.tf 檔案中。
    2. main.tf 檔案中執行下列操作:
      • google_project 資源區塊中更新 name 屬性、project-id 屬性,以及使用自有值設定 billing_account 屬性 (如果您是透過 Terraform 設定驗證)。
      • google_firebase_web_app 資源區塊中,將 display_name 屬性更新為您自己的值。
      • google_firestore_databasegoogle_app_engine_application 資源區塊中,將 location_id 屬性更新為您自己的值。
  3. 因此,請務必瞭解並修正一些與現有基礎架構相比,Terraform 如何解讀這項設定的問題,而非立即套用這項設定。
    1. 目前如果套用這項設定使用 for_each,則「資源位址」如下所示:
      google_project.default["prod"]
      google_project.default["staging"]
      google_firebase_project.default["prod"]
      google_firebase_project.default["staging"]
      google_firebase_web_app.default["prod"]
      google_firebase_web_app.default["staging"]
      
      敬上 不過,您在本程式碼研究室的第一部分建立的現有專案,Terraform 稱為:
      google_project.default
      google_firebase_project.default
      google_firebase_android_app.default
      
    2. 請執行 terraform plan,查看 Terraform 在達到目前狀態時會執行的動作。

      輸出內容應顯示 Terraform 會刪除您在本程式碼研究室第一部分建立的專案,並建立兩個新專案。這是因為 Terraform 不知道位於 google_project.default 位址的專案已移至新位址 google_project.default["prod"]
    3. 如要修正這個問題,請執行 terraform state mv 指令:
      terraform state mv "google_project.default" "google_project.default[\"prod\"]"
      
    4. 同樣地,如要修正所有其他資源區塊,請為 google_firebase_projectgoogle_firebase_web_app 以及 main.tf 檔案中的所有其他資源區塊執行 terraform state mv
    5. 現在,如果您再次執行 terraform plan,系統就不會顯示 Terraform 會刪除您在本程式碼研究室第一部分建立的專案。
  4. 執行 terraform apply 來佈建新的「測試環境」Firebase 專案及其所有資源,並啟用服務。
  5. 和先前一樣,前往 Firebase 控制台查看這些項目,確認所有項目都已按照預期完成佈建與啟用。

12. 額外步驟:部署測試環境和正式版應用程式

  1. 在應用程式的程式碼集中,將 firebase-config.js 改為使用測試專案中的 Firebase 設定。

    如要提醒自己如何取得 Firebase 設定並將其加入應用程式,請查看本程式碼研究室的前一個步驟,也就是將 Firebase 設定新增至應用程式。
  2. web 目錄的根目錄中執行下列指令,將應用程式部署至測試環境 Firebase 專案。
    firebase deploy --only hosting --project=<STAGING_PROJECT_ID>
    
  3. 透過 firebase deploy 輸出內容中輸出的網址,在瀏覽器中開啟測試應用程式。請嘗試登入、傳送訊息及上傳圖片。

    將應用程式部署至 Firebase 專案時,應用程式會使用真實的 Firebase 資源,而非模擬資源。與測試環境應用程式互動時,你應該會在 Firebase 控制台的測試專案中看見資料和圖片。
  4. 在測試環境測試應用程式後,請將 firebase-config.js 改回使用實際工作環境專案的 Firebase 設定 (您在本程式碼研究室中建立的第一個專案)。
  5. web 目錄的根目錄中執行下列指令,將應用程式部署至實際工作環境中的 Firebase 專案。
    firebase deploy --only hosting --project=<PRODUCTION_PROJECT_ID>
    
  6. 透過 firebase deploy 輸出內容中輸出的網址,在瀏覽器中開啟正式版應用程式。請嘗試登入、傳送訊息及上傳圖片。

    資料和圖片應該會顯示在 Firebase 控制台的實際工作環境專案中。
  7. 完成本程式碼研究室的兩個應用程式互動後,您可以停止 Firebase 提供這些應用程式。為每個專案執行下列指令:
    firebase hosting:disable --project=<STAGING_PROJECT_ID>
    
    firebase hosting:disable --project=<PRODUCTION_PROJECT_ID>
    

13. 恭喜!

您已使用 Terraform 設定即時即時通訊網頁應用程式!並按照開發環境的最佳做法,分別建立測試環境和正式環境 Firebase 專案。

涵蓋內容

  • 使用 Terraform CLI 管理雲端資源
  • 使用 Terraform 設定 Firebase 產品 (驗證、Firestore、Cloud Storage 和安全性規則)
  • 使用 Firebase 本機模擬器套件在本機執行及測試網頁應用程式
  • 將 Firebase 匯入網頁應用程式
  • 使用 Terraform 複製多個環境中的設定

如要進一步瞭解 Firebase 和 Terraform,請參閱說明文件。這個頁面會列出支援 Terraform 的所有 Firebase 產品、常見用途的 Terraform 設定範例,以及實用的疑難排解和常見問題。