Настраивайте проекты и продукты Firebase и управляйте ими через Terraform.

1. Введение

Цели

С помощью Terraform можно настроить и управлять проектом Firebase, включая программную конфигурацию инфраструктуры и продуктов Firebase.

В этом практическом занятии сначала описывается, как создать конфигурационный файл Terraform для создания нового проекта Firebase, а затем как настроить приложения и продукты Firebase, которые вы хотите использовать в этом проекте. Мы также рассмотрим основы работы с командной строкой Terraform, такие как предварительный просмотр изменений и их последующая реализация.

Если вы хотели научиться настраивать и управлять проектами и продуктами Firebase с помощью Terraform, то этот практический курс для вас!

Что вы узнаете

  • Как создать конфигурационный файл Terraform ( *.tf )
  • Как использовать команды CLI Terraform для управления вашей инфраструктурой
  • Как изменить конфигурацию для обновления ресурсов и служб
  • Как применить вашу конфигурацию к реальному веб-приложению (например, Friendly Chat )
  • Как определить параллельные (и синхронные) конфигурации в разных средах (производственная, тестовая и т. д.)

Что вам понадобится

Для успешного выполнения этого практического задания вам необходимы базовые навыки работы с Terraform и его терминологией, включая следующие предварительные условия:

  • Установите Terraform и ознакомьтесь с его возможностями, используя официальные руководства.

В этом практическом занятии представлен реальный пример приложения, позволяющий протестировать и взаимодействовать с тем, что вы создаёте с помощью Terraform. Для этого вам потребуется следующее:

  • Пример кода веб-приложения — скачайте этот код на следующем шаге практического занятия.
  • Менеджер пакетов npm (который обычно поставляется вместе с Node.js ) — установите следующие инструменты.
  • Firebase CLI — установите этот CLI и войдите в систему.

2. Получите стартовый код

В этом практическом занятии вы сможете протестировать ресурсы, выделенные с помощью Terraform, на реальном веб-приложении. Мы рекомендуем сделать это, чтобы понять все шаги, необходимые для использования ресурсов, выделенных Terraform.

Клонируйте репозиторий codelab на GitHub из командной строки:

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

В качестве альтернативы, если у вас не установлен Git, вы можете загрузить репозиторий в виде ZIP-файла .

3. Создайте конфигурацию Terraform.

Настройка Terraform

  1. В коде загруженного демонстрационного приложения перейдите в корневую директорию web приложения.
  2. В корневом каталоге создайте конфигурационный файл Terraform с именем main.tf со следующими начальными настройками:

    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 . Синтаксис alias Terraform позволяет различать две настройки провайдеров на следующих шагах этого практического занятия.

Инициализируйте Terraform в указанной директории.

Для создания новой конфигурации в первый раз необходимо загрузить провайдер, указанный в конфигурации.

Для выполнения этой инициализации запустите следующую команду из корневого каталога того же каталога, что и ваш конфигурационный файл main.tf :

terraform init

4. Создайте проект Firebase с помощью Terraform.

Чтобы "создать проект Firebase", важно помнить, что каждый проект Firebase на самом деле является проектом Google Cloud, просто с включенными для него сервисами Firebase.

Добавьте блоки для базового проекта Google Cloud и API.

  1. Сначала выполните развертывание базового проекта Google Cloud.

    В файл конфигурации main.tf добавьте следующий блок ресурсов.

    Вам необходимо указать собственное название проекта (например, "Terraform FriendlyChat Codelab" ) и собственный идентификатор проекта (например, "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: API использования сервиса и API управления Firebase.

    Обычно эта функция включения API выполняется автоматически при создании проекта Firebase через консоль Firebase, но для включения этой функции в 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
    }
    
    Включив 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 .

The Terraform FriendlyChat Codelab project selected on the Firebase console

5. Зарегистрируйте свое приложение Firebase через Terraform.

