Pierwsze kroki z Terraform i Firebase

Firebase zaczyna obsługiwać Terraform. Jeśli należysz do zespołu, który chce zautomatyzować i ustandaryzować tworzenie projektów Firebase z określonymi zasobami i włączonymi usługami, możesz skorzystać z Terraform w Firebase.

Podstawowy proces korzystania z Terraform w Firebase obejmuje te czynności:

  • Tworzenie i dostosowywanie pliku konfiguracji Terraform (pliku .tf), który określa infrastrukturę, którą chcesz zainicjować (czyli zasoby, które chcesz zainicjować, oraz usługi, które chcesz włączyć).

  • Używanie poleceń gcloud CLI, które współpracują z Terraform, do zaopatrywania infrastruktury określonej w pliku .tf.

Co można robić z Terraform i Firebase?

Przykładowy ogólny proces roboczy w tym przewodniku to tworzenie nowego projektu Firebase z aplikacją na Androida. Ale możesz też zrobić znacznie więcej za pomocą Terraform, np.:

  • usuwać i modyfikować istniejącą infrastrukturę za pomocą Terraform.

  • Za pomocą Terraform możesz zarządzać konfiguracją i zadaniami dotyczącymi poszczególnych usług, np.:

    • Włączanie dostawców logowania Firebase Authentication.
    • tworzenie Cloud Storage lub instancji bazy danych i wdrażanie dla nich Firebase Security Rules.

Aby wykonać te zadania, możesz użyć standardowych plików konfiguracji i poleceń Terraform. Aby Ci w tym pomóc, udostępniliśmy przykładowe pliki konfiguracji Terraform na potrzeby kilku typowych zastosowań.



Ogólny proces korzystania z Terraform w Firebase

Wymagania wstępne

Ten przewodnik to wprowadzenie do korzystania z Terraform w Firebase, dlatego zakłada podstawową znajomość tej usługi. Zanim rozpoczniesz ten proces, upewnij się, że spełnione są te wymagania wstępne.

  • Zainstaluj Terraform i zapoznaj się z tym narzędziem, korzystając z oficjalnych samouczków.

  • Zainstaluj Google Cloud CLI (gcloud CLI). Zaloguj się za pomocą konta użytkownika lub konta usługi.

    • Jeśli używasz konta użytkownika, musisz zaakceptować Warunki korzystania z usługi Firebase. Jeśli możesz wyświetlić projekt Firebase w Firebase konsoli, oznacza to, że akceptujesz Warunki korzystania z usługi Firebase.
    • Aby Terraform mógł wykonywać określone czynności (np. tworzyć projekty), muszą być spełnione te warunki:
      • Użytkownik lub konto usługi musi mieć odpowiedni dostęp do uprawnień IAM do wykonywania tych działań.
      • Jeśli konto użytkownika lub usługi należy do organizacji Google Cloud, zasady organizacji muszą zezwalać na wykonywanie przez to konto tych działań.


Krok 1. Utwórz i dostosuj plik konfiguracji Terraform

Plik konfiguracji Terraform wymaga dwóch głównych sekcji (opisane szczegółowo poniżej):

Konfigurowanie urządzenia provider

Konfiguracja provider jest wymagana niezależnie od tego, z których usług Firebase chcesz korzystać.

  1. Utwórz plik konfiguracji Terraform (np. plik main.tf) w katalogu lokalnym.

    W tym przewodniku użyjesz tego pliku konfiguracji, aby określić providerkonfigurację i całą infrastrukturę, którą ma utworzyć Terraform. Pamiętaj jednak, że masz opcje dotyczące sposobu uwzględniania konfiguracji dostawcy.

    Aby uwzględnić konfigurację provider w pozostałej konfiguracji Terraform, masz do wyboru te opcje:

    • Opcja 1: umieść ją na początku pojedynczego pliku konfiguracyjnego Terraform .tf (jak pokazano w tym przewodniku).

      • Użyj tej opcji, jeśli dopiero zaczynasz korzystać z Terraform lub testujesz Terraform w Firebase.
    • Opcja 2: dołącz je w osobnym pliku .tf (np. pliku provider.tf), z dala od pliku .tf, w którym określasz infrastrukturę do utworzenia (np. plik main.tf).

      • Użyj tej opcji, jeśli należysz do większego zespołu, który musi ujednolicić konfigurację.
      • Podczas wykonywania poleceń Terraform plik provider.tf i plik main.tf muszą znajdować się w tym samym katalogu.

  2. U góry pliku main.tf umieść następującą konfigurację provider.

    Musisz użyć dostawcy google-beta, ponieważ jest to wersja beta korzystania z Firebase z Terraform. Zachowaj ostrożność podczas korzystania z tego narzędzia w produkcji.

    # Terraform configuration to set up providers by version.
    terraform {
      required_providers {
        google-beta = {
          source  = "hashicorp/google-beta"
          version = "~> 5.0"
        }
      }
    }
    
    # Configures the provider to use the resource block's specified project for quota checks.
    provider "google-beta" {
      user_project_override = true
    }
    
    # Configures the provider to not use the resource block's specified project for quota checks.
    # This provider should only be used during project creation and initializing services.
    provider "google-beta" {
      alias = "no_user_project_override"
      user_project_override = false
    }

    Dowiedz się więcej o różnych typach atrybutów związanych z projektem (w tym o tym, co w tym przewodniku nazywamy „projektem sprawdzania limitu”) podczas korzystania z Terraform w Firebase.

  3. Przejdź do następnej sekcji, aby uzupełnić plik konfiguracji i określić, jaką infrastrukturę utworzyć.

Określ, jaką infrastrukturę utworzyć za pomocą bloków resource

