この Codelab について
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 プロジェクトは実際には Firebase サービスが有効になっている Google Cloud プロジェクトであることを覚えておくことが重要です。
基盤となる 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
である必要があります)のルートから次のコマンドを実行します。 このコマンドで新しい 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 を設定します。
- このオプションを使用する場合、GCIP ではプロジェクトに Blaze お支払いプランが適用されている必要があるため、新しいプロジェクトを Cloud 請求先アカウントに関連付ける必要があります。
オプション 1: Firebase コンソールを使用して Authentication を設定する
Firebase コンソールを使用して Firebase Authentication を設定するには、プロジェクトが Blaze 料金プランに登録されている必要はありません。
Firebase Authentication を設定して Google でログインする手順は次のとおりです。
- Firebase コンソールの左側のパネルで、[Build] セクションを見つけます。
- [認証]、[始める]、[ログイン方法] タブの順にクリックします(または、ここをクリックして [ログイン方法] タブに直接移動します)。
- [新しいプロバイダを追加] をクリックし、[その他のプロバイダ] セクションで [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"
}
}
...
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 を追加] をクリックし、
- [保存] をクリックします。
- 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 を有効にしてデータベース インスタンスをプロビジョニングするには、
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 コンソールの左側のパネルで、[Build] セクションを見つけます。
- [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 コンソールの左側のパネルで、[Build] セクションを見つけます。
- [Storage] セクションに移動し、[Rules] タブをクリックします。
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 で構成を取得してコードベースに追加する
また、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 が実行するアクションを確認します。
出力には、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、Security Rules)を構成する
- Firebase Local Emulator Suite を使用してウェブアプリをローカルで実行してテストする
- Firebase をウェブアプリにインポートする
- Terraform を使用して複数の環境に構成を複製する
Firebase と Terraform の詳細については、ドキュメントをご覧ください。Terraform をサポートするすべての Firebase プロダクトのリスト、一般的なユースケースの Terraform 構成の例、役立つトラブルシューティングとよくある質問を確認できます。