terraformを使って環境別にfirebase構築を行う
はじめに
Google I/O 2024 が開催され、Firebaseも予想以上に多くのアップデートがあり、大変盛り上がりました。
PostgresSQLとgraphqlを利用したサーバ環境を簡単に構築できるDataConnectは今後に期待ですね...!!
さて、今回は、それとは全く関係なく、firebaseのterraformによる構築について、自己整理も兼ねて記事としてみます。
terraformについてまだまだ学習したてなので、ツッコミどころがあるかと思います。。。ぜひ指摘いただけたら幸いです。
Terraformとは?
一言で言うと、インフラの構成をソースコードとして管理できる機能です。
同じ構成を本番環境や検証環境など複数環境に用意したい場合とても有用です。
公式では以下のようにメリットが説明されています。
Terraformには、チームでの共用や再利用、バージョン管理がしやすく、自動化によってオペレーションコストを削減し、人的ミスが発生する可能性を減らせるというメリットがあります。
今回導入するFirebaseのサービス
以下のサービスをterraformで構築します
- firebase
- cloud functions (firebase functions)
- firestore
- storage
- authentication
## terraformの実装
設計
今回は以下のようなディレクトリで構成しました
- terraform
- main.tf # 全構成の設定 (今回はfirebase_project/mainの利用が殆ど)
- variables.tf # mainで利用する変数の定義
- env.tfvars # 実行時環境変数の定義
- firebase_project
- main.tf # firebase周りの設定
- variables.tf # firebase_project/main.tfで利用する変数の定義
(今回、一回のterraform実行で本番・検証・開発環境をdeployできるようにしました)
(terraformについてまだ学習したてのため、もしアンチパターンとなってたら指摘いただけると幸いです)
providerの設定
# 利用プロバイダのセットアップ
terraform {
required_providers {
google-beta = {
source = "hashicorp/google-beta"
version = "~> 4.0"
}
}
}
provider "google-beta" {
alias = "default"
user_project_override = true
region = var.region
}
# クォータチェック(上限割り当て)を回避したプロバイダの設定
provider "google-beta" {
alias = "no_user_project_override"
user_project_override = false
}
# ...以降に環境ごとの設定のため、moduleを定義する
google serviceの設定
環境ごとに利用するresourceなどを定義していきます。
# GCPプロジェクトの作成
resource "google_project" "default" {
provider = google-beta.no_user_project_override
name = var.project_id # 簡単のため、プロジェクト名はprojectIDと同じにしています。
project_id = var.project_id
billing_account = var.billing_account
labels = {
"firebase" = "enabled"
}
}
# 各APIの有効化
resource "google_project_service" "default" {
provider = google-beta.no_user_project_override
project = google_project.default.project_id
for_each = toset([
"serviceusage.googleapis.com",
"cloudbuild.googleapis.com",
"cloudbilling.googleapis.com",
"cloudresourcemanager.googleapis.com",
"firebase.googleapis.com",
"identitytoolkit.googleapis.com",
"firestore.googleapis.com",
"firebaserules.googleapis.com",
"firebasestorage.googleapis.com",
"storage.googleapis.com",
"cloudfunctions.googleapis.com",
"firebasehosting.googleapis.com",
])
service = each.key
disable_on_destroy = false
}
# Firebaseの設定
resource "google_firebase_project" "default" {
provider = google-beta
project = google_project.default.project_id
depends_on = [
google_project_service.default
]
}
# Locationの設定 (hashicorp/google-beta@5.0以上のversionは別の定義)
# 参考: https://zenn.dev/tkow/scraps/8bc5d0ab4d7b8b
resource "google_firebase_project_location" "default" {
provider = google-beta
project = google_project.default.project_id
location_id = var.region
}
# Firestoreの有効化
resource "google_firestore_database" "default" {
provider = google-beta.no_user_project_override
project = google_project.default.project_id
name = "(default)"
location_id = var.region
type = "FIRESTORE_NATIVE"
concurrency_mode = "OPTIMISTIC"
app_engine_integration_mode = "DISABLED"
depends_on = [
google_firebase_project.default,
]
}
# Firebase CloudStorageの有効化
## AppEngineの有効化が必要
resource "google_app_engine_application" "default" {
provider = google-beta
project = google_project.default.project_id
location_id = var.region
# Cloud Firestore DB を作成する場合は、その作成を待つ必要がある
depends_on = [
google_firestore_database.default,
]
}
## Storage バケット
resource "google_firebase_storage_bucket" "default" {
provider = google-beta
project = google_project.default.project_id
bucket_id = google_app_engine_application.default.default_bucket
}
# FirebaseAuthenticationの有効化
resource "google_identity_platform_config" "default" {
provider = google-beta
project = google_project.default.project_id
depends_on = [
google_project_service.default,
]
}
resource "google_identity_platform_project_default_config" "default" {
provider = google-beta
project = google_project.default.project_id
sign_in {
allow_duplicate_emails = false
}
depends_on = [
google_identity_platform_config.default
]
}
# Firebase Web Appの有効化
resource "google_firebase_web_app" "default" {
provider = google-beta
project = google_project.default.project_id
display_name = "Web App"
deletion_policy = "DELETE"
depends_on = [
google_firebase_project.default,
]
}
data "google_firebase_web_app_config" "basic" {
provider = google-beta
project = google_project.default.project_id
web_app_id = google_firebase_web_app.default.app_id
}
google_projectで利用する変数の定義
variable "project_id" {
description = "The project ID"
type = string
nullable = false
}
variable "billing_account" {
description = "Billing account ID for the project"
type = string
nullable = false
}
variable "region" {
type = string
nullable = false
}
環境ごとにmoduleとしてgoogle serviceを設定
# ...providerの設定コード
module "prod" {
source = "./firebase_project"
providers = {
google-beta = google-beta.default
google-beta.no_user_project_override = google-beta.no_user_project_override
}
project_id = var.prod_project_id
billing_account = var.billing_account
region = var.region
}
module "stg" {
source = "./firebase_project"
providers = {
google-beta = google-beta.default
google-beta.no_user_project_override = google-beta.no_user_project_override
}
project_id = var.stg_project_id
billing_account = var.billing_account
region = var.region
}
module "dev" {
source = "./firebase_project"
providers = {
google-beta = google-beta.default
google-beta.no_user_project_override = google-beta.no_user_project_override
}
project_id = var.dev_project_id
billing_account = var.billing_account
region = var.region
}
上記で用いる変数の定義
# terraform/google_project/variables.tfと重複がある。重複を無くしたいが、やり方が不明...
variable "prod_project_id" {
description = "The project ID for prod"
type = string
nullable = false
}
variable "stg_project_id" {
description = "The project ID for stg"
type = string
nullable = false
}
variable "dev_project_id" {
description = "The project ID for dev"
type = string
nullable = false
}
variable "billing_account" {
description = "Billing account ID for the project"
type = string
nullable = false
}
variable "region" {
type = string
nullable = false
}
実際の変数ファイルの用意
prod_project_id = "prod_project_id"
stg_project_id = "stg_project_id"
dev_project_id = "dev_project_id"
region = "asia-northeast1"
billing_account = "billing-account-id"
以上で、各環境ごとに同一の構成でfirebaseを構築する用意ができました.
terraformの実行
初期化
terraform init
plan/deploy
terraform plan -var-file=env.tfvars # 実行計画の確認
terraform apply -var-file=env.tfvars # 実行
以上で、firebase projectが環境ごろに別プロジェクトとして用意されます。 🙌🙌🙌🙌
(APIが有効になっていない、などのエラーが出た場合は、APIの有効化に時間がかかっているためです。数分間時間をおいて再度applyしてみてください)
おわりに
今回はterraformを用いて、firebaseでよく使うサービス周りの構築を行いました。
今回記載したサービス以外も多くのものがterraformで構築可能ですので、ぜひ試してみてください。
はじめに述べたように、terraformに関してまだ学習した手であり、つっこみどころがあるかと思います。
ぜひ優しく指摘いただけると幸いです...!
複数環境を用意したい場合にGUIでちょこちょこ行うのは大変ですし、今後のためにも、BestPracticeなど学んでいきたいと思います。