W pliku konfiguracji Terraform (w przypadku tego poradnika jest to plik main.tf) musisz określić całą infrastrukturę, którą ma utworzyć Terraform (czyli wszystkie zasoby, które chcesz udostępnić, i wszystkie usługi, które chcesz włączyć). W tym przewodniku znajdziesz pełną listę wszystkich zasobów Firebase, które obsługują Terraform.

  1. Otwórz plik main.tf.

  2. W ramach konfiguracji provider dodaj tę konfigurację bloków resource.

    W tym podstawowym przykładzie tworzymy nowy projekt Firebase, a potem w jego ramach aplikację Firebase na Androida.

    # Terraform configuration to set up providers by version.
    ...
    
    # Configures the provider to use the resource block's specified project for quota checks.
    ...
    
    # Configures the provider to not use the resource block's specified project for quota checks.
    ...
    
    # Creates a new Google Cloud project.
    resource "google_project" "default" {
      provider   = google-beta.no_user_project_override
    
      name       = "Project Display Name"
      project_id = "project-id-for-new-project"
      # Required for any service that requires the Blaze pricing plan
      # (like Firebase Authentication with GCIP)
      billing_account = "000000-000000-000000"
    
      # Required for the project to display in any list of Firebase projects.
      labels = {
        "firebase" = "enabled"
      }
    }
    
    # Enables required APIs.
    resource "google_project_service" "default" {
      provider = google-beta.no_user_project_override
      project  = google_project.default.project_id
      for_each = toset([
        "cloudbilling.googleapis.com",
        "cloudresourcemanager.googleapis.com",
        "firebase.googleapis.com",
        # Enabling the ServiceUsage API allows the new project to be quota checked from now on.
        "serviceusage.googleapis.com",
      ])
      service = each.key
    
      # Don't disable the service if the resource block is removed by accident.
      disable_on_destroy = false
    }
    
    # Enables Firebase services for the new project created above.
    resource "google_firebase_project" "default" {
      provider = google-beta
      project  = google_project.default.project_id
    
      # Waits for the required APIs to be enabled.
      depends_on = [
        google_project_service.default
      ]
    }
    
    # Creates a Firebase Android App in the new project created above.
    resource "google_firebase_android_app" "default" {
      provider = google-beta
    
      project      = google_project.default.project_id
      display_name = "My Awesome Android app"
      package_name = "awesome.package.name"
    
      # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
      depends_on = [
        google_firebase_project.default,
      ]
    }

Jeśli nie znasz infrastruktury projektów i aplikacji jako zasobów, zapoznaj się z tą dokumentacją:

# Terraform configuration to set up providers by version.
...

# Configures the provider to use the resource block's specified project for quota checks.
...

# Configures the provider to not use the resource block's specified project for quota checks.
...

# Creates a new Google Cloud project.
resource "google_project" "default" {
  # Use the provider that enables the setup of quota checks for a new project
  provider   = google-beta.no_user_project_override

  name            = "Project Display Name"        // learn more about the project name
  project_id      = "project-id-for-new-project"  // learn more about the project ID
  # Required for any service that requires the Blaze pricing plan
  # (like Firebase Authentication with GCIP)
  billing_account = "000000-000000-000000"

  # Required for the project to display in any list of Firebase projects.
  labels = {
    "firebase" = "enabled"  // learn more about the Firebase-enabled label
  }
}

# Enables required APIs.
resource "google_project_service" "default" {
  # Use the provider without quota checks for enabling APIS
  provider = google-beta.no_user_project_override
  project  = google_project.default.project_id
  for_each = toset([
    "cloudbilling.googleapis.com",
    "cloudresourcemanager.googleapis.com",
    "firebase.googleapis.com",
    # Enabling the ServiceUsage API allows the new project to be quota checked from now on.
    "serviceusage.googleapis.com",
  ])
  service = each.key

  # Don't disable the service if the resource block is removed by accident.
  disable_on_destroy = false
}

# Enables Firebase services for the new project created above.
# This action essentially "creates a Firebase project" and allows the project to use
# Firebase services (like Firebase Authentication) and
# Firebase tooling (like the Firebase console).
# Learn more about the relationship between Firebase projects and Google Cloud.
resource "google_firebase_project" "default" {
  # Use the provider that performs quota checks from now on
  provider = google-beta

  project  = google_project.default.project_id

  # Waits for the required APIs to be enabled.
  depends_on = [
    google_project_service.default
  ]
}

# Creates a Firebase Android App in the new project created above.
# Learn more about the relationship between Firebase Apps and Firebase projects.
resource "google_firebase_android_app" "default" {
  provider = google-beta

  project      = google_project.default.project_id
  display_name = "My Awesome Android app"  # learn more about an app's display name
  package_name = "awesome.package.name"    # learn more about an app's package name

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.default,
  ]
}


Krok 2. Uruchom polecenia Terraform, aby utworzyć określoną infrastrukturę

Aby zainicjować zasoby i włączyć usługi określone w pliku main.tf, uruchom podane niżej polecenia w tym samym katalogu, co plik main.tf. Szczegółowe informacje o tych poleceniach znajdziesz w dokumentacji Terraform.

  1. Jeśli po raz pierwszy uruchamiasz w tym katalogu polecenia Terraform, musisz zainicjować katalog konfiguracji i zainstalować dostawcę Terraform Google. Aby to zrobić, uruchom to polecenie:

    terraform init
  2. Utwórz infrastrukturę określoną w pliku main.tf, uruchamiając to polecenie:

    terraform apply
  3. Sprawdź, czy wszystko zostało skonfigurowane lub włączone zgodnie z oczekiwaniami:

    • Opcja 1: aby wyświetlić konfigurację w terminalu, uruchom to polecenie:

      terraform show
    • Opcja 2: otwórz projekt Firebase w Firebase konsoli.



Zasoby Firebase z obsługą Terraform

Te zasoby Firebase i Google są obsługiwane przez Terraform. Stale dodajemy też więcej materiałów. Jeśli nie widzisz zasobu, którym chcesz zarządzać za pomocą Terraform, wkrótce sprawdź, czy jest on dostępny, lub poproś o jego dodanie, zgłaszając problem w repozytorium GitHuba.


