前回投稿で言及したTerraformのループ処理を、めっちゃシンプルなパターンでやってみた。
参考記事
Terraformで配列をloopする時はfor_eachを使った方がいい
やったこと
Terraformのセットアップは割愛。作業ディレクトリには以下のtfコードがある。
work_dir/
├── codecommit.tf
├── init.tf
├── variables.tf
└── vpc.tf
以下は初期化ファイル。terraform init
で初期化実行すみである。VPCも別途サクッと作ってある。ひとりPoCだからremote_stateにする必要もないのだが、なんとなくtfstateをS3に保管するためbackendの定義がある。
init.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "3.66.0"
}
}
}
terraform {
required_version = "1.0.11"
backend "s3" {
bucket = "my-terraform-poc-repository"
key = "poc/poc.tfstate"
region = "ap-northeast-1"
}
}
で、肝心のloop処理。最初なので脳に優しく、超シンプルなパターンでいく。CodeCommitリポジトリの作成はパラメータが少ないので、参考記事を参照し、これで試した。他にもパラメータが少ないやつならなんでもいいけど。今回セットする値はrepository_nameとdescriptionの2点だけ。
variable.tf
variable "codecommit_param_list" {
type = map(map(string))
default = {
param1 = {
repository_name = "repo001"
description = "desciption for repo001"
}
param2 = {
repository_name = "repo002"
description = "desciption for repo002"
}
param3 = {
repository_name = "repo003"
description = "desciption for repo003"
}
}
}
codecommit.tf
resource "aws_codecommit_repository" "codecommit_repos" {
for_each = var.codecommit_param_list
repository_name = lookup(each.value, "repository_name")
description = lookup(each.value, "description")
codecommit.tfの"codecommit_repos"は任意の名称。2行目、for_each
でvariables.tfのcodecommit_param_listを呼び出している。今回の場合はリポジトリ名がrepo001, repo002…となる。この状態でplanを実行すると以下の出力になる。
:
Terraform will perform the following actions:
# aws_codecommit_repository.codecommit_repos["param1"] will be created
+ resource "aws_codecommit_repository" "codecommit_repos" {
+ arn = (known after apply)
+ clone_url_http = (known after apply)
+ clone_url_ssh = (known after apply)
+ description = "desciption for repo001"
+ id = (known after apply)
+ repository_id = (known after apply)
+ repository_name = "repo001"
+ tags_all = (known after apply)
}
# aws_codecommit_repository.codecommit_repos["param2"] will be created
+ resource "aws_codecommit_repository" "codecommit_repos" {
+ arn = (known after apply)
+ clone_url_http = (known after apply)
+ clone_url_ssh = (known after apply)
+ description = "desciption for repo002"
+ id = (known after apply)
+ repository_id = (known after apply)
+ repository_name = "repo002"
+ tags_all = (known after apply)
}
(repo003も同様)
Plan: 3 to add, 0 to change, 0 to destroy.
terraform apply
を実行。期待値になった。(repo003だけ時間がずれているのは、1点間違いがあってやり直したから)
やれることはわかったのでこいつ達は削除する。
リポジトリを削除する。しかしいきなりdestroyすると別途作ったvpcまで消えてしまう。同じ階層にvpc.tfがあるのでそれはそのまま、codecommit.tfを作業ディレクトリから退避。この状態でapplyするとcodecommitリポジトリは消えてvpcは残る。以下でやっていることはapplyでもdestroyなので注意。
$ terraform apply
:
aws_codecommit_repository.codecommit_repos["param3"]: Destroying... [id=repo003]
aws_codecommit_repository.codecommit_repos["param1"]: Destroying... [id=repo001]
aws_codecommit_repository.codecommit_repos["param2"]: Destroying... [id=repo002]
aws_codecommit_repository.codecommit_repos["param1"]: Destruction complete after 0s
aws_codecommit_repository.codecommit_repos["param3"]: Destruction complete after 0s
aws_codecommit_repository.codecommit_repos["param2"]: Destruction complete after 0s
Apply complete! Resources: 0 added, 0 changed, 3 destroyed.
課題
コツは掴めたけど、コード本体に書く値がvariablesに移動しただけという気もする。パラメータが増えるほど、結局variablesが肥大化することになる。変数定義を分割できないか?
この課題については、変数定義をさらにtfvarsに外出しすることで解決可能。変数定義ファイルが増えることにはなるが、1ファイルが肥大化するよりいい。今回やった分だけでいうと、以下の構成になる。
work_dir/
├── codecommit.auto.tfvars
├── codecommit.tf
├── config.tf
├── terraform.tfvars
├── variables.tf
└── vpc.tf
xxxxx.auto.tfvarsに個別に分割した要素の値を記述すると、apply実行時に自動で呼び出される。
codecommit.tfはこれまでと同じ。
variables.tfには値は記述せず、宣言だけ記述する。
terraform.tfvarsにはリージョンなど全てに共通の値、IAMなど他のリソースから共通で参照されるリソースの値を記述。
variables.tf
# main
variable "region" {
type = string
description = ""
}
# codecommit
variable "codecommit_param_list" {
type = map(map(string))
description = ""
}
codecommit.auto.tfvars
# codecommit repos definition
codecommit_param_list = {
param1 = {
repository_name = "repo004"
description = "desciption for repo004"
}
param2 = {
repository_name = "repo005"
description = "desciption for repo005"
}
param3 = {
repository_name = "repo006"
description = "desciption for repo006"
}
}
terraform.tfvars
region = "ap-northeast-1"
codecommit.auto.tfvarsは例なのでこれだけだが、例えばネットワーク周り、アプリ系リソース、監視、ジョブ等の大枠に分割して、その枠毎にtfvarsを用意すれば小回りが効く構成になるんじゃないかと。て、なんかloop処理のことを書くつもりが変数周りのネタメインになった気がする。ま、いいか。
課題2
loopで作成したリソースの参照方法はどうすればいいのか?が気になって調査してみた。今回だと、Terraformで作成したCodeCommitリポジトリ名をCodePipeline作成時のコードで参照するケースとか。リポジトリrepo001を参照するなら以下の記述になる。
codecommit_repository.codecommit_repos["param1"].id
参照名はcodecommit_repository.codecommit_repos["param1"].repository_name
ではないことに注意。それはいいとして、CodePipeline自体もloopで作成するとしたらこの記述は使えないから、結局同じtfvarsの値を参照して作ることになるかな。