こんにちは、エリックです。今回はTerraformの話にします。
Terraformでworkspaceを使う時に、dev/stg/prodなどの環境を統一するのがベストだけど、たまにコストや機能により「ここにはこれは要らないな」などの場合がある。その時、各環境に有無トグルをどうやって設定するか、どうやって依存などを解決するか軽く語ろう。
例として、foo/bar/bazというGKEクラスタのnode poolがあり、stg環境にbazが不要だとする。
- dev: foo, bar, baz
- prod: foo, bar, baz
- stg: foo, bar
各node poolはこんな風:
main.tf:
module node-pool-baz {
source = ".../container_node_pool/google"
version = "1.0.0"
cluster = module.cluster.cluster
node_pool = var.node_pool_baz
node = var.node_baz
service_account = module.sa-baz.sa
}
まず、node poolのモジュールに、有無のトグルを追加:
.terraform/modules/node-pool-baz/main.tf:
resource google_container_node_pool default {
+ count = var.node_pool.enabled ? 1 : 0
[...]
.terraform/modules/node-pool-baz/variables.tf:
variable node_pool {
type = object({
+ enabled = bool,
[...]
})
}
見れば分かると思うが、そのcount
行は三項演算子で、boolのenabled
との変数で、構築するかどうか決める。 trueなら、1つ構築、falseなら0構築(構築しない)。count
はTerraformで、どのリソースにでも使える。
環境(workspace)のtfvarsファイルはこんな風に:
stg.tfvars
:
node_pool_foo = {
enabled = true,
[...]
}
node_pool_bar = {
enabled = true,
[...]
}
node_pool_baz = {
enabled = false,
[...]
}
ここまでは大丈夫だけど、各node poolに、サービスアカウントも依存するから、 そのmoduleにもenabled追加しよう(そうしないと、enabled:falseの場合にでもサービスアカウントが作成されちゃう)。
まず、サービスアカウントのmoduleにそのenabled
変数を追加して、リスースのところに以上の三項演算子を:
.terraform/modules/sa-baz/variables.tf
:
+variable enabled {
+ type = bool
+ default = true
+}
.terraform/modules/sa-baz/main.tf
:
resource google_service_account default {
[...]
+ count = var.enabled ? 1 : 0
}
resource google_project_iam_member default {
[...]
- for_each = toset(var.roles)
+ for_each = var.enable ? toset(var.roles) : []
project = var.project
role = each.key
member = format("serviceAccount:%s", google_service_account.default.email)
}
あと、呼び出し側にもenabledを追加(混乱・重複しないためnode poolのenabledを利用して)。
main.tf
:
module sa-baz {
[...]
roles = var.sa_baz_roles
+ enabled = var.node_pool_baz.enabled
}
OK. 実行してみよう!
Error: Missing resource instance key
on .terraform/modules/sa-baz/main.tf line 15, in resource "google_project_iam_member" "default":
15: member = format("serviceAccount:%s", google_service_account.default.email)
Because google_service_account.default has "count" set, its attributes must be
accessed on specific instances.
For example, to correlate with indices of a referring resource, use:
google_service_account.default[count.index]
なるほど。count追加すると、変数が配列になり、indexで示さないと。 もうちょい修正:
.terraform/modules/sa-baz/main.tf
:
- member = format("serviceAccount:%s", google_service_account.default.email)
+ member = format("serviceAccount:%s", google_service_account.default[0].email)
で、もう一回実行してみる:
Error: Unsupported attribute
on .terraform/modules/node-pool-baz/main.tf line 13, in resource "google_container_node_pool" "default":
13: service_account = var.service_account.email
|----------------
| var.service_account is tuple with 1 element
This value does not have any attributes.
なるほど。配列になったけど、使用してるnode-poolのところが単独の変数を期待してる。どこを修正すれば良いかは、モジュールの出力のところを見てみよう。
.terraform/modules/sa-baz/output.tf
:
output sa {
value = google_service_account.default
}
ああ。では、こっちで配列の[0]
にすれば、配列じゃなくて普通の変数が出てくるわけですね。
value = google_service_account.default[0]
もう一回実行:
Error: Invalid index
on .terraform/modules/sa-baz/output.tf line 2, in output "sa":
2: value = google_service_account.default[0]
|----------------
| google_service_account.default is empty tuple
The given key does not identify an element in this collection value.
あ〜、enabled: falseのところは、サービスアカウントがないから配列の[0]
もないね。 じゃあ、これはどう?
value = length(google_service_account.default) > 0 ? google_service_account.default[0] : ""
やってみよう:
Error: Error in function call
on .terraform/modules/sa-baz/output.tf line 2, in output "sa":
2: value = length(google_service_account.default > 0) ? google_service_account.default[0] : ""
Call to function "length" failed: argument must be a string, a collection
type, or a structural type.
ダメだな。配列がないならlengthも使えない。ちょいググったら、こんな形が出てきた:
value = try(google_service_account.default[0], null)
saの配列[0]
の要素を返してみて、それがなければnull
を。
No changes. Infrastructure is up-to-date.
これで解決〜!
…とはいえ、moduleで色んな書き方があるし、0.13から呼び出しの方からでもfor_each
やcount
が使えるようになったらしい。とゆーところで、 0.13でどうやって扱うか、良い方法考えてみるのは宿題!w
〜終〜
株式会社grasys(グラシス)は、技術が好きで一緒に夢中になれる仲間を募集しています。
grasysは、大規模・高負荷・高集積・高密度なシステムを多く扱っているITインフラの会社です。Google Cloud (GCP)、Amazon Web Services (AWS)、Microsoft Azureの最先端技術を活用してクラウドインフラやデータ分析基盤など、ITシステムの重要な基盤を設計・構築し、改善を続けながら運用しています。
お客様の課題解決をしながら技術を広げたい方、攻めのインフラ技術を習得したい方、とことん技術を追求したい方にとって素晴らしい環境が、grasysにはあります。
お気軽にご連絡ください。