GCPでTerraformを使った自動デプロイ実装とトラブルシューティング
今回のGCP環境でのTerraform自動デプロイ実装において、いくつかのトラブルが発生しました。これらの問題と解決策をまとめることで、同様の実装を行う方の参考になるでしょう。
1. 発生した問題と解決策
問題1: バケットへのアクセス権限不足
エラーメッセージ:
Error: Failed to get existing workspaces: querying Cloud Storage failed: googleapi: Error 403: [サービスアカウント名] does not have storage.objects.list access to the Google Cloud Storage bucket. Permission 'storage.objects.list' denied on resource (or it may not exist)., forbidden
原因:
サービスアカウントにTerraformの状態を保存するGCSバケットへのアクセス権限がありませんでした。
解決策:
# バケットに対してサービスアカウントに権限を付与
gsutil iam ch serviceAccount:[サービスアカウント名]:roles/storage.admin gs://[バケット名]
問題2: バケット作成権限の不足
エラーメッセージ:
Error: googleapi: Error 403: [サービスアカウント名] does not have storage.buckets.create access to the Google Cloud project. Permission 'storage.buckets.create' denied on resource (or it may not exist)., forbidden
原因:
サービスアカウントにプロジェクトレベルでバケットを作成する権限がありませんでした。
解決策:
# プロジェクトレベルでサービスアカウントにStorage Admin権限を付与
gcloud projects add-iam-policy-binding [プロジェクトID] --member=serviceAccount:[サービスアカウント名] --role=roles/storage.admin
# より広範な権限も付与
gcloud projects add-iam-policy-binding [プロジェクトID] --member=serviceAccount:[サービスアカウント名] --role=roles/editor
問題3: 存在しないサービスアカウントの参照
エラーメッセージ:
Error: Error applying IAM policy for storage bucket "b/[バケット名]": Error setting IAM policy for storage bucket "b/[バケット名]": googleapi: Error 400: Service account github-actions@your-project-id.iam.gserviceaccount.com does not exist., invalid
原因:
Terraformの設定ファイル内で、実際には存在しないサービスアカウントを参照していました。
解決策:
variables.tf
ファイルのservice_account_email
変数のデフォルト値を実際のサービスアカウントに修正しました。
variable "service_account_email" {
description = "アクセス権を付与するサービスアカウントのメールアドレス"
type = string
- default = "github-actions@your-project-id.iam.gserviceaccount.com"
+ default = "[実際のサービスアカウント名]"
}
2. GCPでTerraformを使った自動デプロイの実装手順
以下に、GCPでTerraformを使った自動デプロイを実装するための手順をまとめます。
2.1 前提条件
- GitHubアカウント
- GCPアカウントとプロジェクト
- 基本的なTerraformとGCPの知識
2.2 実装手順
1. GCPプロジェクトの準備
-
GCPコンソールでプロジェクトを作成または選択
# プロジェクトの確認 gcloud projects list # プロジェクトの選択 gcloud config set project [プロジェクトID]
-
必要なAPIを有効化
# Storage APIの有効化 gcloud services enable storage.googleapis.com # Resource Manager APIの有効化 gcloud services enable cloudresourcemanager.googleapis.com
2. サービスアカウントの作成と権限設定
-
サービスアカウントの作成
gcloud iam service-accounts create [サービスアカウント名] \ --display-name="[表示名]"
-
必要な権限の付与
# Storage管理者権限 gcloud projects add-iam-policy-binding [プロジェクトID] \ --member="serviceAccount:[サービスアカウント名]@[プロジェクトID].iam.gserviceaccount.com" \ --role="roles/storage.admin" # 編集者権限(より広範な権限) gcloud projects add-iam-policy-binding [プロジェクトID] \ --member="serviceAccount:[サービスアカウント名]@[プロジェクトID].iam.gserviceaccount.com" \ --role="roles/editor"
-
サービスアカウントキーの作成
gcloud iam service-accounts keys create key.json \ --iam-account=[サービスアカウント名]@[プロジェクトID].iam.gserviceaccount.com
3. Terraformの状態管理用バケットの作成
-
バケットの作成
gsutil mb -l [リージョン] gs://[バケット名]
-
バージョニングの有効化
gsutil versioning set on gs://[バケット名]
-
サービスアカウントにバケットへのアクセス権限を付与
gsutil iam ch serviceAccount:[サービスアカウント名]@[プロジェクトID].iam.gserviceaccount.com:roles/storage.admin gs://[バケット名]
4. Terraformの設定ファイルの作成
-
プロバイダー設定(
provider.tf
)provider "google" { project = var.gcp_project_id region = var.gcp_region }
-
バックエンド設定(
backend.tf
)terraform { backend "gcs" { bucket = "[バケット名]" prefix = "terraform/state" } }
-
変数定義(
variables.tf
)variable "gcp_project_id" { description = "GCPのプロジェクトID" type = string } variable "gcp_region" { description = "GCPのリージョン" type = string default = "asia-northeast1" } variable "service_account_email" { description = "アクセス権を付与するサービスアカウントのメールアドレス" type = string default = "[サービスアカウント名]@[プロジェクトID].iam.gserviceaccount.com" }
-
リソース定義(
main.tf
)resource "google_storage_bucket" "example" { name = "example-bucket-${random_string.random.result}" location = var.gcp_region versioning { enabled = true } } resource "random_string" "random" { length = 8 special = false lower = true upper = false }
5. GitHub Actionsの設定
-
GitHub Secretsの設定
-
GCP_CREDENTIALS
: サービスアカウントのJSONキー -
GCP_PROJECT_ID
: GCPプロジェクトID
-
-
ワークフローファイルの作成(
.github/workflows/terraform.yml
)name: Terraform GCP Deployment on: push: branches: [ main ] pull_request: branches: [ main ] workflow_dispatch: jobs: terraform: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 - name: Setup Terraform uses: hashicorp/setup-terraform@v2 with: terraform_version: 1.5.0 - name: Authenticate to Google Cloud uses: google-github-actions/auth@v1 with: credentials_json: ${{ secrets.GCP_CREDENTIALS }} - name: Set up Google Cloud SDK uses: google-github-actions/setup-gcloud@v1 - name: Terraform Init run: terraform init working-directory: ./gcp - name: Terraform Format run: terraform fmt -check working-directory: ./gcp - name: Terraform Validate run: terraform validate working-directory: ./gcp - name: Terraform Plan run: terraform plan -var="gcp_project_id=${{ secrets.GCP_PROJECT_ID }}" working-directory: ./gcp if: github.event_name == 'pull_request' - name: Terraform Apply run: terraform apply -auto-approve -var="gcp_project_id=${{ secrets.GCP_PROJECT_ID }}" working-directory: ./gcp if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
3. トラブルシューティングのポイント
3.1 権限関連の問題
-
バケットアクセス権限の確認
# バケットのIAMポリシーを確認 gsutil iam get gs://[バケット名]
-
サービスアカウントの権限確認
# サービスアカウントの権限を確認 gcloud projects get-iam-policy [プロジェクトID] \ --flatten="bindings[].members" \ --format="table(bindings.role)" \ --filter="bindings.members:serviceAccount:[サービスアカウント名]@[プロジェクトID].iam.gserviceaccount.com"
3.2 Terraform設定の問題
-
バックエンド設定の確認
- バケット名が正しいか
- リージョンが正しいか
- プレフィックスが適切か
-
変数のデフォルト値の確認
- プレースホルダーが実際の値に置き換えられているか
- 特にサービスアカウントのメールアドレスが正確か
3.3 GitHub Actions関連の問題
-
シークレットの確認
-
GCP_CREDENTIALS
が正しいJSONキーを含んでいるか -
GCP_PROJECT_ID
が正確なプロジェクトIDを含んでいるか
-
-
ワークフローの確認
- 作業ディレクトリが正しく設定されているか
- 必要な環境変数がすべて設定されているか
4. ベストプラクティス
-
最小権限の原則
- サービスアカウントには必要最小限の権限のみを付与する
- 本番環境では
roles/editor
のような広範な権限は避ける
-
状態ファイルの保護
- バケットのバージョニングを有効にする
- バケットへのアクセスを制限する
-
変数の使用
- ハードコードされた値ではなく変数を使用する
- 環境ごとに異なる値は変数で管理する
-
モジュール化
- 再利用可能なコンポーネントはモジュール化する
- 環境ごとの違いはモジュールのパラメータで吸収する
-
コードレビュー
- インフラの変更は必ずコードレビューを行う
-
terraform plan
の結果を確認する
5. まとめ
GCPでTerraformを使った自動デプロイを実装する際には、以下の点に注意することが重要です:
- 適切な権限設定:サービスアカウントには必要な権限を正確に付与する
- 状態管理の設定:Terraformの状態を保存するバケットを適切に設定する
- 変数の正確な設定:特にサービスアカウントのメールアドレスなどのプレースホルダーを実際の値に置き換える
- GitHub Secretsの正確な設定:認証情報やプロジェクトIDを正確に設定する
これらのポイントに注意することで、GCPでのTerraformを使った自動デプロイをスムーズに実装することができます。トラブルが発生した場合も、エラーメッセージを注意深く読み、適切な権限設定や設定ファイルの修正を行うことで解決できるでしょう。
Discussion