1. はじめに
目標
Terraform を使用すると、Firebase プロジェクトを設定および管理できます。インフラストラクチャや Firebase プロダクトのプログラムによる構成も可能です。
この Codelab では、まず Terraform 構成ファイルをビルドして新しい Firebase プロジェクトを作成する方法について説明します。次に、そのプロジェクトで使用するアプリと Firebase プロダクトを構成する方法について説明します。また、変更のプレビューや実装など、Terraform コマンドラインの基本についても説明します。
Terraform を使用して Firebase プロジェクトとプロダクトを設定して管理する方法を学びたい場合は、この Codelab がおすすめです。
学習内容
- Terraform 構成ファイルの作成方法(
*.tf
) - Terraform CLI コマンドを使用してインフラストラクチャを管理する方法
- 構成を変更してリソースとサービスを更新する方法
- 実際のウェブアプリ(フレンドリー チャット)に構成を適用する方法
- さまざまな環境(本番環境、ステージング環境など)で並列(同期)構成を定義する方法
必要なもの
- ターミナル / コンソール
- 任意の 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)を有効にする必要があります。
通常、この API の有効化は、Firebase コンソールを使用して Firebase プロジェクトを作成するときにバックグラウンドで処理されますが、この有効化を行うには 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,
]
}
上記のリソース ブロックには、depends_on
句があります。これは、基盤となる API が有効になるまで待機するよう Terraform に指示します。この句がないと、Terraform は依存関係を認識しないため、リソースを並行してプロビジョニングするときにエラーが発生する可能性があります。
構成を適用する
- 新しいリソースをプロビジョニングし、構成ファイルで指定された API を有効にするには、
main.tf
ファイル(web
にする必要があります)と同じディレクトリのルートから次のコマンドを実行します。terraform apply
- ターミナルに、実行されるアクションのプランが表示されます。
すべてが想定どおりであれば、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
にする必要がある)と同じディレクトリのルートから次のコマンドを実行します。terraform apply
このコマンドでは、新しい Google Cloud プロジェクトは再作成されません。Terraform は、指定されたプロジェクト ID のプロジェクトがすでに存在することを確認し、プロジェクトの現在の状態を.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 を設定する。
- このオプションを使用する場合、GCIP ではプロジェクトに Blaze お支払いプランが適用されている必要があるため、新しいプロジェクトを Cloud 請求先アカウントに関連付ける必要があります。
オプション 1: Firebase コンソールを使用して認証を設定する
Firebase コンソールを使用して Firebase Authentication を設定するには、プロジェクトに Blaze 料金プランを適用している必要はありません。
Firebase Authentication を設定して Google でログインする方法は次のとおりです。
- Firebase コンソールで、左側のパネルにある [ビルド] セクションを見つけます。
- [Authentication]、[開始] の順にクリックし、[ログイン方法] タブをクリックします(または、こちらをクリックして直接移動します)。
- [新しいプロバイダを追加] をクリックし、[その他のプロバイダ] セクションで [Google] を選択します。
- [有効にする] をオンに切り替えます。
- アプリの一般公開名を
FriendlyChat
などに設定します(グローバルに一意である必要はありません)。 - プルダウン メニューから [プロジェクト サポートのメールアドレス] を選択し、[保存] をクリックします。
- 有効なログイン プロバイダとして Google が表示されます。
オプション 2: Google Cloud Identity Platform(GCIP)API を使用して Terraform で認証を設定する
Terraform を使用して Firebase Authentication を設定するには、GCIP API を使用する必要があります。つまり、プロジェクトに Blaze 料金プランを適用している必要があります。Firebase プロジェクトを Blaze プランを使用するようにアップグレードするには、プロジェクトに Cloud 請求先アカウントを関連付けます。
Terraform で課金を有効にする
- Cloud 請求先アカウントをまだお持ちでない場合は、まず Google Cloud コンソールで新しいアカウントを作成します。その際、その請求先アカウント ID をメモします。請求先アカウント ID は、プロジェクトに関連付けられた [請求先アカウント ID] の [お支払い] ページで確認できます。
- Terraform でプロジェクトで課金を有効にするには、
main.tf
ファイルの既存のgoogle_project
リソースにbilling_account
属性を追加します。
main.tf... # Create a new Google Cloud project. resource "google_project" "default" { provider = google-beta.no_user_project_override name = "<PROJECT_NAME_OF_YOUR_PROJECT>" project_id = "<PROJECT_ID_OF_YOUR_PROJECT>" billing_account = "<YOUR_BILLING_ACCOUNT_ID>" # Add this line with your Cloud Billing account ID # Required for the project to display in any list of Firebase projects. labels = { "firebase" = "enabled" } } ...
Firebase Authentication を有効にし、Terraform を介して 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 同意画面ページを開き、作成したプロジェクトを選択します。
- [ユーザーの種類] を [外部] に設定し、[作成] をクリックします。
- 次の画面で以下の手順に沿って操作し、[保存して次へ] をクリックします。
- アプリの一般公開される [App name] を
FriendlyChat
などに設定します(グローバルに一意である必要はありません)。 - プルダウン メニューから [ユーザー サポートのメールアドレス] を選択します。
- [デベロッパーの連絡先情報] にメールアドレスを入力します。
- アプリの一般公開される [App name] を
- 次の画面で、次の操作を行います。
- [スコープ] ページでデフォルト値をそのまま使用して、[保存して次へ] をクリックします。
- [テストユーザー] ページでデフォルト値をそのままにして、[保存して次へ] をクリックします。
- 概要を確認し、[ダッシュボードに戻る] をクリックします。
- [認証情報] ページで 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 を追加] をクリックして「
- [保存] をクリックします。
- 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 コンソールの左側のパネルで、[Build] セクションを見つけます。
- [認証] をクリックし、[ログイン方法] タブをクリックします(または、ここをクリックして [ログイン方法] タブに直接移動します)。
- 有効なログイン プロバイダとして Google が表示されます。
7. Firestore データベースとそのセキュリティ ルールを設定する
この Codelab のウェブアプリでは、エンドユーザー間のメッセージを Firestore データベースに保存します。
- 必要な API を有効にしてデータベース インスタンスをプロビジョニングするには、次の resource ブロックを
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 のサンプルコードでは、firestore.rules
ファイルに安全な Firestore ルールのセットが用意されています。このファイルは、web
ディレクトリのルートにあります。 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] セクションに移動し、[ルール] タブをクリックします。
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 コンソールで、左側のパネルにある [ビルド] セクションを見つけます。
- [ストレージ] セクションに移動し、[ルール] タブをクリックします。
9. アプリをローカルで実行する
これで、ウェブアプリを初めて実行する準備ができました。Firebase Hosting エミュレータを使用して、アプリをローカルで提供します。
- 新しいターミナル ウィンドウを開き、
web
ディレクトリから次の Firebase CLI コマンドを実行してエミュレータを起動します。firebase emulators:start --project=<PROJECT_ID>
- ブラウザで、CLI から返されたローカル URL(通常は
http://localhost:5000
)でウェブアプリを開きます。
フレンドリー チャット アプリの 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 スニペット] ペインで [構成] を選択し、構成スニペットをコピーします。
- 次のように構成をアプリの
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 を介して構成を取得し、コードベースに追加する
また、CLI で Terraform を介して Firebase 構成を出力値として取得することもできます。
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 が実行するアクションを確認します。
出力には、この Codelab の前半で作成したプロジェクトが削除され、2 つの新しいプロジェクトが作成されることが示されます。これは、アドレスgoogle_project.default
のプロジェクトが新しいアドレスgoogle_project.default["prod"]
に移動したことを Terraform が認識していないためです。- この問題を解決するには、
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
を実行して、新しい「staging」をプロビジョニングします。Firebase プロジェクトとそのすべてのリソースを作成し、そのサービスを有効にします。- 前と同様に Firebase コンソールで確認し、すべてが想定どおりにプロビジョニングされ、有効になっていることを確認します。
12. ボーナス ステップ: ステージング アプリと本番環境アプリをデプロイする
- アプリのコードベースで、ステージング プロジェクトの Firebase 構成を使用するように
firebase-config.js
を変更します。
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 構成のサンプル、役立つトラブルシューティングとよくある質問をご覧いただけます。