Zarządzanie projektem i aplikacją Firebase

  • google_firebase_project – włączanie usług Firebase w dotychczasowym projekcie Google Cloud.

  • Aplikacje Firebase


Firebase Authentication

Nieobsługiwane:

  • Konfigurowanie uwierzytelniania wielopoziomowego (MFA) za pomocą Terraform

Firebase Data Connect


Firebase Realtime Database

Nieobsługiwane:

  • Wdrażanie Firebase Realtime Database Security Rules za pomocą Terraform (dowiedz się, jak wdrażać te Rules za pomocą innych narzędzi, w tym opcji programowych).

Cloud Firestore

  • google_firestore_database – utwórz instancję Cloud Firestore.

  • google_firestore_index – włącza wydajne zapytania do usługi Cloud Firestore.

  • google_firestore_document – zasilenie instancji Cloud Firestore określonym dokumentem w kolekcji.

    Ważne: w tym dokumencie nie używaj prawdziwych danych użytkownika ani danych produkcyjnych.


Cloud Storage for Firebase

  • google_firebase_storage_bucket – udostępnij istniejący folder Cloud Storage pakietowi SDK Firebase, uwierzytelnianiu i funkcji Firebase Security Rules.

  • google_storage_bucket_object – dodawanie obiektu do zasobnika Cloud Storage.

    Ważne: w tym pliku nie używaj prawdziwych danych użytkownika ani danych produkcyjnych.


Firebase Security Rules (dla Cloud FirestoreCloud Storage)

Pamiętaj, że Firebase Realtime Database używa innego systemu obsługi Firebase Security Rules.

  • google_firebaserules_ruleset – definiowanie Firebase Security Rules, które mają zastosowanie do instancji Cloud Firestore lub zasobnika Cloud Storage.

  • google_firebaserules_release – wdrożenie określonych zbiorów reguł do instancji Cloud Firestore lub zasobnika Cloud Storage.


Firebase App Check


Firebase Extensions



Przykładowe pliki konfiguracji Terraform na potrzeby typowych zastosowań

Ta konfiguracja tworzy nowy projekt Google Cloud, łączy go z kontem Cloud Billing (abonament Blaze jest wymagany w przypadku usługi Firebase Authentication w GCP), włącza usługi Firebase w projekcie, konfiguruje Firebase Authentication w GCP i rejestruje w projekcie 3 różne typy aplikacji.

Pamiętaj, że aby skonfigurować Firebase Authentication za pomocą Terraform, musisz włączyć GCIP.

# Creates a new Google Cloud project.
resource "google_project" "auth" {
  provider  = google-beta.no_user_project_override
  folder_id = "folder-id-for-new-project"
  name            = "Project Display Name"
  project_id      = "project-id-for-new-project"

  # Associates the project with a Cloud Billing account
  # (required for Firebase Authentication with GCIP).
  billing_account = "000000-000000-000000"

  # Required for the project to display in a list of Firebase projects.
  labels = {
    "firebase" = "enabled"
  }
}

# Enables required APIs.
resource "google_project_service" "auth" {
  provider = google-beta.no_user_project_override
  project  = google_project.auth.project_id
  for_each = toset([
    "cloudbilling.googleapis.com",
    "cloudresourcemanager.googleapis.com",
    "serviceusage.googleapis.com",
    "identitytoolkit.googleapis.com",
  ])
  service = each.key

  # Don't disable the service if the resource block is removed by accident.
  disable_on_destroy = false
}

# Enables Firebase services for the new project created above.
resource "google_firebase_project" "auth" {
  provider = google-beta
  project  = google_project.auth.project_id

  depends_on = [
    google_project_service.auth,
  ]
}

# Creates an Identity Platform config.
# Also enables Firebase Authentication with Identity Platform in the project if not.
resource "google_identity_platform_config" "auth" {
  provider = google-beta
  project  = google_project.auth.project_id

  # Auto-deletes anonymous users
  autodelete_anonymous_users = true

  # Configures local sign-in methods, like anonymous, email/password, and phone authentication.
  sign_in {
    allow_duplicate_emails = true

    anonymous {
      enabled = true
    }

    email {
      enabled = true
      password_required = false
    }

    phone_number {
      enabled = true
      test_phone_numbers = {
        "+11231231234" = "000000"
      }
    }
  }

  # Sets an SMS region policy.
  sms_region_config {
    allowlist_only {
      allowed_regions = [
        "US",
        "CA",
      ]
    }
  }

  # Configures blocking functions.
  blocking_functions {
    triggers {
      event_type = "beforeSignIn"
      function_uri = "https://us-east1-${google_project.auth.project_id}.cloudfunctions.net/before-sign-in"
    }
    forward_inbound_credentials {
      refresh_token = true
      access_token = true
      id_token = true
    }
  }

  # Configures a temporary quota for new signups for anonymous, email/password, and phone number.
  quota {
    sign_up_quota_config {
      quota = 1000
      start_time = ""
      quota_duration = "7200s"
    }
  }

  # Configures authorized domains.
  authorized_domains = [
    "localhost",
    "${google_project.auth.project_id}.firebaseapp.com",
    "${google_project.auth.project_id}.web.app",
  ]

  # Wait for identitytoolkit.googleapis.com to be enabled before initializing Authentication.
  depends_on = [
    google_project_service.auth,
  ]
}

# Creates a Firebase Android App in the new project created above.
resource "google_firebase_android_app" "auth" {
  provider     = google-beta
  project      = google_project.auth.project_id
  display_name = "My Android app"
  package_name = "android.package.name"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.auth,
  ]
}

# Creates a Firebase Apple-platforms App in the new project created above.
resource "google_firebase_apple_app" "auth" {
  provider     = google-beta
  project      = google_project.auth.project_id
  display_name = "My Apple app"
  bundle_id    = "apple.app.12345"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.auth,
  ]
}

# Creates a Firebase Web App in the new project created above.
resource "google_firebase_web_app" "auth" {
  provider     = google-beta
  project      = google_project.auth.project_id
  display_name = "My Web app"

  # The other App types (Android and Apple) use "DELETE" by default.
  # Web apps don't use "DELETE" by default due to backward-compatibility.
  deletion_policy = "DELETE"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.auth,
  ]
}

