1. はじめに
目標
Terraform を使用して、インフラストラクチャと Firebase プロダクトのプログラムによる構成など、Firebase プロジェクトの設定と管理を行うことができます。
この Codelab では、まず Terraform 構成ファイルを作成して新しい Firebase プロジェクトを作成する方法について説明し、次にそのプロジェクトで使用するアプリと Firebase プロダクトを構成する方法について説明します。また、Terraform コマンドラインの基本(変更のプレビューと実装など)についても説明します。
Terraform を使用して Firebase プロジェクトとプロダクトを設定して管理する方法を学びたい場合は、この Codelab がおすすめです。
学習内容
- Terraform 構成ファイル(
*.tf)を作成する方法 - Terraform CLI コマンドを使用してインフラストラクチャを管理する方法
 - 構成を変更してリソースとサービスを更新する方法
 - 実際のウェブアプリ(Friendly Chat)に構成を適用する方法
 - さまざまな環境(本番環境、ステージング環境など)で並列(同期)構成を定義する方法
 
必要なもの
- ターミナル/コンソール
 - 任意の IDE またはテキスト エディタ(WebStorm、Atom、Sublime、VS Code など)
 - 任意のブラウザ(Chrome など)
 - Google Cloud CLI(gcloud CLI)- この CLI をインストールし、ユーザー アカウントまたはサービス アカウントを使用してログインします。
 
この Codelab を完了するには、Terraform とその用語に関する基本的な知識が必要です。これには、次の前提条件が含まれます。
- Terraform をインストールし、公式のチュートリアルで Terraform について学習している
 
この Codelab では、Terraform でプロビジョニングしたものをテストして操作できるように、実際のサンプルアプリを提供します。これを行うには、次のものが必要です。
- ウェブアプリのサンプルコード - このコードは Codelab の次の手順でダウンロードします。
 - パッケージ マネージャー npm(通常は Node.js に付属) - これらのツールをインストールします。
 - Firebase CLI - この CLI をインストールしてログインします。
 
