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

1. 簡介

目標

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

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

如果您想瞭解如何使用 Terraform 設定及管理 Firebase 專案和產品,這個程式碼研究室就是為您而設!

課程內容

  • 如何建立 Terraform 設定檔 (*.tf)
  • 如何使用 Terraform CLI 指令管理基礎架構
  • 如何修改設定,更新資源和服務
  • 如何在實際的網頁應用程式 (稱為「Friendly Chat」) 上套用設定
  • 如何在不同環境 (實際工作環境、測試環境等) 中定義平行 (且同步) 設定

事前準備

如要順利完成本程式碼研究室,您必須具備 Terraform 及其術語的基本知識,包括下列先決條件:

本程式碼研究室提供實際的範例應用程式,方便您測試及互動透過 Terraform 佈建的內容。如要執行這項操作,您需要:

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

2. 取得範例程式碼

在本程式碼研究室中,您可以透過實際的 Web 應用程式,測試您透過 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 專案」其實是建立 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 設定檔中 (就在建立新 Cloud 專案的區塊下方),新增下列資源區塊:

    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 後,新專案就能接受配額檢查!因此,在後續所有資源佈建和服務啟用作業中,您都應使用供應商 with 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 FriendlyChat 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 Authentication。
    • 使用這個選項表示您必須將新專案與 Cloud Billing 帳戶建立關聯,因為 GCIP 規定專案必須採用 Blaze 定價方案。

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

如要使用 Firebase 主控台設定 Firebase 驗證,專案不一定要採用 Blaze 定價方案。

以下說明如何設定 Firebase 驗證,並透過 Google 登入:

  1. Firebase 控制台中,找出左側面板的「Build」部分。
  2. 依序點選「Authentication」和「Get started」,然後點選「Sign-in method」分頁標籤 (或按這裡直接前往該分頁)。
  3. 按一下「新增供應商」,然後在「其他供應商」部分選取「Google」
  4. 啟用「啟用」切換鈕。
  5. 將應用程式的公開名稱設為類似 FriendlyChat 的名稱 (不必是全域唯一的名稱)。
  6. 從下拉式選單中選擇「專案支援電子郵件」,然後按一下「儲存」在 Firebase 控制台設定 Firebase Auth
  7. 您應該會看到 Google 已啟用為登入服務供應商。Firebase 控制台的「驗證」頁面:已啟用 Google 登入

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

如要透過 Terraform 設定 Firebase Authentication,您必須使用 GCIP API,也就是說,專案必須採用 Blaze 計費方案。如要將 Firebase 專案升級至 Blaze 方案,請將 Cloud Billing 帳戶與專案建立關聯。

透過 Terraform 啟用計費功能

  1. 如果沒有 Cloud Billing 帳戶,請先在 Google Cloud 控制台建立新帳戶。請記下該帳戶的帳單帳戶 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"
      }
    }
    
    ...
    

透過 Terraform 啟用 Firebase 驗證和 Google 登入功能

  1. 如要使用 GCIP 佈建 Firebase Authentication,請在 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. 如要啟用「使用 Google 帳戶登入」,您必須擁有 OAuth 用戶端。如要進行這項設定,請前往 Google Cloud Console 的「API 和服務」部分
  3. 這是您第一次為這個專案建立用戶端 ID,因此需要設定 OAuth 同意畫面。
    1. 開啟「OAuth 同意畫面」頁面,然後選取您剛建立的專案。
    2. 將「使用者類型」設為「外部」,然後按一下「建立」
    3. 在下一個畫面中,完成下列步驟,然後按一下「儲存並繼續」
      • 將應用程式的公開名稱設為類似 FriendlyChat 的名稱 (不必是全域唯一的名稱)。
      • 從下拉式選單中選擇「使用者支援電子郵件」
      • 輸入「開發人員聯絡資訊」的電子郵件地址。
    4. 在下一個畫面中,完成下列步驟:
      • 在「範圍」頁面接受預設值,然後按一下「儲存並繼續」
      • 接受「測試使用者」頁面上的預設值,然後按一下「儲存並繼續」
      • 查看摘要,然後按一下「返回資訊主頁」
      使用 Google Cloud 控制台設定 OAuth2 用戶端
  4. 在「Credentials」頁面中設定 OAuth 用戶端,方法如下:
    1. 按一下「建立憑證」,然後選取「OAuth 用戶端 ID」
    2. 從「應用程式類型」下拉式選單中,選取「網頁應用程式」
    3. 在「名稱」欄位中輸入應用程式名稱,例如 FriendlyChat (不必是全域不重複的名稱)。
    4. 設定下列項目,允許應用程式的網址使用這個 OAuth 用戶端:
      • 在「已授權的 JavaScript 來源」下方,按一下「新增 URI」,然後輸入
        https://<PROJECT_ID>.firebaseapp.com,其中 <PROJECT_ID> 是您在 main.tf 中設定的專案 ID。
      • 按一下「Authorized redirect URIs」(已授權的重新導向 URI) 下方的「Add 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 控制台中,找出左側面板的「Build」部分。
  2. 依序點選「Authentication」和「Sign-in method」分頁標籤 (或按這裡直接前往該分頁)。
  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> 改為您希望資料庫所在的地區。

    開發正式版應用程式時,您會希望資料庫位於大多數使用者附近的地區,並與其他 Firebase 服務 (例如 Cloud Functions) 位於同一地區。在本程式碼研究室中,您可以使用 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 控制台中,找出左側面板的「Build」部分。
    2. 前往「Firestore Database」部分,然後按一下「規則」分頁標籤。
    使用 Firebase 控制台驗證 Cloud Firestore 規則

8. 設定 Cloud Storage bucket 及其安全規則

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

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

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

    如要在專案中建立多個 bucket,請使用 google_storage_bucket 資源佈建 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 bucket 的規則集。
    請注意,這些資源區塊的作用,相當於在 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. 確認已佈建 bucket,且已部署安全規則:
    1. Firebase 控制台中,找出左側面板的「Build」部分。
    2. 前往「儲存空間」部分,然後按一下「規則」分頁標籤。
    使用 Firebase 控制台驗證安全性規則

9. 在本機執行應用程式

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

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

您應該會看到 FriendlyChat 應用程式的 UI,但目前還無法運作。應用程式尚未連結至 Firebase,但完成本程式碼研究室的後續步驟後,應用程式就會連結至 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 知道要使用哪個 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,在 CLI 中以輸出值的形式取得 Firebase 設定。

  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 屬性,以及 (如果您透過 Terraform 設定驗證) billing_account 屬性。
      • 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 meta 引數的 main.tf 檔案完整設定:

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

    如要使用這項設定,請務必執行下列操作:
    1. main-foreach.tf 複製設定,然後貼到 main.tf 檔案中。
    2. main.tf 檔案中,執行下列操作:
      • google_project 資源區塊中,使用您自己的值更新 name 屬性、project-id 屬性,以及 (如果您透過 Terraform 設定驗證) billing_account 屬性。
      • 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_appmain.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 產品 (Authentication、Firestore、Cloud Storage 和 Security Rules)
  • 使用 Firebase 本機模擬器套件在本機執行及測試網頁應用程式
  • 將 Firebase 匯入網頁應用程式
  • 使用 Terraform 在多個環境中複製設定

如要進一步瞭解 Firebase 和 Terraform,請參閱說明文件。您可以查看支援 Terraform 的所有 Firebase 產品清單、常見用途的 Terraform 設定範例,以及實用的疑難排解和常見問題。