May 1, 2024
description : モジュールとループを駆使して可読性の高いterraformを目指したメモ
以前の記事の拡張エキスパンション的な記事。
上記を読んでる前提で書くので、先に読んでおくとわかりやすい、かも。
最近terraformを書くときに、意識的に同じようなリソース定義を繰り返さない実装をしている。
具体的には、
の2つを積極的に取り入れている。
たぶん半年くらいすると自分で意図がわからなくなっているので、未来の自分に向けて記録を残す。
リポジトリ、もしくはserviceモジュール直下のtfファイルは、そこで管理されているterraform全体で定義したいものを読み解けることが必要だと考えている。
ところが、リソースを律儀に定義しているとtfファイルがどんどん肥大化して可読性が落ちてしまう。これをなんとかしたい。
より具体的にすると、
あたりを目指す。
基本的にterraformはモジュールを使わなくても使える。
モジュールは再利用したい=複数回定義したいリソース群をまとめるのが一般的な使い方だと思うが、最近はあえて一度きりしか定義しないものもモジュール化している。
これは依存関係をわかりやすくするため。
terraformは、同一ディレクトリ内で定義されたリソースやデータに対して自由に参照できる。
便利な一方で、「このリソースってどこで定義しているんだっけ?」「このリソースそこからも参照してるの?」みたいなことが時々起きる。
モジュールを使うことで、これを防ぐ。
モジュールで定義されたリソースやデータには直接参照できず、またモジュール側もモジュールの外のリソースを直接参照できない。
モジュール-モジュールの外部の入出力はそれぞれvariable
, output
で明示的に定義する必要があり、これを安全装置として使おうという試み。
variable
, output
をいちいち定義するのはめんどうなので、周辺の依存関係を自然とモジュール化するようになるvariable
, output
のdescriptionでドキュメント化される
main.tf
を想定)を見ればだいたいどんなリソースが定義されるのか俯瞰できるようになる、はずの2点をねらっている。
また、適度にモジュール化されていると、terraform graph
の出力がある程度綺麗になってセイシンテキがとてもいい。
まず、このようにlocalsを使ってリソースのリストを作る。
locals {
cname_records = {
"blog" = { value = "cname.vercel-dns.com.", comment = "blog on Vercel", proxied = false }
"k16em.net" = { value = "k16em-net.pages.dev", comment = "LP on Cloudflare Pages / using CNAME flattening", proxied = true }
"www" = { value = "k16em-net.pages.dev", comment = "LP on Cloudflare Pages", proxied = true }
}
txt_records = {
"k16em.net" = { value = "keybase-site-verification=tpgM8Hmp9bkePa9j-qMD7G_Hy1KoCkpEgPi_OQVqzW8", comment = "for keybase" }
"blog" = { value = "keybase-site-verification=udbQAxp-I1L3AHezcTnOAXhSPpq_CbLz1P9KCj9lkfo", comment = "for keybase" }
}
}
それをもとに、for_each
を使って実体を定義する。
# CNAME Records
resource "cloudflare_record" "cname" {
for_each = local.cname_records
zone_id = var.cloudflare_zone_id
name = each.key
comment = each.value.comment
type = "CNAME"
value = each.value.value
proxied = each.value.proxied
allow_overwrite = false
}
# TXT Records
resource "cloudflare_record" "txt" {
for_each = local.txt_records
zone_id = var.cloudflare_zone_id
name = each.key
comment = each.value.comment
type = "TXT"
value = each.value.value
allow_overwrite = false
}
やっていることは単純で、事前に定義したいパラメータのリストを作り、それをループで回しているだけ。
この書き方にはメリットがあり、
とくに、リソース名で悩まなくなったのが大きい。
これまでは、cloudflare_record.txt_blog
, cloudflare_record.cname_blog
のような形でリソースを定義していた。
あれ、これってサフィックスだっけ? プレフィックスだっけ? DNS名ってどこまで書くんだっけ? と、意外と命名には脳ミソを使っていた。
今回から、cloudflare_record.DNSの種別['ドメイン名']
の形にしたので、なにも悩まなくなった。
例ではcloudflare_record
を挙げたが、この他にもaws_ecr_repository
やaws_ecs_cluster
などもこの形で定義しており、今後は基本的にこの形で書いていくつもり。
aws_lb_listener_ruleのような、複数のblockが定義できるリソースをどうするかは要検討。