0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Google CloudでTerraformを使って、サーバレスアプリを作ってみた(メモ)

Posted at

Google Cloud×Terraformで最小サーバーレス・チャットを作った

TL;DR この記事は普段はアプリ側メインのエンジニアが「Terraform」を使用してみて、失敗したブブなどをメモ書き程度に残すものになります。
生成AIを使って作成している部分もあるので、同じように作成された場合にも同様のつまづきがあるかもしれません...


何を作ったか

構成イメージ

  • フロント: Cloud Storage 静的ホスティング(index.html)
  • API: Cloud Run Functions(Python, GET/POST)
  • DB: Firestore(今回は (default) を避けて 名前付きDB: chat
  • CORS: 関数側で許可。Storage→Functions 直fetch。

image.png

資源一覧

project/
├─ main.tf              # 各リソースの作成を行うメインの処理
├─ variables.tf         # プロジェクトIDやregionなどの変数用
├─ outputs.tf           # 作成後のエンドポイントなどの処理後の出力フォーマット
├─ files/
│  └─ index.html.tmpl   # 静的ホストするhtml
└─ functions/
   ├─ main.py           # Firestoreへのget/post処理のPythonコード
   └─ requirements.txt  # 使用するライブラリの定義

(ちなみに)今回のデプロイ手順

1. Google Cloud Consoleにアクセスする

2. Cloud Shellを起動する

3. 資材を上げる(terraformフォルダ一式)

4. terraformの初期化を行う

terraform init

5. コードの検証

terraform validate

6. リソースの展開

terraform apply -auto-approve \
  -var="project=$(gcloud config get-value project)" \
  -var="region=asia-northeast1" \
  -var="firestore_location=asia-northeast1"

7. console上に出力されるURLをブラウザでアクセス

※お片付け

terraform destroy -auto-approve -var="project=$(gcloud config get-value project)"

静的ホストのfrontend_url を開ければ完成。
動かない?…ログへ直行です。


躓きポイント

1. Firestore ドキュメント作成で fields 必須 / fields_json 使えない

  • 事象: The argument "fields" is requiredfields_json not expected

  • 原因: Google provider v7 系の仕様。Firestore型ラッパで JSON 文字列を渡す必要あり。

  • 解決策:

    fields = jsonencode({
      username   = { stringValue = "System" }
      text       = { stringValue = "ようこそ!" }
      created_at = { integerValue = "0" }
    })
    

2. ${} によってバグる

  • 事象: Invalid character; Single quotes are not valid… などテンプレ展開時エラー。
  • 原因: Terraform でも ${...} を使用しており、JS テンプレート中の ${...} をTerraformの構文だと解釈。
  • 解決策: Terraform に解釈させたくない ${$${ にエスケープ。"${API_URL}" だけはそのまま。

3. Firestore API が未有効で 403 SERVICE_DISABLED

  • 事象: Firestoreにデフォルトデータ投入時に403 SERVICE_DISABLEDが発生。
  • 原因: API 有効化直後で伝播待ちが足りない。
  • 解決策: google_project_service で有効化 → time_sleep で 30–60s 待ってから DB 作成に depends_on

4. Firestoreを作成で 409 already exists

  • 事象: terraform destroy したのに Firestore が消えない
  • 原因: Firestoreに関しては、既定は ABANDON(破棄しない)。さらに Delete Protection が有効なことも。
  • 解決策: DB リソースに以下を追加する
    delete_protection_state = "DELETE_PROTECTION_DISABLED"
    deletion_policy = "DELETE"
    
    ConsoleでポチポチしたDBは gcloud firestore databases delete も視野に。

5. Cloud Run Functions起動失敗:Container Healthcheck failed

  • 事象: PORT=8080 で待受できず Ready にならない。
  • 原因: 単純にPython上のエラー....。
  • 解決策: ローカルできちんと試さないと...。

Terraform の“性格”を掴む(運用Tips)

  • Terraform は常に差分実行planapply。差分が無ければ何もしません。

  • State が真実:State に無い既存リソースは「無い扱い」。衝突しそうなら import 一択。

    terraform import 'google_firestore_database.named' "projects/$PROJECT/databases/chat"
    
  • 部分適用は最終手段-target=... は便利だけど常用は非推奨。緊急のときだけ。

  • 状態だけ同期:実体に合わせたいだけなら -refresh-only

    terraform plan -refresh-only && terraform apply -refresh-only
    
  • 依存は明示&バージョン固定required_providersrequirements.txt をナメない。

  • 時間は偉大:API有効化直後は世界がまだ知らない。time_sleep で数十秒の平和を。

  • テンプレと $ の三角関係templatefile() と JS の `...${}...`$${} で平和に暮らす。

一言で言うと「神は State に宿る」。Console 先輩を尊重するなら、まず import しましょう。


原因を特定するログ調査

# Cloud Run Functionsの最新リビジョン名
REV=$(gcloud run services describe chat-api --region=asia-northeast1 \
      --format='value(status.latestCreatedRevisionName)')

# その起動ログ(最重要)
gcloud logging read \
  "resource.type=cloud_run_revision AND resource.labels.revision_name=$REV" \
  --limit=200 --order=desc --format='table(timestamp,severity,textPayload)'

# 関数ログ(エラー要約)
gcloud functions logs read chat-api --gen2 --region=asia-northeast1 --limit=200

# Cloud Build(依存が本当に入ったか)
gcloud builds list --limit=5
# ID が出たら
#gcloud builds log --stream --id <BUILD_ID>

読むポイント:

  • ImportError/ModuleNotFoundError → requirements を直す
  • TypeError: ... database → Firestore SDK を上げる
  • Failed to find attribute 'chat'entry_point と関数名を合わせる
  • 待受開始メッセージが無い → 起動前に落ちてる(遅延初期化で回避)

おわりに

クラウド×サーバーレス×IaCの現場は動くまでが大変。将来同じ轍を踏む方の参考になれば嬉しいです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?