2. 開始用コードを取得する
この Codelab では、Terraform でプロビジョニングしたものを実際のウェブアプリでテストできます。Terraform でプロビジョニングされたリソースを使用するために必要なすべての手順を理解するために、このテストを行うことをおすすめします。
コマンドラインから、Codelab の GitHub リポジトリのクローンを作成します。
git clone https://github.com/firebase/codelab-friendlychat-web
または、git がインストールされていない場合は、リポジトリを ZIP ファイルとしてダウンロードすることもできます。
3. Terraform 構成を作成する
Terraform の設定
- ダウンロードしたサンプルアプリのコードベースで、
webディレクトリのルートに移動します。 - そのディレクトリのルートに、次の初期設定を含む 
main.tfという Terraform 構成ファイルを作成します。
main.tf# Terraform configuration to set up providers by version. terraform { required_providers { google-beta = { source = "hashicorp/google-beta" version = "~> 4.0" } } } # Configure the provider not to use the specified project for quota check. # This provider should only be used during project creation and initializing services. provider "google-beta" { alias = "no_user_project_override" user_project_override = false } # Configure the provider that uses the new project's quota. provider "google-beta" { user_project_override = true } 
各 google-beta プロバイダには、Terraform のオペレーションの割り当てチェック方法を決定する user_project_override という属性があります。ほとんどのリソースのプロビジョニングで user_project_override = true の使用を推奨します。これを使用すると、Firebase プロジェクトの割り当てがチェックされます。ただし、新しいプロジェクトをセットアップする際に割り当てチェックが行われるようにするには、最初に user_project_override=false を使用する必要があります。Terraform の alias 構文を使用すると、この Codelab の次の手順で 2 つのプロバイダ設定を区別できます。
ディレクトリで Terraform を初期化する
新しい構成を初めて作成する場合は、構成で指定されたプロバイダをダウンロードする必要があります。
この初期化を行うには、main.tf 構成ファイルと同じディレクトリのルートから次のコマンドを実行します。
terraform init
4. Terraform を使用して Firebase プロジェクトを作成する
「Firebase プロジェクトを作成する」には、各 Firebase プロジェクトが実際には Google Cloud プロジェクトであり、Firebase サービスが有効になっていることを覚えておくことが重要です。
基盤となる Google Cloud プロジェクトと API のブロックを追加する
- まず、基盤となる Google Cloud プロジェクトをプロビジョニングします。
main.tf構成ファイルに、次のリソース ブロックを追加します。
独自のプロジェクト名("Terraform FriendlyChat Codelab"など)と独自のプロジェクト ID("terraform-codelab-your-initials"など)を指定する必要があります。nameの値は Firebase インターフェース内でのみ使用され、エンドユーザーには表示されません。ただし、project_id値は Google に対してプロジェクトを一意に識別するため、一意の値を指定してください。 main.tf... # Create a new Google Cloud project. resource "google_project" "default" { provider = google-beta.no_user_project_override name = "<PROJECT_NAME_OF_YOUR_PROJECT>" project_id = "<PROJECT_ID_OF_YOUR_PROJECT>" # Required for the project to display in any list of Firebase projects. labels = { "firebase" = "enabled" } } - 次に、必要な基盤となる API(Service Usage API と Firebase Management API)を有効にする必要があります。
通常、Firebase コンソールを使用して Firebase プロジェクトを作成すると、この API の有効化はバックグラウンドで処理されますが、Terraform には明示的に有効化を指示する必要があります。main.tf構成ファイル(新しい Cloud プロジェクトを作成するブロックのすぐ下)に、次のリソース ブロックを追加します。
main.tf Service Usage API を有効にすると、新しいプロジェクトで割り当てチェックを受け入れることができるようになります。したがって、以降のリソース プロビジョニングとサービス有効化では、... # 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 }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,
  ]
}
上記のリソース ブロックには、Terraform に基盤となる API が有効になるまで待機するように指示する depends_on 句があります。この句がないと、Terraform は依存関係を認識せず、リソースを並行してプロビジョニングするときにエラーが発生する可能性があります。
構成を適用する
- 新しいリソースをプロビジョニングして構成ファイルで指定された API を有効にするには、
main.tfファイル(web)と同じディレクトリのルートから次のコマンドを実行します。terraform apply
 - ターミナルに、Terraform が実行するアクションのプランが出力されます。
すべてが想定どおりになっている場合は、yesと入力してアクションを承認します。
main.tfTerraform 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 コンソールでプロジェクトを表示して、プロジェクトが作成されたことを確認することもできます。

5. Terraform を使用して Firebase アプリを登録する
Firebase を使用するには、アプリの各プラットフォーム バリエーションを Firebase プロジェクトに登録する必要があります。この Codelab では、実際のアプリを使用して、Terraform でプロビジョニングしたものをテストし、操作します。このアプリはウェブアプリであるため、新しく作成した Firebase プロジェクトに Firebase ウェブアプリを登録するように Terraform に指示する必要があります。
ウェブアプリを登録するブロックを追加する
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"
}
構成を適用する
- 新しいリソースをプロビジョニングするには、
main.tfファイル(web)と同じディレクトリのルートから次のコマンドを実行します。 このコマンドでは、新しい Google Cloud プロジェクトは再作成されません。Terraform は、指定されたプロジェクト ID のプロジェクトがすでに存在することを検出し、プロジェクトの現在の状態とterraform apply
.tfファイルの内容を比較して、検出された変更を行います。 - 印刷された行動計画を確認します。すべてが想定どおりに表示されたら、「
yes」と入力して Enter キーを押し、アクションを承認します。 
変更を検証する
新しくプロビジョニングされたリソースの状態を確認するには、次のコマンドを実行します。
terraform show
または、Firebase コンソールでアプリを表示して、アプリがプロジェクトに正常に登録されたことを確認することもできます。[プロジェクト設定] に移動し、[アプリ] セクションまで下にスクロールします。
6. Firebase Authentication を設定する
認証はあらゆるアプリの重要な要素です。エンドユーザーが Google アカウントでウェブアプリにログインできるようにするには、Firebase Authentication を有効にして、Google でログインする方法を設定します。
この Codelab では、Firebase Authentication を設定するための 2 つの異なるオプションを用意しています。
- オプション 1(推奨): コンソールで Firebase Authentication を設定します。GCIP は必要ありません。
- このオプションを使用すると、新しいプロジェクトを Cloud 請求先アカウントに関連付ける必要がなくなります。
 
 - オプション 2: Google Cloud Identity Platform(GCIP)API を使用して Terraform 経由で Firebase Authentication を設定します。