Для использования 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 обнаружит, что проект с указанным идентификатором уже существует, сравнит текущее состояние проекта с содержимым файла .tf и внесет необходимые изменения.
  2. Ознакомьтесь с распечатанным планом действий. Если все выглядит так, как ожидалось, введите yes и нажмите Enter для подтверждения действий.

Подтвердите изменения.

Проверить состояние недавно созданного ресурса можно, выполнив следующую команду:

terraform show

В качестве альтернативы вы можете убедиться в успешной регистрации приложения в вашем проекте, просмотрев его в консоли Firebase. Перейдите в «Настройки проекта» , а затем прокрутите вниз до раздела «Ваши приложения» .

6. Настройка аутентификации Firebase

Аутентификация — важная составляющая любого приложения. Чтобы позволить конечным пользователям входить в ваше веб-приложение с помощью своих учетных записей Google, вы можете включить аутентификацию Firebase и настроить вход через Google.

Обратите внимание, что в этом практическом занятии мы предлагаем два разных варианта настройки аутентификации Firebase:

  • Вариант 1 (рекомендуемый) : Настройте аутентификацию Firebase в консоли, для чего не требуется GCIP.
    • Использование этой опции означает, что вам не нужно связывать свой новый проект с учетной записью облачной биллинговой системы.
  • Вариант 2 : Настройка аутентификации Firebase через Terraform с использованием API платформы Google Cloud Identity Platform (GCIP).
    • Использование этого варианта означает, что вам необходимо связать свой новый проект с учетной записью Cloud Billing, поскольку GCIP требует, чтобы проект был привязан к тарифному плану Blaze.

Вариант 1: Настройка аутентификации с помощью консоли Firebase.

Для настройки аутентификации Firebase с помощью консоли Firebase вашему проекту не обязательно использовать тарифный план Blaze.

Вот как настроить аутентификацию Firebase и войти в систему с помощью Google:

  1. В консоли Firebase найдите раздел «Сборка» на левой панели.
  2. Нажмите «Аутентификация» , затем «Начать» и, наконец, вкладку «Способ входа» (или нажмите здесь, чтобы перейти непосредственно туда).
  3. Нажмите «Добавить нового поставщика» и в разделе «Дополнительные поставщики» выберите Google .
  4. Активируйте переключатель «Включить ».
  5. Установите для общедоступного приложения, например, FriendlyChat (это название не обязательно должно быть уникальным во всем мире).
  6. Выберите адрес электронной почты службы поддержки проекта из выпадающего меню, а затем нажмите «Сохранить» . Configuring Firebase Auth on the Firebase console
  7. В списке доступных способов авторизации должен отображаться Google. Firebase console Authentication page: Google sign-in enabled

Вариант 2: Настройка аутентификации через Terraform с использованием API Google Cloud Identity Platform (GCIP).

Для настройки аутентификации Firebase через Terraform необходимо использовать API GCIP, а это значит, что проект должен быть подключен к тарифному плану Blaze. Для перехода на тарифный план Blaze необходимо связать проект с учетной записью Cloud Billing.