Ta konfiguracja tworzy nowy projekt Google Cloud, włącza w nim usługi Firebase i rezerwuje usługę Data Connect.

# Creates a new Google Cloud project.
resource "google_project" "dataconnect" {
  provider   = google-beta.no_user_project_override
  folder_id  = "folder-id-for-new-project"
  name       = "Project Display Name"
  project_id = "project-id-for-new-project"

  # Associates the project with a Cloud Billing account
  # (required to use Firebase Data Connect).
  billing_account = "000000-000000-000000"

  # Required for the project to display in a list of Firebase projects.
  labels = {
    "firebase" = "enabled"
  }
}

# Enables required APIs.
resource "google_project_service" "services" {
  provider = google-beta.no_user_project_override
  project  = google_project.dataconnect.project_id
  for_each = toset([
    "serviceusage.googleapis.com",
    "cloudresourcemanager.googleapis.com",
    "firebasedataconnect.googleapis.com",
  ])
  service = each.key

  # Don't disable the service if the resource block is removed by accident.
  disable_on_destroy = false
}

# Enables Firebase services for the new project created earlier.
resource "google_firebase_project" "dataconnect" {
  provider = google-beta
  project  = google_project.dataconnect.project_id

  depends_on = [google_project_service.services]
}

# Create a Firebase Data Connect service
resource "google_firebase_data_connect_service" "dataconnect-default" {
  project         = google_firebase_project.dataconnect.project
  location        = "name-of-region-for-service"
  service_id      = "${google_firebase_project.dataconnect.project}-default-fdc"
  deletion_policy = "DEFAULT"
}

Ta konfiguracja tworzy nowy projekt Google Cloud, włącza w nim usługi Firebase, udostępnia domyślny egzemplarz Realtime Database projektu i rejestruje w nim 3 różne typy aplikacji.

# Creates a new Google Cloud project.
resource "google_project" "rtdb" {
  provider   = google-beta.no_user_project_override
  folder_id  = "folder-id-for-new-project"
  name       = "Project Display Name"
  project_id = "project-id-for-new-project"

  # Required for the project to display in a list of Firebase projects.
  labels = {
    "firebase" = "enabled"
  }
}

# Enables required APIs.
resource "google_project_service" "rtdb" {
  provider = google-beta.no_user_project_override
  project  = google_project.rtdb.project_id
  for_each = toset([
    "serviceusage.googleapis.com",
    "cloudresourcemanager.googleapis.com",
    "firebasedatabase.googleapis.com",
  ])
  service = each.key

  # Don't disable the service if the resource block is removed by accident.
  disable_on_destroy = false
}

# Enables Firebase services for the new project created above.
resource "google_firebase_project" "rtdb" {
  provider = google-beta
  project  = google_project.rtdb.project_id
}

# Provisions the default Realtime Database default instance.
resource "google_firebase_database_instance" "database" {
  provider    = google-beta
  project     = google_project.rtdb.project_id
  # See available locations: https://firebase.google.com/docs/database/locations
  region      = "name-of-region"
  # This value will become the first segment of the database's URL.
  instance_id = "${google_project.rtdb.project_id}-default-rtdb"
  type        = "DEFAULT_DATABASE"

  # Wait for Firebase to be enabled in the Google Cloud project before initializing Realtime Database.
  depends_on = [
    google_firebase_project.rtdb,
  ]
}

# Creates a Firebase Android App in the new project created above.
resource "google_firebase_android_app" "rtdb" {
  provider     = google-beta
  project      = google_project.rtdb.project_id
  display_name = "My Android app"
  package_name = "android.package.name"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.rtdb,
  ]
}

# Creates a Firebase Apple-platforms App in the new project created above.
resource "google_firebase_apple_app" "rtdb" {
  provider     = google-beta
  project      = google_project.rtdb.project_id
  display_name = "My Apple app"
  bundle_id    = "apple.app.12345"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.rtdb,
  ]
}

# Creates a Firebase Web App in the new project created above.
resource "google_firebase_web_app" "rtdb" {
  provider     = google-beta
  project      = google_project.rtdb.project_id
  display_name = "My Web app"

  # The other App types (Android and Apple) use "DELETE" by default.
  # Web apps don't use "DELETE" by default due to backward-compatibility.
  deletion_policy = "DELETE"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.rtdb,
  ]
}

Ta konfiguracja tworzy nowy projekt Google Cloud, łączy go z kontem Cloud Billing (abonament Blaze jest wymagany w przypadku wielu instancji Realtime Database), włącza usługi Firebase w projekcie, udostępnia wiele instancji Realtime Database (w tym domyślną instancję Realtime Database projektu) i rejestruje w projekcie 3 różne typy aplikacji.

# Creates a new Google Cloud project.
resource "google_project" "rtdb-multi" {
  provider   = google-beta.no_user_project_override
  folder_id  = "folder-id-for-new-project"
  name       = "Project Display Name"
  project_id = "project-id-for-new-project"

  # Associate the project with a Cloud Billing account
  # (required for multiple Realtime Database instances).
  billing_account = "000000-000000-000000"

  # Required for the project to display in a list of Firebase projects.
  labels = {
    "firebase" = "enabled"
  }
}

# Enables required APIs.
resource "google_project_service" "rtdb-multi" {
  provider = google-beta.no_user_project_override
  project  = google_project.rtdb-multi.project_id
  for_each = toset([
    "cloudbilling.googleapis.com",
    "serviceusage.googleapis.com",
    "cloudresourcemanager.googleapis.com",
    "firebasedatabase.googleapis.com",
  ])
  service = each.key

  # Don't disable the service if the resource block is removed by accident.
  disable_on_destroy = false
}

# Enables Firebase services for the new project created above.
resource "google_firebase_project" "rtdb-multi" {
  provider = google-beta
  project  = google_project.rtdb-multi.project_id
}