- このオプションを使用する場合は、新しいプロジェクトを Cloud 請求先アカウントに関連付ける必要があります。これは、GCIP でプロジェクトに Blaze お支払いプランが適用されている必要があるためです。
 
 
オプション 1: Firebase コンソールを使用して Authentication を設定する
Firebase コンソールを使用して Firebase Authentication を設定する場合、プロジェクトに Blaze 料金プランを適用する必要はありません。
Firebase Authentication を設定して Google でログインする方法は次のとおりです。
- Firebase コンソールの左側のパネルで、[ビルド] セクションを見つけます。
 - [Authentication]、[始める] の順にクリックし、[ログイン方法] タブをクリックします(または、こちらをクリックして直接移動します)。
 - [新しいプロバイダを追加] をクリックし、[追加のプロバイダ] セクションで [Google] を選択します。
 - [有効にする] 切り替えをオンにします。
 - アプリの一般公開名を 
FriendlyChatなどの名前に設定します(グローバルに一意である必要はありません)。 - プルダウン メニューから [プロジェクト サポートのメールアドレス] を選択し、[保存] をクリックします。

 - Google が有効なログイン プロバイダとして表示されます。
![Firebase コンソールの [Authentication] ページ: Google ログインが有効になっている Firebase コンソールの [Authentication] ページ: Google ログインが有効になっている](https://firebase.google.com/static/codelabs/firebase-terraform/img/c11e3c03fe5461d3.png?hl=ja)
 
オプション 2: Google Cloud Identity Platform(GCIP)API を使用して Terraform で認証を設定する
Terraform で Firebase Authentication を設定するには、GCIP API を使用する必要があります。つまり、プロジェクトのお支払いプランが Blaze である必要があります。Firebase プロジェクトをアップグレードして Blaze プランを使用するには、Cloud 請求先アカウントをプロジェクトに関連付けます。
Terraform を使用して課金を有効にする
- Cloud Billing アカウントをまだお持ちでない場合は、まず Google Cloud コンソールで新しいアカウントを作成します。その場合は、請求先アカウント ID をメモしておきます。請求先アカウント ID は、プロジェクトに関連付けられている [お支払い] ページの [請求先アカウント ID] で確認できます。
![Google Cloud コンソールの [お支払い] ページ Google Cloud コンソールを使用して請求先アカウントを有効にする](https://firebase.google.com/static/codelabs/firebase-terraform/img/37bfd701518dbe0b.png?hl=ja)
 - Terraform を使用してプロジェクトで課金を有効にするには、
main.tfファイルの既存のgoogle_projectリソースにbilling_account属性を追加します。
main.tf... # Create a new Google Cloud project. resource "google_project" "default" { provider = google-beta.no_user_project_override name = "<PROJECT_NAME_OF_YOUR_PROJECT>" project_id = "<PROJECT_ID_OF_YOUR_PROJECT>" billing_account = "<YOUR_BILLING_ACCOUNT_ID>" # Add this line with your Cloud Billing account ID # Required for the project to display in any list of Firebase projects. labels = { "firebase" = "enabled" } } ... 
Terraform を使用して Firebase Authentication と Google ログインを有効にする
- GCIP を使用して Firebase Authentication をプロビジョニングするには、
main.tfファイルに次のリソース ブロックを追加します。
main.tf... # Enable the Identity Toolkit API. resource "google_project_service" "auth" { provider = google-beta project = google_firebase_project.default.project service = "identitytoolkit.googleapis.com" # Don't disable the service if the resource block is removed by accident. disable_on_destroy = false } # Create an Identity Platform config. # Also, enable Firebase Authentication using Identity Platform (if Authentication isn't yet enabled). resource "google_identity_platform_config" "auth" { provider = google-beta project = google_firebase_project.default.project # For example, you can configure to auto-delete anonymous users. autodelete_anonymous_users = true # Wait for identitytoolkit.googleapis.com to be enabled before initializing Authentication. depends_on = [ google_project_service.auth, ] } - Google でログインを有効にするには、OAuth クライアントが必要です。この設定を行うには、Google Cloud コンソールの [API とサービス] セクションに移動します。
 - このプロジェクトでクライアント ID を作成するのは今回が初めてなので、OAuth 同意画面を構成する必要があります。
- OAuth 同意画面のページを開き、作成したプロジェクトを選択します。
 - [ユーザーの種類] を [外部] に設定し、[作成] をクリックします。
 - 次の画面で、以下を完了し、[保存して続行] をクリックします。
- アプリの一般公開用のアプリ名を 
FriendlyChatなどに設定します(グローバルに一意である必要はありません)。 - プルダウン メニューから [ユーザー サポートのメールアドレス] を選択します。
 - [デベロッパーの連絡先情報] にメールアドレスを入力します。
 
 - アプリの一般公開用のアプリ名を 
 - 次の画面で、次の操作を行います。
- [スコープ] ページでデフォルト値をそのまま使用し、[保存して次へ] をクリックします。
 - [テストユーザー] ページでデフォルト値をそのままにして、[保存して次へ] をクリックします。
 - 概要を確認して、[ダッシュボードに戻る] をクリックします。
 

 
 - 次の手順で、[認証情報] ページで OAuth クライアントを設定します。
- [認証情報を作成] をクリックし、[OAuth クライアント ID] を選択します。
 - [アプリケーションの種類] プルダウンから [ウェブ アプリケーション] を選択します。
 - [名前] フィールドに、アプリの名前(
FriendlyChatなど)を入力します(グローバルに一意である必要はありません)。 - 次の設定を行って、アプリの URL でこの OAuth クライアントを使用できるようにします。
- [承認済みの JavaScript 生成元] で [URI を追加] をクリックし、
https://<PROJECT_ID>.firebaseapp.comと入力します。ここで、<PROJECT_ID>はmain.tfで設定したプロジェクト ID です。 - [承認済みのリダイレクト URI] で、[URI を追加] をクリックして 
https://<PROJECT_ID>.firebaseapp.com/__/auth/handlerと入力します。ここで、<PROJECT_ID>はmain.tfで設定したプロジェクト ID です。 
 - [承認済みの JavaScript 生成元] で [URI を追加] をクリックし、
 - [Save] をクリックします。
 
![Google Cloud コンソールの [認証情報] ページ Google Cloud コンソールの [認証情報] ページから OAuth2 クライアント ID とシークレットを取得する](https://firebase.google.com/static/codelabs/firebase-terraform/img/4d96e882873d8248.png?hl=ja)
 - OAuth クライアント ID とクライアント シークレットを使用して Google でログインを有効にするには、
main.tfファイルに次のブロックを追加します。
main.tf... variable "oauth_client_secret" { type = string description = "OAuth client secret. For this codelab, you can pass in this secret through the environment variable TF_VAR_oauth_client_secret. In a real app, you should use a secret manager service." sensitive = true } resource "google_identity_platform_default_supported_idp_config" "google_sign_in" { provider = google-beta project = google_firebase_project.default.project enabled = true idp_id = "google.com" client_id = "<YOUR_OAUTH_CLIENT_ID>" client_secret = var.oauth_client_secret depends_on = [ google_identity_platform_config.auth ] } 
構成を適用する
- 構成に従って認証を設定するには、
main.tfファイル(web)と同じディレクトリのルートから次のコマンドを実行します。export TF_VAR_oauth_client_secret="<YOUR_OAUTH_CLIENT_SECRET>"
terraform apply
terraform applyを実行しても、新しい Google Cloud プロジェクトは再作成されません。Terraform は、指定されたプロジェクト ID のプロジェクトがすでに存在することを検出し、プロジェクトの現在の状態と.tfファイルの内容を比較します。その後、検出された変更が適用されます。 - 印刷された行動計画を確認します。すべてが想定どおりに表示されたら、「
yes」と入力して Enter キーを押し、アクションを承認します。 
変更を検証する
- Firebase コンソールの左側のパネルで、[ビルド] セクションを見つけます。
 - [認証] をクリックし、[ログイン方法] タブをクリックします(または、ここをクリックして直接移動します)。
 - Google が有効なログイン プロバイダとして表示されます。
![Firebase コンソールの [Authentication] ページ: Google ログインが有効になっている Firebase コンソールの [Authentication] ページ: Google ログインが有効になっている](https://firebase.google.com/static/codelabs/firebase-terraform/img/c11e3c03fe5461d3.png?hl=ja)
 
7. Firestore データベースとそのセキュリティ ルールを設定する
この Codelab のウェブアプリでは、エンドユーザー間のメッセージを Firestore データベースに保存します。
- 必要な 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 ] } <NAME_OF_DESIRED_REGION>を、データベースを配置するリージョンに変更します。
本番環境アプリを開発する場合は、ユーザーの大部分に近いリージョンで、Cloud Functions などの他の Firebase サービスと共通のリージョンに配置することをおすすめします。この Codelab では、us-east1(サウスカロライナ)を使用するか、最寄りのリージョンを使用します(Cloud Firestore のロケーションを参照)。- Firebase からアクセス可能なすべての Firestore データベース インスタンスは、Firebase セキュリティ ルールで保護する必要があります。
この Codelab のサンプルコードでは、webディレクトリのルートにあるfirestore.rulesファイルに一連の安全な Firestore ルールが用意されています。 main.tfファイルに次のリソース ブロックを追加して、次の操作を行います。- ローカルの 
firestore.rulesファイルから Firebase セキュリティ ルールのルールセットを作成します。 - Firestore インスタンスのルールセットをリリースします。
 
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 ] } }- ローカルの 
 terraform applyを実行して Firestore データベースをプロビジョニングし、セキュリティ ルールをデプロイします。- データベースがプロビジョニングされ、セキュリティ ルールがデプロイされていることを確認します。
