🔨

Google CloudのリソースをTerraform化するための7ステップ

2024/03/10に公開

私は本業、副業、個人開発と関わる全てのプロジェクトで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つで抜け漏れなくコード出力できるわけではない点に注意が必要です。

参考

2. 使用しているAPIから当たりを付ける

gcloud services list コマンドで使用しているサービスの一覧を取得し、そのサービスからリソースを想定する方法です。しかし、この方法で出力されたサービスの一覧と、実際にTerraformで定義できるリソースは一対一の対応をしているわけではないため、別途手動での対応付けが必要になります。具体的には、出力されたAPIの一覧を参考に、コンソールやコマンドにて具体的にどのリソースが存在するかを確認する、といった方法が可能です。
この方法は、コマンドの実行例、Google Providerのドキュメント、Google Cloudのコンソールをそれぞれ行き来する必要があるため手間はかかるのですが、他に良い方法が見当たらないためこの方法を取っています。

参考

コマンド実行例

例として、私が個人開発のプロジェクトで実行したコマンドを紹介します。

まず、サービスの一覧を取得します。

$ 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のツールとして何を使用するかを決定します。

主なツールとしては下記があります。

どのツールを選択するかは「何を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が導入されているかどうか」や「開発速度」、「チームでの認知負荷」を考慮して以下の提案をする事が多いです。

  • ディレクトリ構造: 環境ごとにディレクトリを作成する
  • リポジトリ構造: アプリケーションと同一リポジトリ

参考

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については、メジャーバージョンごとにアップグレードについての詳細な公式ドキュメントが用意されていますので、こちらを参照するとスムーズにアップグレードできます。

Step7. リソースごとにimportする

あとはひたすらimportしていきます。importとは、既存のGoogle Cloudのリソースは変更せずに、リソースの状態をstateファイルに変更することです。
importには、CLIでterraform importコマンドを使う方法と、import blockをTerraformのファイルに定義する方法がありますが、私はimport blockを使う方法を推奨しています。この方法については記事を書きましたので、ご参考ください。

https://zenn.dev/yuki0920/articles/736c66784e58f9

importする上で私は下記の方法で行いました。

  1. gcloud {resource_name} list コマンドで対象のリソースのリソース名の一覧を取得する
  2. 対象のリソースのimport方法をGoogle Providerのドキュメントで確認する
  3. リソースごとに import block を定義する
  4. terraform plan -generate-config-out={file_name}コマンドで自動でTerraformのコードを生成する
  5. terraform plan コマンドを実行し差分がないことを確認する
  6. 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