# Provisions the default Realtime Database default instance.
resource "google_firebase_database_instance" "database-default" {
  provider    = google-beta
  project     = google_project.rtdb-multi.project_id
  # See available locations: https://firebase.google.com/docs/database/locations
  region      = "name-of-region"
  # This value will become the first segment of the database's URL.
  instance_id = "${google_project.rtdb-multi.project_id}-default-rtdb"
  type        = "DEFAULT_DATABASE"

  # Wait for Firebase to be enabled in the Google Cloud project before initializing Realtime Database.
  depends_on = [
    google_firebase_project.rtdb-multi,
  ]
}

# Provisions an additional Realtime Database instance.
resource "google_firebase_database_instance" "database-additional" {
  provider    = google-beta
  project     = google_project.rtdb-multi.project_id
  # See available locations: https://firebase.google.com/docs/projects/locations#rtdb-locations
  # This location doesn't need to be the same as the default database instance.
  region      = "name-of-region"
  # This value will become the first segment of the database's URL.
  instance_id = "name-of-additional-database-instance"
  type        = "USER_DATABASE"

  # Wait for Firebase to be enabled in the Google Cloud project before initializing Realtime Database.
  depends_on = [
    google_firebase_project.rtdb-multi,
  ]
}

# Creates a Firebase Android App in the new project created above.
resource "google_firebase_android_app" "rtdb-multi" {
  provider     = google-beta
  project      = google_project.rtdb-multi.project_id
  display_name = "My Android app"
  package_name = "android.package.name"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.rtdb-multi,
  ]
}

# Creates a Firebase Apple-platforms App in the new project created above.
resource "google_firebase_apple_app" "rtdb-multi" {
  provider     = google-beta
  project      = google_project.rtdb-multi.project_id
  display_name = "My Apple app"
  bundle_id    = "apple.app.12345"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.rtdb-multi,
  ]
}

# Creates a Firebase Web App in the new project created above.
resource "google_firebase_web_app" "rtdb-multi" {
  provider     = google-beta
  project      = google_project.rtdb-multi.project_id
  display_name = "My Web app"

  # The other App types (Android and Apple) use "DELETE" by default.
  # Web apps don't use "DELETE" by default due to backward-compatibility.
  deletion_policy = "DELETE"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.rtdb-multi,
  ]
}

Ta konfiguracja tworzy nowy projekt Google Cloud, włącza w nim usługi Firebase, udostępnia domyślny egzemplarz Cloud Firestore projektu i rejestruje w nim 3 różne typy aplikacji.

Ponadto tworzy instancję Firebase Security Rules dla domyślnej instancji Cloud Firestore, indeks Cloud Firestore oraz dokument Cloud Firestore z danymi początkowymi.

# Creates a new Google Cloud project.
resource "google_project" "firestore" {
  provider   = google-beta.no_user_project_override
  folder_id  = "folder-id-for-new-project"
  name       = "Project Display Name"
  project_id = "project-id-for-new-project"

  # Required for the project to display in a list of Firebase projects.
  labels = {
    "firebase" = "enabled"
  }
}

# Enables required APIs.
resource "google_project_service" "firestore" {
  provider = google-beta.no_user_project_override
  project  = google_project.firestore.project_id
  for_each = toset([
    "cloudresourcemanager.googleapis.com",
    "serviceusage.googleapis.com",
    "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
}

# Enables Firebase services for the new project created above.
resource "google_firebase_project" "firestore" {
  provider = google-beta
  project  = google_project.firestore.project_id
}

# Provisions the Firestore database instance.
resource "google_firestore_database" "firestore" {
  provider                    = google-beta
  project                     = google_project.firestore.project_id
  name                        = "(default)"
  # See available locations: https://firebase.google.com/docs/firestore/locations
  location_id                 = "name-of-region"
  # "FIRESTORE_NATIVE" is required to use Firestore with Firebase SDKs, authentication, and Firebase Security Rules.
  type                        = "FIRESTORE_NATIVE"
  concurrency_mode            = "OPTIMISTIC"

  # Wait for Firebase to be enabled in the Google Cloud project before initializing Firestore.
  depends_on = [
    google_firebase_project.firestore,
  ]
}

# Creates a ruleset of Firestore Security Rules from a local file.
resource "google_firebaserules_ruleset" "firestore" {
  provider = google-beta
  project  = google_project.firestore.project_id
  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.firestore,
  ]
}

# Releases 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_project.firestore.project_id

  # Wait for Firestore to be provisioned before releasing the ruleset.
  depends_on = [
    google_firestore_database.firestore,
  ]
}

# Adds a new Firestore index.
resource "google_firestore_index" "indexes" {
  provider = google-beta
  project  = google_project.firestore.project_id

  collection  = "quiz"
  query_scope = "COLLECTION"

  fields {
    field_path = "question"
    order      = "ASCENDING"
  }

  fields {
    field_path = "answer"
    order      = "ASCENDING"
  }

  # Wait for Firestore to be provisioned before adding this index.
  depends_on = [
    google_firestore_database.firestore,
  ]
}

# Adds a new Firestore document with seed data.
# Don't use real end-user or production data in this seed document.
resource "google_firestore_document" "doc" {
  provider    = google-beta
  project     = google_project.firestore.project_id
  collection  = "quiz"
  document_id = "question-1"
  fields      = "{\"question\":{\"stringValue\":\"Favorite Database\"},\"answer\":{\"stringValue\":\"Firestore\"}}"

  # Wait for Firestore to be provisioned before adding this document.
  depends_on = [
    google_firestore_database.firestore,
  ]
}

# Creates a Firebase Android App in the new project created above.
resource "google_firebase_android_app" "firestore" {
  provider     = google-beta
  project      = google_project.firestore.project_id
  display_name = "My Android app"
  package_name = "android.package.name"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.firestore,
  ]
}

