この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
データアナリティクス事業部でGoogle Cloudのデータエンジニアをしています。はんざわです。
Terraformにはmoduleという他のプログラミング言語でいう所の関数のようなものが存在します。今回はmoduleの使い方を改めて学習したのでそのことをまとめておきます。
また、複数のCloudサービスをmoduleで管理する際にmodule間での変数の受け渡しに困ったのでそれについても調べたことをまとめておきます。
環境
Google Cloud Shell
terraform:v1.2.7
構成図
output_test/
└── terraform
├── environments
│ ├── test1
│ │ ├── main.tf
│ │ └── terraform.tfvars
│ ├── test2
│ │ ├── main.tf
│ │ └── terraform.tfvars
│ └── test3
│ ├── main.tf
│ └── terraform.tfvars
└── modules
├── cloud_storage
│ ├── main.tf
│ ├── output.tf
│ └── variables.tf
└── storage_bucket_object
├── main.tf
└── variables.tf
8 directories, 11 files
構成はベストプラクティスを参考にしています。
検証
冒頭でも説明した通り、Terraformにはmoduleという他のプログラミング言語でいう所の関数のようなものが存在します。この関数の中でCloudサービスのリソースを定義し、それを変数と一緒に呼び出すことでその変数通りのCloudサービスを構築することができます。
今回の検証ではmodulesディレクトリでCloudサービスのリソースを定義し、environmentsディレクトリの各testリポジトリでmodulesディレクトリから必要なリソースを呼び出しています。
下記は、modules配下のCloud Storageディレクトリの主要ファイルの中身です。
# modules/cloud_storage/main.tf
resource "google_storage_bucket" "bucket" {
name = var.bucket_name
location = var.bucket_location
}
# modules/cloud_storage/variables.tf
variable "bucket_name" {
type = string
}
variable "bucket_location" {
type = string
default = "US-CENTRAL1"
}
main.tfで使用するCloudサービスを定義し、variables.tfで使用している変数を宣言しています。defaultが設定されている変数は何も値を与えないとその値で作成されます。
この例では、bucket_name
とbucket_location
の2つの変数が宣言されています。bucket_location
にはUS-CENTRAL1がdefault値として設定されいるため、何も設定しないとUS-CENTRAL1で作成されます。
1. とりあえずCloud Storageをmoduleで構築する
ここではシンプルにmodulesで定義したリソースを呼び出し、Cloud Storageを構築します。
test1ディレクトリ配下のmain.tfは以下のような構成になっています。
# test1/main.tf
# 変数定義
variable project_id {}
provider "google" {
project = var.project_id
}
# ロケーションを指定せずにバケットを作成
module "test1_bucket1" {
source = "../../modules/cloud_storage/"
bucket_name = "test1-bucket1-yuya-hanzawa"
}
# ロケーションを指定してバケットを作成
module "test1_bucket2" {
source = "../../modules/cloud_storage/"
bucket_name = "test1-bucket2-yuya-hanzawa"
bucket_location = "ASIA-NORTHEAST1"
}
test1_bucket1ではbucket_location
を代入せず、test1_bucket2ではbucket_location
にASIA-NORTHEAST1を代入しました。あとはtest1ディレクトリ配下でtf init
、tf plan
、tf apply
と順に実行すればファイルが実行されます。
想定通り作れていました。
2. output.tfファイルを理解する
そもそもoutput.tfとは何者なのか。一言で表すなら関数の戻り値を定義するファイルです。 cloud_storageディレクトリ配下のoutput.tfは以下のようになっています。
# modules/cloud_storage/output.tf
output "bucket_name" {
value = google_storage_bucket.bucket.name
}
output "location_name" {
value = google_storage_bucket.bucket.location
}
このファイルで定義されているoutputはこのディレクトリのリソースを呼び出した時に参照することが可能です。 test2ディレクトリのmain.tfは以下のような構成をしています。
# test2/main.tf
# 変数定義
variable project_id {}
provider "google" {
project = var.project_id
}
# bucketを作成
module "test2_bucket1" {
source = "../../modules/cloud_storage/"
bucket_name = "test2-bucket1-yuya-hanzawa"
bucket_location = "ASIA-NORTHEAST1"
}
# 全てのアウトプットを取得
output "bucket_output_all" {
value = module.test2_bucket1
}
# バケットの名前を取得
output "bucket_output_name" {
value = module.test2_bucket1.bucket_name
}
# バケットのロケーションを取得
output "bucket_output_location" {
value = module.test2_bucket1.location_name
}
このファイルのvalue = module.test2_bucket1
の部分でmodules配下のoutput.tfで定義したoutput valueを呼び出しています。
ここでoutput.tfを作成していないとこの部分は空で返ってきます。
上記ファイルの実行結果は以下の通りです。
Changes to Outputs:
+ bucket_output_all = {
+ bucket_name = "test2-bucket1-yuya-hanzawa"
+ location_name = "ASIA-NORTHEAST1"
}
+ bucket_output_location = "ASIA-NORTHEAST1"
+ bucket_output_name = "test2-bucket1-yuya-hanzawa"
期待通りの結果になっていました。
3. ファイルをstorage bucketに転送する
最後にoutput.tfからbucketの名前を取得し、そのbucketにファイルを転送してみます。 ファイルを転送するmoduleは以下の通りです。
# modules/storage_bucket_object/main.tf
data "archive_file" "zip_file" {
type = "zip"
source_dir = var.source_dir
output_path = var.output_path
}
resource "google_storage_bucket_object" "upload_files" {
name = var.file_name
bucket = var.archive_bucket
source = "${data.archive_file.zip_file.output_path}"
}
上記のmoduleはtest3ディレクトリのmain.tfで呼び出されています。
# test3/main.tf
# 変数定義
variable project_id {}
provider "google" {
project = var.project_id
}
# bucket1を作成
module "test3_bucket1" {
source = "../../modules/cloud_storage/"
bucket_name = "test3-bucket1-yuya-hanzawa"
}
# terraformディレクトリ配下のファイルをzip形式でbucket1に転送
module "test3_upload1" {
source = "../../modules/storage_bucket_object"
source_dir = "../../"
output_path = "/tmp/terraform.zip"
file_name = "terraform.zip"
archive_bucket = module.test3_bucket1.bucket_name
}
上記のtest3_upload1
moduleのarchive_bucket = module.test3_bucket1.bucket_name
でtest3_bucket1
のバケット名を取得しています。
このようにoutput.tfを適切に設定することで異なるmodule間で変数を呼び出すことが可能になります。
まとめ
同一のクラウドサービスを複数個作成する場合、moduleを適切に管理すると可読性が上がり、管理しやすくなると思います。
まだまだDevelopersIO内でGoogle CloudのTerraformに関する記事は少ないのでもっと書いていきたいと思っています。
参照元
Terraform ベストプラクティスを整理してみました。
Google Cloud Terraform を使用するためのベスト プラクティス
google_storage_bucket | Resources | hashicorp/google