TerraformでGoogle Cloudのインフラ構成を管理し始めるためにやったこと

最近はGoogle Cloudを触る機会も増えており、コンソールからポチポチ設定していたが、コード管理していきたいなというところからTerraformを触り始めた。その際にやったことを書いておく。

Terraform by Hashicorp

導入

Terraformのインストールが必要になりますが、その際 tfutils/tfenv を使うのがよくある方法のよう。
nodenvやrbenvのような *.env 系のバージョン管理ツールで、rbenvにインスパイアされたツール。

この手のツールは数が多く、なんだっけとなりがちなので mise を導入してこちらで管理してみた。

miseの導入

jdx/miseはasdfという *.env系のツールをいい感じに統合して扱えるツールをRustで再実装したようなツールで、Node.js以外はこちら経由で入れることが多い。ちなみにNode.jsについてはVoltaにしている。

ドキュメントに従い、以下のコマンドで導入する。

$ curl https://mise.run | sh
$ ~/.local/bin/mise --version
2024.6.6 linux-x64 (409d6e4 2024-06-20)

$ echo '~/.local/bin/mise activate fish | source' >> ~/.config/fish/paths.fish
$ source ~/.config/fish/paths.fish
$ mise --version
2024.6.6 linux-x64 (409d6e4 2024-06-20)

miseでTerraformを導入する

miseでTerraformを導入してみる。

$ mise install terraform
~中略~
mise terraform@1.8.5 ✓ installed
$ mise use terraform@1.8.5
mise ~/.mise.toml tools: terraform@1.8.5

$ mise use --global terraform@1.8.5
mise terraform is defined in ~/.mise.toml which overrides the global config (~/.config/mise/config.toml)
mise ~/.config/mise/config.toml tools: terraform@1.8.5

$ terraform --version
Terraform v1.8.5
on linux_amd64

どうでもいいが、ちゃんとインストールができるまで、「 terraforme」 とか 「terrafrom」 とかタイポがひどかった。

Google Cloudで使う設定をしてみる

※Google Cloudのプロジェクト作成とgcloud周りの設定は終わっている状態。

Terraform用のサービスアカウントを用意する

Terraformから各種リソースを操作していくために、専用のサービスアカウントを作成し、権限を付与しておく。

シェルスクリプト化したのでこちらを活用する。

#!/bin/bash

# 変数の定義
PROJECT_ID="your-project-id"
SERVICE_ACCOUNT_NAME="terraform"
DISPLAY_NAME="terraform"
KEY_FILE="terraform-sa.json"

# プロジェクトを設定
gcloud config set project $PROJECT_ID

# サービスアカウントを作成
gcloud iam service-accounts create $SERVICE_ACCOUNT_NAME \
    --display-name="$DISPLAY_NAME"

# サービスアカウントに権限を付与
gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member="serviceAccount:$SERVICE_ACCOUNT_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
    --role="roles/editor"

# サービスアカウントキーの作成とダウンロード
gcloud iam service-accounts keys create $KEY_FILE \
    --iam-account=$SERVICE_ACCOUNT_NAME@$PROJECT_ID.iam.gserviceaccount.com

オーナー権限を使うというのもあったが、編集権限である程度操作ができたので一旦こうしている。

Terraformのスクリプトを書いていく

一応スクリプトと呼称しているが、なんというのか分かっていない。

インフラサービス毎にスタートガイドのようなものが用意されていて、Google Cloudはこちらを参考に進めると良さそうだった。

https://developer.hashicorp.com/terraform/tutorials/gcp-get-started/google-cloud-platform-build

取り急ぎ main.tf でTerraformのバージョンはなんとなく指定しておく。

terraform {
  required_version = ">= 1.0.0, < 2.0.0"
}

この範囲外のバージョンで実行すると怒られる様になるらしい。

作成から実行までの流れ

なんとなくの流れとしては以下になる。

  1. 上記下準備をしておく
  2. Terraformで構築するリソースなど書いていく (main.tfなど)
  3. terraform init # terraform環境の初期化
  4. terraform plan # 何が作成されて、何が削除されるかが確認できるらしい
  5. terraform apply # リソースが実際に構築されるらしい

余談だが、環境差異で動かないこともあるらしく、terraform planterraform apply はCI/CD上で構築しておくのがいいらしい。
調べていると、4のタイミングで結果を PRにコメントとして出力させる方法があるろしい。すごく便利なのでWorkflowが構築できたら組み込みたい。
tfcmt で Terraform の CI/CD を改善する

また、合わせて組み込むと良さそうなツール類もいくつかあったので合わせて貼っておく。

Terraform開発時のDeveloper Experienceを爆上げする

小さい構成で作ってみる

main.tf

terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "4.51.0"
    }
  }
}

provider "google" {
  project = var.project_id
  region  = var.region
}

resource "google_storage_bucket" "bucket" {
  name     = var.bucket_name
  location = var.region
  strage_class = "STANDARD"
}

variables.tf

variable "project_id" {
  description = "The ID of the project in which to create resources."
  type        = string
}

variable "region" {
  description = "The region in which to create resources."
  type        = string
}

variable "bucket_name" {
  description = "The name of the Cloud Storage bucket."
  type        = string
}

staging.tfvars

project_id         = "PROJECT_ID"
region             = "us-west1"
bucket_name        = "bucket-name"

あるプロジェクトにリージョンを指定しつつ、Cloud Storageにバケットを作成するという内容。

スクリプトのチェックとリソース作成

$ terraform plan -var-file="staging.tfvars"
$ terraform apply -var-file="staging.tfvars"

terraform plan で何が作られるかを確認。 terraform apply でリソースの作成を行った

コマンド実行後にコンソールから作成できている事を確認。
terraform destroy で削除されることまで確認済み。

terraform.tfstateのバックアップ

terraform.tfstate に現状の構成がどうなっているかを保持しているらしい。
複数人開発なんかだと、これをStorageに持っておくのがいいらしい。どうやるかを以下の記事が書いている。

Terraform で入門する Google Cloud【セットアップ編】

専用のバケットを用意して、 terraform apply 時に自動でバックアップを取るというもの。
自動で取れるのでとてもいい気がする。

今回は構成が同じでいいので main.tf にまとめているが、環境ごとに分けるほうがいいのかもしれない。
元々このまま運用しても terraform.tfstate がおかしくなるような気もする。varファイルを切り替えたときにどうなるか次第だけど、ファイル構成は要検討になってきた。

main.tfはどういう構成にしておくといいか

先述の話を踏まえて色々調べていると、 environments/staging/main.tf みたいな環境毎に切り替える方法が出てきた。

これだと確かに先述の terraform.tfstate が環境ごとにぶつかりそう問題がおそらく回避できる。かつ、バックアップも取りやすそう。

共通する部分については、モジュールを活用するといいのかもしれない。

やってみて

ChatGPTなんかを活用しながら入門してみたが、こういうことを始めるのにとてもいい環境が整ってきたなと感じた。

また、いつかやろうと思っていたのを満を持してやってみたが、いい感じに進めることができた。今後Cloud RunやCloud SQLなど他のサービスも絡めて書いてみようと思う。