# Creates a Firebase Apple-platforms App in the new project created above.
resource "google_firebase_apple_app" "firestore" {
  provider     = google-beta
  project      = google_project.firestore.project_id
  display_name = "My Apple app"
  bundle_id    = "apple.app.12345"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.firestore,
  ]
}

# Creates a Firebase Web App in the new project created above.
resource "google_firebase_web_app" "firestore" {
  provider     = google-beta
  project      = google_project.firestore.project_id
  display_name = "My Web app"

  # The other App types (Android and Apple) use "DELETE" by default.
  # Web apps don't use "DELETE" by default due to backward-compatibility.
  deletion_policy = "DELETE"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.firestore,
  ]
}

To zbiór reguł Cloud Firestore Security Rules, który powinien znajdować się w pliku lokalnym o nazwie firestore.rules.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /some_collection/{document} {
      allow read, create, update: if request.auth != null;
    }
  }
}

Ta konfiguracja tworzy nowy projekt Google Cloud, łączy go z kontem Cloud Billing (abonament Blaze jest wymagany w przypadku dodatkowych zasobów), włącza usługi Firebase w projekcie, udostępnia dodatkowe, inne niż domyślne zasoby Cloud Storage i rejestruje w projekcie 3 różne typy aplikacji.

Tworzy też Firebase Security Rules dla każdego zasobnika Cloud Storage i przesyła plik do jednego z zasobników Cloud Storage.

# Creates a new Google Cloud project.
resource "google_project" "storage-multi" {
  provider  = google-beta.no_user_project_override
  folder_id = "folder-id-for-new-project"
  name            = "Project Display Name"
  project_id      = "project-id-for-new-project"

  # Associates the project with a Cloud Billing account
  # (required for multiple Cloud Storage buckets).
  billing_account = "000000-000000-000000"

  # Required for the project to display in a list of Firebase projects.
  labels = {
    "firebase" = "enabled"
  }
}

# Enables required APIs.
resource "google_project_service" "storage-multi" {
  provider = google-beta.no_user_project_override
  project  = google_project.storage-multi.project_id
  for_each = toset([
    "cloudbilling.googleapis.com",
    "serviceusage.googleapis.com",
    "cloudresourcemanager.googleapis.com",
    "firebaserules.googleapis.com",
    "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
}

# Enables Firebase services for the new project created above.
resource "google_firebase_project" "storage-multi" {
  provider = google-beta
  project  = google_project.storage-multi.project_id
}

# Provisions a Cloud Storage bucket.
resource "google_storage_bucket" "bucket-1" {
  provider = google-beta
  project  = google_project.storage-multi.project_id
  name     = "name-of-storage-bucket"
  # See available locations: https://cloud.google.com/storage/docs/locations#available-locations
  location = "name-of-region-for-bucket"
}

# Provisions an additional Cloud Storage bucket.
resource "google_storage_bucket" "bucket-2" {
  provider = google-beta
  project  = google_project.storage-multi.project_id
  name     = "name-of-additional-storage-bucket"
  # See available locations: https://cloud.google.com/storage/docs/locations#available-locations
  # This location does not need to be the same as the existing Storage bucket.
  location = "name-of-region-for-additional-bucket"
}

# Makes the first Storage bucket accessible for Firebase SDKs, authentication, and Firebase Security Rules.
resource "google_firebase_storage_bucket" "bucket-1" {
  provider  = google-beta
  project   = google_project.storage-multi.project_id
  bucket_id = google_storage_bucket.bucket-1.name
}

# Makes the additional Storage bucket accessible for Firebase SDKs, authentication, and Firebase Security Rules.
resource "google_firebase_storage_bucket" "bucket-2" {
  provider  = google-beta
  project   = google_project.storage-multi.project_id
  bucket_id = google_storage_bucket.bucket-2.name
}

# Creates a ruleset of Firebase Security Rules from a local file.
resource "google_firebaserules_ruleset" "storage-multi" {
  provider = google-beta
  project  = google_project.storage-multi.project_id
  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 Storage buckets to be provisioned before creating this ruleset.
  depends_on = [
    google_firebase_project.storage-multi,
  ]
}

# Releases the ruleset to the first Storage bucket.
resource "google_firebaserules_release" "bucket-1" {
  provider     = google-beta
  name         = "firebase.storage/${google_storage_bucket.bucket-1.name}"
  ruleset_name = "projects/${google_project.storage-multi.project_id}/rulesets/${google_firebaserules_ruleset.storage-multi.name}"
  project      = google_project.storage-multi.project_id
}

# Releases the ruleset to the additional Storage bucket.
resource "google_firebaserules_release" "bucket-2" {
  provider     = google-beta
  name         = "firebase.storage/${google_storage_bucket.bucket-2.name}"
  ruleset_name = "projects/${google_project.storage-multi.project_id}/rulesets/${google_firebaserules_ruleset.storage-multi.name}"
  project      = google_project.storage-multi.project_id
}

# Uploads a new file to the first Storage bucket.
# Do not use real end-user or production data in this file.
resource "google_storage_bucket_object" "cat-picture-multi" {
  provider = google-beta
  name     = "cat.png"
  source   = "path/to/cat.png"
  bucket   = google_storage_bucket.bucket-1.name
}

# Creates a Firebase Android App in the new project created above.
resource "google_firebase_android_app" "storage-multi" {
  provider     = google-beta
  project      = google_project.storage-multi.project_id
  display_name = "My Android app"
  package_name = "android.package.name"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.storage-multi,
  ]
}

# Creates a Firebase Apple-platforms App in the new project created above.
resource "google_firebase_apple_app" "storage-multi" {
  provider     = google-beta
  project      = google_project.storage-multi.project_id
  display_name = "My Apple app"
  bundle_id    = "apple.app.12345"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.storage-multi,
  ]
}

# Creates a Firebase Web App in the new project created above.
resource "google_firebase_web_app" "storage-multi" {
  provider     = google-beta
  project      = google_project.storage-multi.project_id
  display_name = "My Web app"

  # Wait for Firebase to be enabled in the Google Cloud project before creating this App.
  depends_on = [
    google_firebase_project.storage-multi,
  ]
}

