Google CloudのリソースをTerraform化するための7ステップ
私は本業、副業、個人開発と関わる全てのプロジェクトでGoogle CloudとTerraformを利用しています。
中でも直近の案件でGoogle CloudのリソースをTerraform化するプロジェクトに3ヶ月間ほど取り組んでおり、ナレッジが蓄積してきましたので7つのStepに分けて解説します。
はじめに
すでにプロジェクトでTerraformが導入されているかどうかに関わらず参考できる記事となります。また、Terraformが未導入の場合は、以下のセクションを読み飛ばしていただいても構いません
- Terraformのアップグレードをする
- Google Providerのアップグレードをする
コマンドの実行例はGoogle Cloudのみに適用できるケースが多いですが、それ以外はAWSやAzureなどを他のクラウドプロバイダーを利用中の方もご参考いただける点もあるかと思います。
※コマンドの実行例は、Google Cloud Project IDに個人プロジェクト(company-ranking-prod
)を指定しています。必要に応じて、ご自身のProject IDに読み替えてください。
この記事で扱わないこと
それぞれ1つの記事以上のボリュームになるトピックになるため、本記事では扱いません
- Infrastructure as Code(以下、IaC)とは何か
- Terraformのstate, importとは何か
- Terraformと他のIaCツールとの比較
Step1. 使用しているリソースを洗い出す
まずは、現在使用しているGoogle Cloudのリソースを洗い出しましょう。
個人的に一番苦戦している点で、抜け漏れなくかつ効率よく行う方法について、まだ試行錯誤中です。
私が試している2つの方法について紹介します。
1. 一括でTerraformのコードに出力する
gcloud beta resource-config bulk-export
コマンドで現在使用しているリソースを一括でTerraformのコードに出力することが可能です。しかし、この方法は対応しているリソースの種類が少ないため、このコマンド1つで抜け漏れなくコード出力できるわけではない点に注意が必要です。
参考
- https://cloud.google.com/docs/terraform/resource-management/export?hl=ja#export_the_entire_project_configuration_to_terraform_hcl_code
- https://cloud.google.com/sdk/gcloud/reference/beta/resource-config/bulk-export
2. 使用しているAPIから当たりを付ける
gcloud services list
コマンドで使用しているサービスの一覧を取得し、そのサービスからリソースを想定する方法です。しかし、この方法で出力されたサービスの一覧と、実際にTerraformで定義できるリソースは一対一の対応をしているわけではないため、別途手動での対応付けが必要になります。具体的には、出力されたAPIの一覧を参考に、コンソールやコマンドにて具体的にどのリソースが存在するかを確認する、といった方法が可能です。
この方法は、コマンドの実行例、Google Providerのドキュメント、Google Cloudのコンソールをそれぞれ行き来する必要があるため手間はかかるのですが、他に良い方法が見当たらないためこの方法を取っています。
参考
- https://cloud.google.com/sdk/gcloud/reference/services/list
- https://cloud.google.com/service-usage/docs/list-services?hl=ja
コマンド実行例
例として、私が個人開発のプロジェクトで実行したコマンドを紹介します。
まず、サービスの一覧を取得します。
$ gcloud services list --project=company-ranking-prod --format=json | jq '.[].name'
"projects/1026927710795/services/artifactregistry.googleapis.com"
"projects/1026927710795/services/cloudasset.googleapis.com"
"projects/1026927710795/services/cloudbuild.googleapis.com"
"projects/1026927710795/services/cloudscheduler.googleapis.com"
"projects/1026927710795/services/cloudtrace.googleapis.com"
"projects/1026927710795/services/containeranalysis.googleapis.com"
"projects/1026927710795/services/containerregistry.googleapis.com"
"projects/1026927710795/services/iam.googleapis.com"
"projects/1026927710795/services/iamcredentials.googleapis.com"
"projects/1026927710795/services/logging.googleapis.com"
"projects/1026927710795/services/pubsub.googleapis.com"
"projects/1026927710795/services/run.googleapis.com"
"projects/1026927710795/services/secretmanager.googleapis.com"
"projects/1026927710795/services/storage-api.googleapis.com"
"projects/1026927710795/services/storage-component.googleapis.com"
"projects/1026927710795/services/workflowexecutions.googleapis.com"
"projects/1026927710795/services/workflows.googleapis.com"
projects/1026927710795/services/run.googleapis.com
というサービスに焦点を当てます。
ここから、Cloud Runのリソースが有効化されていることが想定できます。
Cloud Runに関するリソースの中でもTerraform化可能なのは画像の通りです。
それぞれのリソース一覧を確認するためにコマンドで一覧を取得します。
# Cloud Run Jobsの場合
$ gcloud run jobs list --project=company-ranking-prod --format=json | jq '.[].metadata.name'
"company-ranking-job"
"destroy-old-documents"
"save-document-detail-job"
"save-document-summary-daily-job"
"save-securities-job"
# Cloud Run Serviceの場合
$ gcloud run services list --project=company-ranking-prod --format=json | jq '.[].metadata.name'
"company-ranking-server"
Step2. Terraform化するリソースを決める
次に、どのリソースをTerraform化するかを判断しましょう。IaCといっても、全てのリソースをコード化することが必ずしも最適とは限りません。
観点としては、
- プロジェクト作成時やAPI有効時に自動で作成されるデフォルトのリソースをIaC対象とするかどうか
などが挙げられます。私はこの点について、「デフォルトのリソースを変更する可能性があるかどうか」を判断の軸とし、変更の可能性があればIaC化する場合が多いです。
Step3. CI/CDを構築する
CI/CDのツールとして何を使用するかを決定します。
主なツールとしては下記があります。
- Terraform Cloud
- Atlantis
- GitHub Actions
- Cloud Build
どのツールを選択するかは「何をCI/CDで実現したいか」により決定すべきですが、私はやりたいことを以下のように定義しているため、「GitHub Actions」を採用するケースが多いです。
- PR作成時に、tfファイルに変更があれば
terraform fmt
,terraform validate
,terraform plan
を実行し、実行結果をPRのコメント欄に貼付する - PRマージ時に、マージコミットを参照して
terraform apply
を実行い、実行結果をPRのコメント欄に貼付する
Step4. ディレクトリ構造、リポジトリ構造を決める
Terraformのディレクトリ構造とリポジトリ構造を決定します。
主なパターンは下記の通りです。
- ディレクトリ構造のパターン
- 1ディレクトリでTerraformのworkspace機能を使う
- 環境ごとにディレクトリを作成する
- リポジトリ構造のパターン
- アプリケーションと同一リポジトリ
- Terraform専用のモノレポ
- Terraform専用のマルチレポ
詳細なメリット・デメリットの比較は参考記事をご覧ください。私は「すでにTerraformが導入されているかどうか」や「開発速度」、「チームでの認知負荷」を考慮して以下の提案をする事が多いです。
- ディレクトリ構造: 環境ごとにディレクトリを作成する
- リポジトリ構造: アプリケーションと同一リポジトリ
参考
- ディレクトリ構造
- モノレポ vs マルチレポ
Step5. Terraformのアップグレードをする
この前までのStepでTerraformのCI/CDが構築されているため、安全にTerraformのアップグレードをすることが出来ます。最新バージョンまで上げましょう。
アップグレード方法については、公式ドキュメントが非常に詳しいため、バージョンごとのドキュメントを参照すれば、問題なくアップグレードできるでしょう。Terraformの一部のバージョンでは、1つのマイナーバージョンずつしか上げられない場合があるため、注意が必要です。
私がTerraformのv0.12からv1.7まで上げた際は、「v0.12 → v0.13 → v0.14 → v1.7」の順に上げました。
参考
- 公式ドキュメント
- その他
Step6. Google Providerのアップグレードをする
Terraformのアップグレードと同タイミングでGoogle Providerのバージョンも上げましょう。Google Providerについては、メジャーバージョンごとにアップグレードについての詳細な公式ドキュメントが用意されていますので、こちらを参照するとスムーズにアップグレードできます。
- https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/version_4_upgrade
- https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/version_5_upgrade
Step7. リソースごとにimportする
あとはひたすらimportしていきます。importとは、既存のGoogle Cloudのリソースは変更せずに、リソースの状態をstateファイルに変更することです。
importには、CLIでterraform import
コマンドを使う方法と、import block
をTerraformのファイルに定義する方法がありますが、私はimport block
を使う方法を推奨しています。この方法については記事を書きましたので、ご参考ください。
importする上で私は下記の方法で行いました。
-
gcloud {resource_name} list
コマンドで対象のリソースのリソース名の一覧を取得する - 対象のリソースのimport方法をGoogle Providerのドキュメントで確認する
- リソースごとに
import block
を定義する -
terraform plan -generate-config-out={file_name}
コマンドで自動でTerraformのコードを生成する -
terraform plan
コマンドを実行し差分がないことを確認する -
terraform apply
を実行し差分がないことを確認する
コマンド実行例
例として、私が個人開発のプロジェクトでCloud Run Jobsをimportする場合に実行したコマンドを紹介します。
# 1. 対象のリソースのリソース名の一覧を取得する
$ gcloud run jobs list --project=company-ranking-prod --format=json | jq '.[].metadata.name'
"company-ranking-job"
"destroy-old-documents"
"save-document-detail-job"
"save-document-summary-daily-job"
"save-securities-job"
# 2. import方法を確認し、3. import blockを定義する
$ cat google_cloud_run_v2_job_import.tf
import {
id = "asia-northeast1/company-ranking-job"
to = google_cloud_run_v2_job.company_ranking_job
}
import {
id = "asia-northeast1/destroy-old-documents"
to = google_cloud_run_v2_job.destroy_old_documents
}
import {
id = "asia-northeast1/save-document-detail-job"
to = google_cloud_run_v2_job.save_document_detail_job
}
import {
id = "asia-northeast1/save-document-summary-daily-job"
to = google_cloud_run_v2_job.save_document_summary_daily_job
}
import {
id = "asia-northeast1/save-securities-job"
to = google_cloud_run_v2_job.save_securities_job
}
# 4. 自動でTerraformのコードを生成する
terraform plan -generate-config-out=google_cloud_run_v2_job.tf
# 5. terraform plan を実行し差分がないことを確認する
terraform plan
# 6. terraform apply を実行し差分がないことを確認する
terraforma apply
最後に
本記事では、Google Cloudのリソースを対象にTerraform化するためにやることを1つずつ紹介しました。
Terraform歴は長くはないため、改善の余地がある点もあるかと思いますので、Xやコメント欄でフィードバックをお待ちしています。
少しでもお役立ちいただけたら、リアクションをしていただけると嬉しいです。
Discussion