Включение выставления счетов через Terraform

  1. Если у вас еще нет учетной записи Cloud Billing, первым шагом будет создание новой учетной записи в консоли Google Cloud . При этом запишите идентификатор учетной записи для выставления счетов . Идентификатор учетной записи для выставления счетов можно найти на странице «Выставление счетов» в учетной записи , связанной с вашим проектом. Enabling a billing account using the Google Cloud console
  2. Чтобы включить оплату в вашем проекте с помощью Terraform, добавьте атрибут billing_account в существующий ресурс google_project в файле main.tf :

    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 и войдите в систему с помощью Google через Terraform.

  1. Для настройки аутентификации Firebase с использованием GCIP добавьте в файл 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 . Для этого перейдите в раздел «API и сервисы» в консоли Google Cloud.
  3. Поскольку вы впервые создаете идентификатор клиента для этого проекта, вам необходимо настроить экран согласия OAuth.
    1. Откройте страницу согласия OAuth , а затем выберите только что созданный проект.
    2. Установите тип пользователя на «Внешний» , а затем нажмите «Создать» .
    3. На следующем экране выполните следующие действия, а затем нажмите «Сохранить и продолжить» .
      • Установите для общедоступного приложения имя , например, FriendlyChat (это имя не обязательно должно быть уникальным во всем мире).
      • Выберите адрес электронной почты службы поддержки пользователей из выпадающего меню.
      • Введите адрес электронной почты, чтобы получить контактную информацию разработчика .
    4. На следующих экранах выполните следующие действия:
      • На странице «Области действия» примите значения по умолчанию, а затем нажмите «Сохранить и продолжить» .
      • На странице «Тестовые пользователи» примите значения по умолчанию, а затем нажмите «Сохранить и продолжить» .
      • Просмотрите сводку, а затем нажмите «Назад на панель управления» .
      Configuring an OAuth2 client using the Google Cloud console
  4. На странице «Учетные данные» настройте OAuth-клиент, выполнив следующие действия:
    1. Нажмите «Создать учетные данные» и выберите «Идентификатор клиента OAuth» .
    2. В раскрывающемся списке «Тип приложения» выберите «Веб-приложение» .
    3. В поле «Название» введите название вашего приложения, например FriendlyChat (это название не обязательно должно быть уникальным во всем мире).
    4. Разрешите URL-адресу вашего приложения использовать этот OAuth-клиент, установив следующие параметры:
      • В разделе «Авторизованные источники JavaScript» нажмите «Добавить URI» и введите
        https://<PROJECT_ID>.firebaseapp.com , где <PROJECT_ID> — это идентификатор проекта, который вы указали в main.tf
      • В разделе «Авторизованные URI перенаправления» нажмите «Добавить URI» и введите
        https://<PROJECT_ID>.firebaseapp.com/__/auth/handler , где <PROJECT_ID> — это идентификатор проекта, который вы указали в main.tf
    5. Нажмите « Сохранить ».
    Obtaining the OAuth2 Client ID and secret from the Google Cloud console Credentials page
  5. Чтобы включить вход в систему через Google с использованием вашего идентификатора клиента OAuth и секретного ключа клиента, добавьте в файл 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 обнаружит, что проект с указанным идентификатором уже существует, и сравнит текущее состояние проекта с содержимым файла .tf . Затем он внесет все обнаруженные изменения.
  2. Ознакомьтесь с распечатанным планом действий. Если все выглядит так, как ожидалось, введите yes и нажмите Enter для подтверждения действий.

Подтвердите изменения.

  1. В консоли Firebase найдите раздел «Сборка» на левой панели.
  2. Нажмите «Аутентификация» , а затем перейдите на вкладку «Способ входа» (или нажмите здесь, чтобы перейти непосредственно туда).
  3. В списке доступных способов авторизации должен отображаться Google. Firebase console Authentication page: Google sign-in enabled

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. Каждый экземпляр базы данных Firestore, доступный для Firebase, должен быть защищен правилами безопасности Firebase .

    В этом примере кода представлен набор правил безопасного использования Firestore в файле firestore.rules , который находится в корневом каталоге web сервера.
  4. Добавьте в файл main.tf следующие блоки ресурсов, чтобы выполнить следующие действия:
    • Создайте набор правил безопасности Firebase на основе локального файла firestore.rules .
    • Опубликуйте набор правил для экземпляра 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» , а затем нажмите вкладку «Правила» .
    Verifying Cloud Firestore rules using the Firebase console

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. Каждый сегмент Cloud Storage, доступный для Firebase, должен быть защищен правилами безопасности Firebase .

    В этом примере кода представлен набор правил безопасного использования Firestore в файле storage.rules , который находится в корневом каталоге web сервера.
  3. Добавьте в файл main.tf следующие блоки ресурсов, чтобы выполнить следующие действия:
    • Создайте набор правил безопасности Firebase из локального файла.
    • Опубликуйте набор правил для хранилища.
    Обратите внимание, что эти блоки ресурсов выполняют действия, эквивалентные нажатию кнопки «Опубликовать» в консоли 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. Перейдите в раздел «Хранилище» , а затем нажмите вкладку «Правила» .
    Verifying security rules using the Firebase console