To zbiór reguł Cloud Storage Security Rules, który powinien znajdować się w pliku lokalnym o nazwie storage.rules.

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /some_folder/{fileName} {
      allow read, write: if request.auth != null;
    }
  }
}

Ta konfiguracja tworzy nowy projekt Google Cloud, włącza usługi Firebase w tym projekcie oraz konfiguruje i włącza egzekwowanie Firebase App Check w projekcie Cloud Firestore, tak aby można było uzyskać do niego dostęp tylko z aplikacji na Androida.

# Creates a new Google Cloud project.
resource "google_project" "appcheck" {
  provider   = google-beta.no_user_project_override
  folder_id  = "folder-id-for-new-project"
  name       = "Project Display Name"
  project_id = "project-id-for-new-project"

  # Required for the project to display in a list of Firebase projects.
  labels = {
    "firebase" = "enabled"
  }
}

# Enables required APIs.
resource "google_project_service" "services" {
  provider = google-beta.no_user_project_override
  project  = google_project.appcheck.project_id
  for_each = toset([
    "cloudresourcemanager.googleapis.com",
    "firebase.googleapis.com",
    "firebaseappcheck.googleapis.com",
    "firestore.googleapis.com",
    "serviceusage.googleapis.com",
  ])
  service = each.key

  # Don't disable the service if the resource block is removed by accident.
  disable_on_destroy = false
}

# Enables Firebase services for the new project created earlier.
resource "google_firebase_project" "appcheck" {
  provider = google-beta
  project  = google_project.appcheck.project_id

  depends_on = [google_project_service.services]
}

# Provisions the Firestore database instance.
resource "google_firestore_database" "database" {
  provider = google-beta
  project  = google_firebase_project.appcheck.project
  name     = "(default)"
  # See available locations: https://firebase.google.com/docs/projects/locations#default-cloud-location
  location_id = "name-of-region"
  # "FIRESTORE_NATIVE" is required to use Firestore with Firebase SDKs, authentication, and Firebase Security Rules.
  type             = "FIRESTORE_NATIVE"
  concurrency_mode = "OPTIMISTIC"

  # Wait for Firebase to be enabled in the Google Cloud project before initializing Firestore.
  depends_on = [
    google_firebase_project.appcheck,
  ]
}

# Creates a Firebase Android App in the new project created earlier.
resource "google_firebase_android_app" "appcheck" {
  provider     = google-beta
  project      = google_firebase_project.appcheck.project
  display_name = "Play Integrity app"
  package_name = "package.name.playintegrity"
  sha256_hashes = [
    # TODO: insert your Android app's SHA256 certificate
  ]
}

# It takes a while for App Check to recognize the new app
# If your app already exists, you don't have to wait 30 seconds.
resource "time_sleep" "wait_30s" {
  depends_on      = [google_firebase_android_app.appcheck]
  create_duration = "30s"
}

# Register the Android app with the Play Integrity provider
resource "google_firebase_app_check_play_integrity_config" "appcheck" {
  provider = google-beta
  project  = google_firebase_project.appcheck.project
  app_id   = google_firebase_android_app.appcheck.app_id

  depends_on = [time_sleep.wait_30s, google_firestore_database.database]

  lifecycle {
    precondition {
      condition     = length(google_firebase_android_app.appcheck.sha256_hashes) > 0
      error_message = "Provide a SHA-256 certificate on the Android App to use App Check"
    }
  }
}

# Enable enforcement of App Check for Firestore
resource "google_firebase_app_check_service_config" "firestore" {
  provider = google-beta

  project    = google_firebase_project.appcheck.project
  service_id = "firestore.googleapis.com"

  depends_on = [google_project_service.services]
}

Ta konfiguracja tworzy nowy projekt Google Cloud, włącza w nim usługi Firebase i instaluje w nim nowy egzemplarz usługi Firebase Extension. Jeśli instancja już istnieje, jej parametry zostaną zaktualizowane na podstawie wartości podanych w konfiguracji.

# Creates a new Google Cloud project.
resource "google_project" "extensions" {
  provider   = google-beta.no_user_project_override
  folder_id  = "folder-id-for-new-project"
  name       = "Project Display Name"
  project_id = "project-id-for-new-project"

  # Associates the project with a Cloud Billing account
  # (required to use Firebase Extensions).
  billing_account = "000000-000000-000000"

  # Required for the project to display in a list of Firebase projects.
  labels = {
    "firebase" = "enabled"
  }
}

# Enables required APIs.
resource "google_project_service" "extensions" {
  provider = google-beta.no_user_project_override
  project  = google_project.extensions.project_id
  for_each = toset([
    "cloudbilling.googleapis.com",
    "cloudresourcemanager.googleapis.com",
    "serviceusage.googleapis.com",
    "firebase.googleapis.com",
    "firebaseextensions.googleapis.com",
  ])
  service = each.key

  # Don't disable the service if the resource block is removed by accident.
  disable_on_destroy = false
}

# Enables Firebase services for the new project created above.
resource "google_firebase_project" "extensions" {
  provider = google-beta
  project  = google_project.extensions.project_id

  depends_on = [
    google_project_service.extensions,
  ]
}

# Installs an instance of the "Translate Text in Firestore" extension.
# Or updates the extension if the specified instance already exists.
resource "google_firebase_extensions_instance" "translation" {
  provider = google-beta
  project = google_project.extensions.project_id

  instance_id = "translate-text-in-firestore"
  config {
    extension_ref = "firebase/firestore-translate-text"

    params = {
      COLLECTION_PATH      = "posts/comments/translations"
      DO_BACKFILL          = true
      LANGUAGES            = "ar,en,es,de,fr"
      INPUT_FIELD_NAME     = "input"
      LANGUAGES_FIELD_NAME = "languages"
      OUTPUT_FIELD_NAME    = "translated"
    }

    system_params = {
      "firebaseextensions.v1beta.function/location"                   = "us-central1"
      "firebaseextensions.v1beta.function/memory"                     = "256"
      "firebaseextensions.v1beta.function/minInstances"               = "0"
      "firebaseextensions.v1beta.function/vpcConnectorEgressSettings" = "VPC_CONNECTOR_EGRESS_SETTINGS_UNSPECIFIED"
    }
  }
}