- Firebase コンソールの左側のパネルで、[構築] セクションを見つけます。
 - [Firestore Database] セクションに移動し、[ルール] タブをクリックします。
 
![Cloud Firestore の [ルール] ページ Firebase コンソールを使用して Cloud Firestore ルールを検証する](https://firebase.google.com/static/codelabs/firebase-terraform/img/f7e02341df8d5d2.png?hl=ja)
 
8. Cloud Storage バケットとそのセキュリティ ルールを設定する
この Codelab のウェブアプリでは、エンドユーザー間で共有される画像を Cloud Storage バケットに保存します。
- 必要な API を有効にして Cloud Storage のデフォルト バケットをプロビジョニングするには、
main.tfファイルに次のリソース ブロックを追加します。
プロジェクトのデフォルトの Cloud Storage バケットは Google App Engine を介してプロビジョニングされ、Firestore データベースと同じロケーションにする必要があります。詳細については、App Engine のロケーションをご覧ください。
プロジェクトに複数のバケットが必要な場合は、google_storage_bucketリソースを使用してプロビジョニングします(この Codelab では説明しません)。
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 } - Firebase からアクセス可能なすべての Cloud Storage バケットは、Firebase セキュリティ ルールで保護する必要があります。
この Codelab のサンプルコードでは、storage.rulesファイルに一連の安全な Firestore ルールが用意されています。このファイルはwebディレクトリのルートにあります。 main.tfファイルに次のリソース ブロックを追加して、次の操作を行います。- ローカル ファイルから Firebase セキュリティ ルールのルールセットを作成します。
 - Storage バケットのルールセットをリリースします。
 
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 ] } }terraform applyを実行して、デフォルトの Cloud Storage バケットをプロビジョニングし、そのセキュリティ ルールをデプロイします。- バケットがプロビジョニングされ、セキュリティ ルールがデプロイされていることを確認します。
- Firebase コンソールの左側のパネルで、[ビルド] セクションを見つけます。
 - [ストレージ] セクションに移動し、[ルール] タブをクリックします。
 