9. Запустите приложение локально.

Теперь вы готовы впервые запустить своё веб-приложение! Для локального запуска приложения вы будете использовать эмулятор Firebase Hosting .

  1. Откройте новое окно терминала и из web каталога выполните следующую команду Firebase CLI, чтобы запустить эмулятор:
    firebase emulators:start --project=<PROJECT_ID>
    
  2. В браузере откройте веб-приложение по локальному URL-адресу, полученному от CLI (обычно http://localhost:5000 ).

Вы должны увидеть пользовательский интерфейс вашего приложения FriendlyChat, который (пока!) не работает. Приложение еще не подключено к Firebase, но, выполнив следующие шаги этого практического задания, вы его подключите!

Обратите внимание, что всякий раз, когда вы вносите изменения в свое веб-приложение (как это будет происходить на следующих этапах этого практического занятия), обновляйте страницу в браузере, чтобы обновить локальный URL-адрес с учетом этих изменений.

10. Установите, настройте и инициализируйте Firebase.

Для работы приложения с Firebase вашему приложению необходим SDK Firebase и конфигурация Firebase для вашего проекта Firebase.

Пример кода для этого практического занятия представляет собой уже работающее приложение со всеми зависимостями и необходимыми функциями для использования различных продуктов Firebase. Вы можете посмотреть в web/package.json и web/src/index.js если хотите увидеть, что уже сделано.

Несмотря на то, что пример кода в основном готов, вам все равно нужно выполнить несколько действий, чтобы запустить приложение, в том числе: установить Firebase SDK, запустить сборку, добавить конфигурацию Firebase в приложение и, наконец, инициализировать Firebase.

Установите Firebase SDK и запустите сборку webpack.

Для начала сборки вашего приложения вам потребуется выполнить несколько команд.

  1. Откройте новое окно терминала.
  2. Убедитесь, что вы находитесь в корневом каталоге web сервера.
  3. Выполните npm install , чтобы загрузить SDK Firebase.
  4. Выполните npm update , чтобы обновить все зависимости.
  5. Запустите команду npm run start , чтобы запустить webpack.

В оставшейся части практического занятия webpack будет постоянно пересобирать ваш исходный код.

Добавьте конфигурацию Firebase в ваше приложение.

Также необходимо добавить конфигурацию Firebase в ваше приложение, чтобы SDK Firebase знали, какой проект Firebase вы хотите использовать.

Для этого практического занятия у вас есть два разных варианта получения конфигурации Firebase:

  • Вариант 1 : Получите конфигурацию Firebase из консоли Firebase.
  • Вариант 2 : Получите конфигурацию Firebase через Terraform.

Вариант 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 и добавьте её в свой код.

В качестве альтернативы, вы можете получить конфигурацию Firebase через Terraform в качестве выходного значения в 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 сервера создайте новый конфигурационный файл Terraform с именем main_staging.tf .
  2. Скопируйте все блоки ресурсов из файла main.tf (кроме блоков terraform и provider ) и вставьте их в файл 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 .
    Полную конфигурацию файла main_staging.tf можно найти в репозитории GitHub этого учебного пособия:

    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_database и google_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

Этот вариант обеспечивает более эффективное повторное использование кода, если каждый проект не должен существенно отличаться от других, и вы хотите распространить изменения на все проекты одновременно. Он использует мета-аргумент for_each в языке Terraform.

  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.
    
    Полную конфигурацию файла main.tf , использующего мета-аргумент for_each , можно найти в репозитории GitHub этого учебного пособия:

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

    Если вы хотите использовать эту конфигурацию, убедитесь, что вы выполнили следующие действия:
    1. Скопируйте конфигурацию из main-foreach.tf и вставьте её в свой файл main.tf
    2. В файле main.tf выполните следующие действия:
      • In the google_project resource block, update the name attribute, the project-id attribute, and (if you set up Authentication via Terraform) the billing_account attribute with your own values.
      • In the google_firebase_web_app resource block, update the display_name attribute with your own value.
      • In the google_firestore_database and google_app_engine_application resource blocks, update the location_id attributes with your own value.
  3. Instead of applying this config right away, it's important to understand and fix a few things about how Terraform interprets this config compared to the existing infrastructure.
    1. Right now, if you applied this config that uses for_each , the resource addresses would look like the following:
      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"]
      
      However, the existing project you created in the first part of this codelab is known to Terraform as the following:
      google_project.default
      google_firebase_project.default
      google_firebase_android_app.default
      
    2. Run terraform plan to see what actions Terraform would take given the current state.

      The output should show that Terraform would delete the project you created in the first part of this codelab and create two new projects. This is because Terraform doesn't know that the project at the address google_project.default has been moved to the new address google_project.default["prod"] .
    3. To fix this, run the terraform state mv command:
      terraform state mv "google_project.default" "google_project.default[\"prod\"]"
      
    4. Similarly, to fix all the other resource blocks, run terraform state mv for google_firebase_project , google_firebase_web_app , and all the other resource blocks in your main.tf file.
    5. Now, if you run terraform plan again, it shouldn't show that Terraform would delete the project you created in the first part of this codelab.
  4. Run terraform apply to provision your new "staging" Firebase project and all its resources and enable its services.
  5. Verify that everything was provisioned and enabled as expected by checking them in the Firebase console as before.

12. Bonus step: Deploy your staging and prod apps

  1. In your app's codebase, change the firebase-config.js to use the Firebase config from your staging project instead.

    To remind yourself how to get your Firebase config and add it to your app, see the earlier step of this codelab, Add your Firebase configuration to your app.
  2. At the root of your web directory, run the following command to deploy your app to your staging Firebase project.
    firebase deploy --only hosting --project=<STAGING_PROJECT_ID>
    
  3. Open your staging app in the browser via the URL that's printed in the output of firebase deploy . Try signing in, sending messages, and uploading images.

    When you deploy an app to a Firebase project, it uses real Firebase resources, not emulated resources. As you interact with your staging app, you should see data and images appear in your staging project in the Firebase console.
  4. After testing your app in staging, change the firebase-config.js back to using the prod project's Firebase config (the first project that you created in this codelab).
  5. At the root of your web directory, run the following command to deploy your app to your production Firebase project.
    firebase deploy --only hosting --project=<PRODUCTION_PROJECT_ID>
    
  6. Open your production app in the browser via the URL that's printed in the output of firebase deploy . Try signing in, sending messages, and uploading images.

    You should see data and images appear in your production project in the Firebase console.
  7. When you're finished interacting with the two apps for this codelab, you can stop Firebase from serving them. Run the following command for each of your projects:
    firebase hosting:disable --project=<STAGING_PROJECT_ID>
    
    firebase hosting:disable --project=<PRODUCTION_PROJECT_ID>
    

13. Congratulations!

You've used Terraform to configure a real-time chat web application! And you've followed best practices for development environments by creating separate Firebase projects for staging and prod.

Что мы рассмотрели

  • Using the Terraform CLI to manage cloud resources
  • Using Terraform to configure Firebase products (Authentication, Firestore, Cloud Storage, and Security Rules)
  • Running and testing a web app locally using the Firebase Local Emulator Suite
  • Importing Firebase into a web app
  • Using Terraform to replicate a configuration across multiple environments

For more information about Firebase and Terraform, visit our documentation . You can find a list of all Firebase products with Terraform support, sample Terraform configurations for common use cases, and helpful troubleshooting and FAQ.