こんにちは、最近Terraformデビューしました。 社内の人々がTerraformに苦しんでいたのをみてなんとなく敬遠していたのだけど、そうも言ってられなくデビューしたところうひょーーー!楽しい!!!ってなっている今日この頃。
lifecycleを動的に変更したい
そんなわけでTerraformを使い始め、すでに稼働しているサービスをテラフォーミングしはじめた。 サーバごとにresourceを定義するのだけど、同じような定義が多いのでモジュール化すると思う。 例えば以下のような感じ(説明に必要な最低限のものだけを書いている)。
❯ tree
.
├── a.tf
├── b.tf
└── modules
└── base
└── main.tf
❯ cat a.tf
module "a" {
source = "modules/base"
-- snip --
}
❯ cat b.tf
module "b" {
source = "modules/base"
-- snip --
}
❯ cat modules/base/main.tf
resource "openstack_compute_instance_v2" "base" {
-- snip --
lifecycle {
ignore_changes = [key_pairs]
}
}
しかし、困ったことが起こった。 新たにc.tfを追加したいのだけど、このcサーバではSecurity Group(SG)をTerraformで管理したくない。 具体的には関門海峡を利用していて、SGが頻繁に変更される。 関門海峡でSGを追加しているときにTerraformを適用すると差分になってしまうのでこれをなんとかしたい。
dynamicを使う?
Terraformで差分として扱わないようにするためにlifecycleのignore_changesを指定すればよいのだけど、modules/base/main.tfにこの記述を追加するとa.tfやb.tfもSGが管理されなくなってしまう。 困った。
こういうときのためにdynamicが使えるのだが、なんとこのlifecycleにはdynamicは使えないのであった。
どうしたものか
overrideを使ってみた
解決策として、module/base/main.tfをコピーしてmodule/base_ignore_sg/main.tf を作れば良いと最初に考えた。 しかし、これだとbaseとbase_ignore_sgの2重管理になってめんどうだなっと思った。
そこでこれを解決するためにOverride Filesを使うことを考えた。 具体的には以下のような感じ
❯ tree
.
├── c.tf
└── modules
├── base
│ └── main.tf
└── base_ignore_sg
├── main.tf -> ../base/main.tf 👈 シンボリックリンク
└── override.tf 👈
❯ cat c.tf
module "c" {
source = "modules/base_ignore_sg" 👈
}
❯ cat modules/base_ignore_sg/override.tf
resource "openstack_compute_instance_v2" "base" {
lifecycle {
ignore_changes = [key_pairs, security_groups] 👈
}
}
override.tfを追加して、この中にlifecycle/ignore_changesを追加してこの中でsecurity_groupsを追加している。 main.tfはbaseのシンボリックリンクなので二重管理にならない。 めでたしめでたし。
おわりに
これでやりたかったことはできた。
のだけど、tflintを流すとなぜかterraform_deprecated_interpolationでエラーになってしまう。
何が原因か調べていないけど、terraform validateでエラーにならないのでtflintで --disable-rule=terraform_deprecated_interpolation を指定することにした。
こんな感じで工夫してみたけど、もっといいやり方はあるのかな?