![[Storage Rules] ページ Firebase コンソールを使用してセキュリティ ルールを検証する](https://firebase.google.com/static/codelabs/firebase-terraform/img/41a38c035a884766.png?hl=ja)
 
9. アプリをローカルで実行する
これで、ウェブアプリを初めて実行する準備が整いました。Firebase Hosting エミュレータを使用して、アプリをローカルで提供します。
- 新しいターミナル ウィンドウを開き、
webディレクトリから次の Firebase CLI コマンドを実行してエミュレータを起動します。firebase emulators:start --project=<PROJECT_ID>
 - ブラウザで、CLI から返されたローカル URL(通常は 
http://localhost:5000)でウェブアプリを開きます。 
FriendlyChat アプリの UI が(まだ)機能していない状態で表示されます。アプリはまだ Firebase に接続されていませんが、この Codelab の次の手順を完了すると接続されます。
ウェブアプリに変更を加えたら(この Codelab の次の手順で行うように)、ブラウザを更新してローカル URL に変更を適用してください。
10. Firebase をインストール、構成、初期化する
アプリで Firebase を使用するには、Firebase SDK と Firebase プロジェクトの Firebase 構成が必要です。
この Codelab のサンプルコードは、アプリでさまざまな Firebase プロダクトを使用するために必要な依存関係と関数がすべて含まれた、動作可能なアプリです。すでに完了している内容を確認する場合は、web/package.json と web/src/index.js をご覧ください。
サンプルコードはほぼ完成していますが、アプリを実行するには、Firebase SDK のインストール、ビルドの開始、Firebase 構成のアプリへの追加、Firebase の初期化など、いくつかの作業を行う必要があります。
Firebase SDK をインストールして webpack ビルドを開始する
アプリのビルドを開始するには、いくつかのコマンドを実行する必要があります。
- 新しいターミナル ウィンドウを開きます。
 webディレクトリのルートにいることを確認します。npm installを実行して、Firebase SDK をダウンロードします。npm updateを実行して、依存関係を更新します。npm run startを実行して webpack を起動します。
この Codelab の残りの部分では、webpack がソースコードを継続的に再ビルドします。
Firebase 構成をアプリに追加する
また、Firebase SDK が使用する Firebase プロジェクトを認識できるように、Firebase 構成をアプリに追加する必要があります。
この Codelab では、Firebase 構成を取得する方法が 2 つあります。
- オプション 1: Firebase コンソールから Firebase 構成を取得します。
 - オプション 2: Terraform を使用して Firebase 構成を取得します。
 
オプション 1: Firebase コンソールから構成を取得してコードベースに追加する
- Firebase コンソールで、[プロジェクトの設定] に移動します。
 - [マイアプリ] カードまで下にスクロールし、ウェブアプリを選択します。
 - Firebase SDK スニペット ペインで [Config] を選択し、構成スニペットをコピーします。
 - 次のように、構成をアプリの 
web/src/firebase-config.jsファイルに貼り付けます。
firebase-config.js... const config = { apiKey: "<API_KEY>", authDomain: "<PROJECT_ID>.firebaseapp.com", projectId: "<PROJECT_ID>", storageBucket: "<PROJECT_ID>.appspot.com", messagingSenderId: "<SENDER_ID>", appId: "<APP_ID>", measurementId: "<G-MEASUREMENT_ID>", }; ... 
オプション 2: Terraform を使用して構成を取得し、コードベースに追加する
または、Terraform を介して Firebase 構成を CLI の出力値として取得することもできます。
main.tfファイルで、google_firebase_web_appリソース ブロック(ウェブアプリをプロジェクトに登録したブロック)を見つけます。- そのブロックの直後に、次のブロックを追加します。
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", "") } } ... dataブロックとoutputブロックはインフラストラクチャを変更することを目的としていないため、次のコマンドを実行するだけで済みます。- ウェブアプリの Firebase 構成をディレクトリの Terraform 状態に読み込むには、次のコマンドを実行します。
terraform refresh
 - 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" } } } 
- ウェブアプリの Firebase 構成をディレクトリの Terraform 状態に読み込むには、次のコマンドを実行します。
 valueマップ内の値をコピーします。- これらの値(構成)をアプリの 
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 ファイルに次のコードを追加します。
...
const firebaseAppConfig = getFirebaseConfig();
initializeApp(firebaseAppConfig);
アプリを試す
Firebase のすべての設定が完了したので、機能的なウェブアプリを試してみましょう。
- アプリを配信しているブラウザを更新します。
 - これで、Google でログインしてチャットにメッセージを投稿できるようになります。画像ファイルがある場合は、アップロードすることもできます。
 
11. 環境間で構成を複製する
Terraform は、同様に構成された複数のインフラストラクチャの管理に優れています(たとえば、本番環境プロジェクトと同様のステージング Firebase プロジェクトの設定など)。
この Codelab では、ステージング環境として使用する 2 つ目の Firebase プロジェクトを作成します。
既存の構成を複製してこのステージング プロジェクトを作成するには、次の 2 つの方法があります。
- オプション 1: Terraform 構成のコピーを作成します。
このオプションは、複製されたプロジェクトがソース プロジェクトとどの程度異なるかを最も柔軟に設定できます。 - オプション 2: 
for_eachを使用して構成を再利用します。
このオプションは、各プロジェクトに大きな違いがなく、変更をすべてのプロジェクトに一度に伝播する場合に、コードの再利用性を高めます。 
オプション 1: Terraform 構成のコピーを作成する
このオプションは、複製されたプロジェクトがソース プロジェクトとどの程度異なるかを最も柔軟に設定できます。たとえば、表示名が異なるアプリや段階的リリースなどです。
webディレクトリのルートに、main_staging.tfという名前の新しい Terraform 構成ファイルを作成します。main.tfファイルからすべてのリソース ブロック(terraformブロックとproviderブロックを除く)をコピーし、main_staging.tfファイルに貼り付けます。- 次に、ステージング プロジェクトで動作するように、
main_staging.tfで複製された各リソース ブロックを変更する必要があります。- リソースラベル: 競合を避けるために新しい名前を使用します。たとえば、
resource "google_project" "default"の名前をresource "google_project" "staging"に変更します。 - リソース参照: それぞれを更新します。たとえば、
google_firebase_project.default.projectをgoogle_firebase_project.staging.projectに更新します。 
main_staging.tfファイルの完全な構成は、この Codelab の GitHub リポジトリにあります。web/terraform-checkpoints/replicate-config/main_staging-copypaste.tf
この構成を使用する場合は、次のことを確認してください。main_staging-copypaste.tfから構成をコピーし、main_staging.tfファイルに貼り付けます。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属性を独自の値で更新します。
# 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" } - リソースラベル: 競合を避けるために新しい名前を使用します。たとえば、
 terraform applyを実行して、新しい「ステージング」Firebase プロジェクトとそのすべてのリソースをプロビジョニングし、そのサービスを有効にします。- Firebase コンソールで、すべてが想定どおりプロビジョニングされ、有効になっていることを確認します。
 
オプション 2: for_each を使用して構成を再利用する
このオプションは、各プロジェクトに大きな違いがなく、変更をすべてのプロジェクトに一度に伝播する場合に、コードの再利用性を高めます。Terraform 言語の for_each メタ引数を使用します。
main.tfファイルを開きます。- 複製する各リソース ブロックに、次のように 
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.for_eachメタ引数を使用するmain.tfファイルの完全な構成は、この Codelab の GitHub リポジトリにあります。web/terraform-checkpoints/replicate-config/main-foreach.tf
この構成を使用する場合は、次の操作を行ってください。main-foreach.tfから構成をコピーし、main.tfファイルに貼り付けます。main.tfファイルで、次の操作を行います。google_projectリソース ブロックで、name属性、project-id属性、(Terraform を介して認証を設定した場合は)billing_account属性を独自の値で更新します。google_firebase_web_appリソース ブロックで、display_name属性を独自の値で更新します。google_firestore_databaseリソース ブロックとgoogle_app_engine_applicationリソース ブロックで、location_id属性を独自の値で更新します。
 - この構成をすぐに適用するのではなく、Terraform がこの構成を既存のインフラストラクチャと比較してどのように解釈するかについて、いくつかの点を理解して修正することが重要です。
- 現時点では、
for_eachを使用するこの構成を適用すると、リソース アドレスは次のようになります。 ただし、この Codelab の最初の部分で作成した既存のプロジェクトは、Terraform では次のように認識されます。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"]google_project.default google_firebase_project.default google_firebase_android_app.default terraform planを実行して、現在の状態に基づいて Terraform が実行するアクションを確認します。
出力には、Terraform がこの Codelab の最初の部分で作成したプロジェクトを削除し、2 つの新しいプロジェクトを作成することが示されます。これは、Terraform がアドレスgoogle_project.defaultのプロジェクトが新しいアドレスgoogle_project.default["prod"]に移動されたことを認識していないためです。- この問題を解決するには、
terraform state mvコマンドを実行します。terraform state mv "google_project.default" "google_project.default[\"prod\"]"
 - 同様に、他のすべてのリソース ブロックを修正するには、
main.tfファイル内のgoogle_firebase_project、google_firebase_web_app、その他のすべてのリソース ブロックに対してterraform state mvを実行します。 - ここで 
terraform planを再度実行すると、この Codelab の前半で作成したプロジェクトが Terraform によって削除されることはありません。 
 - 現時点では、
 terraform applyを実行して、新しい「ステージング」Firebase プロジェクトとそのすべてのリソースをプロビジョニングし、そのサービスを有効にします。- Firebase コンソールで、すべてが想定どおりプロビジョニングされ、有効になっていることを確認します。
 
12. ボーナス ステップ: ステージング アプリと本番環境アプリをデプロイする
- アプリのコードベースで、
firebase-config.jsを変更して、代わりにステージング プロジェクトの Firebase 構成を使用するようにします。
Firebase 構成を取得してアプリに追加する方法については、この Codelab の前の手順「Firebase 構成をアプリに追加する」をご覧ください。 webディレクトリのルートで、次のコマンドを実行して、アプリをステージング Firebase プロジェクトにデプロイします。firebase deploy --only hosting --project=<STAGING_PROJECT_ID>
firebase deployの出力に表示された URL を使用して、ブラウザでステージング アプリを開きます。ログイン、メッセージの送信、画像のアップロードを試してください。
アプリを Firebase プロジェクトにデプロイすると、エミュレートされたリソースではなく、実際の Firebase リソースが使用されます。ステージング アプリを操作すると、Firebase コンソールのステージング プロジェクトにデータと画像が表示されます。- ステージングでアプリをテストしたら、
firebase-config.jsを変更して、本番環境プロジェクトの Firebase 構成(この Codelab で最初に作成したプロジェクト)を使用するように戻します。 webディレクトリのルートで、次のコマンドを実行して、アプリを本番環境の Firebase プロジェクトにデプロイします。firebase deploy --only hosting --project=<PRODUCTION_PROJECT_ID>
firebase deployの出力に表示された URL を使用して、ブラウザで本番環境アプリを開きます。ログイン、メッセージの送信、画像のアップロードを試してください。
Firebase コンソールの本番環境プロジェクトにデータと画像が表示されるはずです。- この Codelab の 2 つのアプリの操作が完了したら、Firebase によるアプリの配信を停止できます。プロジェクトごとに次のコマンドを実行します。
firebase hosting:disable --project=<STAGING_PROJECT_ID>
firebase hosting:disable --project=<PRODUCTION_PROJECT_ID>
 
13. 完了
Terraform を使用してリアルタイム チャット ウェブ アプリケーションを構成しました。また、ステージング環境と本番環境用に個別の Firebase プロジェクトを作成することで、開発環境のベスト プラクティスにも従っています。
学習した内容
- Terraform CLI を使用してクラウド リソースを管理する
 - Terraform を使用して Firebase プロダクト(Authentication、Firestore、Cloud Storage、セキュリティ ルール)を構成する
 - Firebase Local Emulator Suite を使用してウェブアプリをローカルで実行してテストする
 - ウェブアプリへの Firebase のインポート
 - Terraform を使用して複数の環境間で構成を複製する
 
Firebase と Terraform の詳細については、ドキュメントをご覧ください。Terraform をサポートするすべての Firebase プロダクトのリスト、一般的なユースケースの Terraform 構成の例、トラブルシューティングとよくある質問を確認できます。