Terraform で Firebase プロジェクトを構築してみる
こんにちは、SRE ディビジョンの小堀内です。
今回も 前回に引き続き Google I/O 2023 で発表された Firebase の新機能 の中から紹介していきます。
本記事のテーマ
対象読者
- Terraform に興味はあるが触ったことがない方
- Terraform を通して IaC を学んでみたい方
- コンソール操作によって Firebase プロジェクトを構築している方
Terraform とは
Terraform とは、HashiCorp 社が開発した IaC(Infrastructure as Code)ツールの一種です。
異なるクラウドプロバイダーまたはオンプレミス環境上のリソースを統一的な形式で記述し、管理できるように設計されています。
ちなみに IaC(Infrastructure as Code)とは、インフラストラクチャをコードとして管理する手法のことです。
IaC を使用すると、コンソール上から手動でネットワーク、仮想マシン、負荷分散などのインフラリソースを設定する代わりに、コードでこれらを定義し、自動的に適用することが可能となります。
IaC 化により、環境構築が迅速かつ一貫したものになり、エラーや非効率な手順を大幅に削減することができます。
Terraform を使用することで、環境のプロビジョニングと構成をコードで記述し、自動的にデプロイすることができます。
基本的な Terraform コマンド
まず「これだけは押さえておきたい」という基本的な Terraform コマンドを紹介します。
コマンド | 役割 |
---|---|
terraform init |
- Terraform 初期化時に使用する - 作業ディレクトリの初期化が行われる |
terraform fmt |
- Terraform コードのフォーマットを整える - コードの一貫性が保たれる |
terraform plan |
- 追加、更新、削除される予定のリソースを表示する - 実際の環境に適用する前に変更内容をレビューすることができる |
terraform apply |
- terraform plan で確認した変更内容を実行し、インフラストラクチャに変更を適用する |
コマンドの実行結果に関しては、Firebase プロジェクトを構築する際に確認していきましょう。
Terraform を用いて Firebase プロジェクトを構築
それでは実際に、Terraform を用いて Firebase プロジェクトを構築していきたいと思います。
構成
イメージ
次の構成図をもとに Terraform を使用して構築を行います。
ディレクトリ構成
次に示すディレクトリ構成をもとにして以降の説明を行います。
.
├── README.md
├── locals.tf
├── main.tf
├── modules
│ ├── authentication
│ │ ├── main.tf
│ │ └── variables.tf
│ ├── firestore
│ │ ├── main.tf
│ │ ├── output.tf
│ │ └── variables.tf
│ └── storage
│ ├── main.tf
│ └── variables.tf
├── provider.tf
└── variables.tf
※ Firebase プロジェクト構築時の Terraform ディレクトリ構成の一例となります。
構築
1. 変数定義
まず、外部(ターミナル、Cloud Build など)から値を渡してもらい Terraform コードを実行するための変数を定義します。
variable "billing_account" {
description = "Firebase プロジェクトに紐づける Google Cloud Billing Account の ID"
type = string
}
variable "project_name" {
description = "Firebase プロジェクトの名前"
type = string
}
variable "project_id" {
description = "Firebase プロジェクトの ID(世界で一意となるコード)"
type = string
}
variable "android_package_name" {
description = "パッケージ名(Android)"
type = string
}
variable "ios_bundle_id" {
description = "バンドルID(iOS)"
type = string
}
2. 使用するプロバイダーの用意
次に required_providers
ブロックを使用して 4.x バージョン
の google-beta
プロバイダーを使用することを宣言します。
terraform {
required_providers {
google-beta = {
source = "hashicorp/google-beta"
version = "~> 4.0"
}
}
}
provider "google-beta" {
# プロジェクトに関連するコストを追跡する
user_project_override = true
billing_project = var.project_id
}
provider "google-beta" {
alias = "no_user_project_override"
user_project_override = false
}
3. Firebase プロジェクト用の Google Cloud プロジェクト構築
Firebase プロジェクトは Google Cloud プロジェクトの一部として構築されます。
そのため、Firebase プロジェクト構築前に Google Cloud プロジェクトを構築する必要があります。
# Firebase プロジェクト用の Google Cloud プロジェクトを立ち上げる
resource "google_project" "default" {
provider = google-beta
# project_id は一意である必要がある
project_id = var.project_id
name = var.project_name
billing_account = var.billing_account
# Firebase のプロジェクトとして表示するために必要
labels = {
"firebase" = "enabled"
}
}
4. 各種 API 有効化
Google Cloud プロジェクト内のいくつかの API を有効化して Firebase プロジェクト内のプロダクト(Cloud Firestore, Cloud Storage, Firebase Authentication 等)を使用可能な状態にします。
# Firebase 内のプロダクトを利用可能にするために Google Cloud 内の API を有効化する
resource "google_project_service" "default" {
provider = google-beta.no_user_project_override
project = google_project.default.project_id
for_each = toset([
"firestore.googleapis.com",
"cloudbilling.googleapis.com",
"cloudresourcemanager.googleapis.com",
"serviceusage.googleapis.com",
"identitytoolkit.googleapis.com",
"firebase.googleapis.com",
"firebaserules.googleapis.com",
"firebasestorage.googleapis.com",
"storage.googleapis.com",
# 後々 Cloud Build 経由で Terraform コマンドを実行するようにしたい場合はこちらも有効化しておくとよい
"cloudbuild.googleapis.com",
])
service = each.key
disable_on_destroy = false
}
5. Firebase プロジェクトの立ち上げ
これで Google Cloud プロジェクト側での事前準備が整いました。
次に Firebase プロジェクトを構築するコードを書いていきます。
# Firebase のプロジェクトを立ち上げる
resource "google_firebase_project" "default" {
provider = google-beta
project = google_project.default.project_id
# Google Cloud プロジェクトの各種 API が有効化されるのを待ってから本リソースを実行する
depends_on = [
google_project_service.default,
]
}
6. Firebase プロジェクトのリージョン設定
東京リージョンに配置するように指定します。
もし、別リージョンに Firebase プロジェクトを配置したい場合は、使用可能なリージョンとゾーン に記載のリージョン名を使用してください。
# 各種リソース共通の定数群
locals {
# リージョン名:東京
region = "asia-northeast1"
}
# Firebase プロジェクトを東京リージョンに配置する
resource "google_firebase_project_location" "default" {
provider = google-beta
project = google_firebase_project.default.project
location_id = local.region
}
7. アプリ設定
Web, Android, iOS のアプリ設定をそれぞれ行います。
設定後のイメージ
Web
# Firebase Web App
resource "google_firebase_web_app" "default" {
provider = google-beta
project = var.project_id
display_name = "My Web App"
depends_on = [
google_firebase_project.default,
]
}
Android
# Firebase Android App
resource "google_firebase_android_app" "default" {
provider = google-beta
project = var.project_id
display_name = "My Android App"
package_name = var.android_package_name
depends_on = [
google_firebase_project.default,
]
}
iOS
# Firebase iOS App
resource "google_firebase_apple_app" "default" {
provider = google-beta
project = var.project_id
display_name = "My iOS app"
bundle_id = var.ios_bundle_id
depends_on = [
google_firebase_project.default,
]
}
8. Firebase の各種プロダクトを有効化
ここでは Cloud Firestore, Cloud Storage, Firebase Authentication の有効化をしてみます。
Cloud Firestore
ここでは 公式ドキュメント および Terraform サンプル の例を参考に somenewcollection
というコレクションを作成して、さらにその中に sub_docs
というサブコレクションを作成しています。
# Firebase Firestore
resource "google_firestore_database" "default" {
project = var.project_id
name = "(default)"
location_id = var.location
type = "FIRESTORE_NATIVE"
concurrency_mode = "OPTIMISTIC"
app_engine_integration_mode = "DISABLED"
depends_on = [
var.services_ready
]
}
# Firebase Cloud Firestore コレクション/ドキュメント定義
resource "google_firestore_document" "mydoc" {
project = var.project_id
collection = "somenewcollection"
document_id = "my-doc-id"
fields = "{\"something\":{\"mapValue\":{\"fields\":{\"akey\":{\"stringValue\":\"avalue\"}}}}}"
depends_on = [google_firestore_database.default]
}
resource "google_firestore_document" "sub_document" {
project = var.project_id
collection = "${google_firestore_document.mydoc.path}/subdocs"
document_id = "bitcoinkey"
fields = "{\"something\":{\"mapValue\":{\"fields\":{\"ayo\":{\"stringValue\":\"val2\"}}}}}"
depends_on = [google_firestore_database.default]
}
Cloud Storage
# Firebase Cloud Storage
# Firebase の Cloud Storage を使用するには 先に App Engine の有効化が必要
resource "google_app_engine_application" "default" {
project = var.project_id
location_id = var.location
# Cloud Firestore DB を作成する場合は、その作成を待つ必要がある
depends_on = [
var.services_ready
]
}
# Storage バケット
resource "google_firebase_storage_bucket" "default" {
provider = google-beta
project = var.project_id
bucket_id = google_app_engine_application.default.default_bucket
}
Firebase Authentication
ここでは Terraform ドキュメント を参考に Firebase Authentication の匿名認証、メール認証、電話番号認証(テスト用の電話番号の登録を含む)を有効化してみます。
# Firebase Authentication
resource "google_identity_platform_config" "default" {
provider = google-beta
project = var.project_id
depends_on = [
var.services_ready,
]
}
resource "google_identity_platform_project_default_config" "default" {
provider = google-beta
project = var.project_id
sign_in {
allow_duplicate_emails = true
anonymous {
enabled = true
}
email {
enabled = true
password_required = false
}
phone_number {
enabled = true
test_phone_numbers = {
"+11231231234" = "000000"
}
}
}
depends_on = [google_identity_platform_config.default]
}
9. Terraform コマンド実行
ここまでで Firebase プロジェクトを管理するためのコードが作成できたので、次は実際の環境に対して適用していきます。
terraform init
まずは terraform init
コマンドを実行して作業ディレクトリを初期化します。
実行例は下記のようになります。
terraform plan
ディレクトリ初期化が完了したら terraform plan
コマンドを実行して、実際の環境に適用されるリソースを確認していきます。
下記の例では、実際の環境に対してリソースが 22 個追加されることを示しています。
terraform apply
上記で変更が加えられるリソースが確認できたら terraform apply
コマンドを実行して、コードの状態を実際の環境に適用します。
「これらのアクションを実行しますか?」と質問されるので yes
を入力して承認することで適用が行われます。
terraform apply 後の確認
上記 terraform apply
コマンドの実行によりコードの状態が実際の環境に適用されました。
適用されたことを Firebase プロジェクトのコンソール上からも確認してみましょう。
Firebase プロジェクト
Firebase プロジェクトのリージョン
Firebase アプリ
Firebase Cloud Firestore
Firebase Cloud Storage
Firebase Authentication
サンプルコード
まとめ
個人的に興味のある Firebase で Terraform がサポートされた
+
最近アサインされた案件で Terraform を使用することになった
というとても良いタイミングで Terraform を学習することができたと感じています。
Terraform の基本的な使い方を理解することができたので案件内ではこの学習を生かしていきます。
今後 Terraform をはじめとして IaC についてさらに深く学習して要件に沿ったインフラ設計をできるよう努力します。
参考
Discussion