Rozwiązywanie problemów i najczęstsze pytania

W tym przewodniku podczas pracy z „projektami” używamy tych atrybutów Terraform.

project w bloku resource

Zalecane: jeśli to możliwe, dołącz atrybut project do każdego bloku resource

Dzięki uwzględnieniu atrybutu projektu Terraform utworzy infrastrukturę określoną w bloku zasobów w określonym projekcie. W tym przewodniku i w przykładowych plikach konfiguracji stosujemy tę metodę.

Zapoznaj się z oficjalną dokumentacją Terraform dotyczącą project.

user_project_override w bloku provider

Do alokowania większości zasobów należy użyć opcji user_project_override = true, która umożliwia sprawdzenie limitu w Twoim projekcie Firebase. Aby jednak skonfigurować nowy projekt tak, aby mógł akceptować kontrole limitu, musisz najpierw użyć user_project_override = false.

Zapoznaj się z oficjalną dokumentacją Terraform dotyczącą user_project_override.

Upewnij się, że konto użytkownika, którego używasz do wykonywania poleceń gcloud CLI, zaakceptowało Warunki korzystania z usługi Firebase.

  • Aby to sprawdzić, otwórz przeglądarkę, zaloguj się na konto użytkownika i spróbuj wyświetlić istniejący projekt Firebase w konsoli Firebase. Jeśli możesz wyświetlić istniejący projekt Firebase, oznacza to, że konto użytkownika zaakceptowało Warunki korzystania z usługi Firebase.

  • Jeśli nie możesz wyświetlić żadnego istniejącego projektu Firebase, konto użytkownika prawdopodobnie nie zaakceptowało Warunków korzystania z usługi Firebase. Aby to naprawić, utwórz nowy projekt Firebase w Firebase konsoli i zaakceptuj Warunki korzystania z usługi Firebase w ramach tworzenia projektu. Możesz natychmiast usunąć ten projekt w Ustawieniach projektu w konsoli.

Zaczekaj kilka minut, a potem spróbuj ponownie uruchomić terraform apply.

Może to być spowodowane opóźnieniem propagacji w różnych systemach. Spróbuj rozwiązać ten problem, importując zasób do stanu Terraform, wykonując polecenie terraform import. Następnie spróbuj ponownie uruchomić terraform apply.

Informacje o importowaniu poszczególnych zasobów znajdziesz w sekcji „Import” dokumentacji Terraform (np. w dokumentacji „Import” dla Cloud Firestore).

Jak sugeruje błąd, Terraform może próbować udostępnić kilka indeksów lub utworzyć dokument jednocześnie i napotkać błąd dotyczący równoczelności. Spróbuj ponownie uruchomić terraform apply.

Ten błąd oznacza, że Terraform nie wie, w którym projekcie ma sprawdzić limit. Aby rozwiązać ten problem, sprawdź w bloku resource te informacje:

  • Sprawdź, czy określono wartość atrybutu project.
  • Upewnij się, że używasz dostawcy z wartością user_project_override = true(bez aliasu), który w przypadku przykładów Firebase to google-beta.

Oto możliwe przyczyny, dla których identyfikator projektu może już istnieć:

  • Projekt powiązany z tym identyfikatorem należy do innej osoby.

    • Rozwiązanie problemu: wybierz inny identyfikator projektu.
  • projekt powiązany z tym identyfikatorem został niedawno usunięty (w stanie miękkiego usunięcia);

    • Rozwiązanie problemu: jeśli uważasz, że projekt powiązany z tym identyfikatorem należy do Ciebie, sprawdź stan projektu za pomocą projects.get interfejsu API REST.
  • projekt powiązany z tym identyfikatorem istnieje prawidłowo w kontekście bieżącego użytkownika; Możliwą przyczyną błędu może być przerwanie poprzedniego terraform apply.

    • Rozwiązanie problemu: uruchom te polecenia:
      terraform import google_project.default PROJECT_ID a potem
      terraform import google_firebase_project.default PROJECT_ID

Jeśli domyślny folder Cloud Storage został skonfigurowany (za pomocą google_app_engine_application) przed próbą skonfigurowania domyślnej instancji Cloud Firestore, domyślna instancja Cloud Firestore została już skonfigurowana. Pamiętaj, że instancja bazy danych utworzona przez pakiet SDK działa w trybie Datastore, co oznacza, że nie jest dostępna dla pakietów SDK Firebase, uwierzytelniania ani Firebase Security Rules. Jeśli chcesz używać usługi Cloud Firestore z tymi usługami Firebase, musisz opróżnić bazę danych, a potem zmienić jej typ w konsoli Google Cloud.

Gdy zarezerwujesz domyślny kontener Cloud Storage projektu (za pomocą google_app_engine_application), a projekt nie ma jeszcze domyślnej instancji Cloud Firestore, google_app_engine_application automatycznie zarezerwuje domyślną instancję Cloud Firestore projektu.

Ponieważ instancja domyślna Cloud Firestore Twojego projektu jest już udostępniona, google_firestore_database wygeneruje błąd, jeśli spróbujesz ponownie udostępnić tę instancję domyślną.

Po wdrożenie domyślnej instancji Cloud Firestore projektu nie można jej „ponownie skonfigurować” ani zmienić jej lokalizacji. Pamiętaj, że utworzona instancja bazy danych jest w trybie Datastore, co oznacza, że nie jest ona dostępna dla pakietów SDK Firebase, uwierzytelniania ani Firebase Security Rules. Jeśli chcesz używać usługi Cloud Firestore z tymi usługami Firebase, musisz opróżnić bazę danych, a potem zmienić jej typ w konsoli Google Cloud.