infrastructure 也可以 for each 之二
課程內容與代碼會放在 Github 上: https://github.com/chechiachang/terraform-30-days
賽後文章會整理放到個人的部落格上 http://chechia.net/
這邊細講 for_each
meta-argument 的相關使用
for_each
的 resource block 中,可以在使用 each object,來取得 for_each
內的 key 與 value以 node_pools
這個變數為例,本身是 module 的 intput variable
# modules/kubernetes_cluster/variables.tf
# var.node_pools is a map of any
variable "node_pools" {
type = map(any)
default = {}
}
實際 node_pools
input variable 內容物可能漲這樣
node_pools = {
spot = {...},
on-demand = {...}
}
然後回頭看 for_each
for_each = var.node_pools
指的是,為每個 node_pools
的 member 產生一組 resourceresource "azurerm_kubernetes_cluster_node_pool" "main" {
for_each = var.node_pools
name = each.value.name
...
}
將 meta-argument 展開後,實際上會是
azurerm_kubernetes_cluster_node_pool
resourcefor_each
meta-argument,讓 terraform 知道resource "azurerm_kubernetes_cluster_node_pool" "main[spot]" {
name = var.node_pools.spot.name
...
}
resource "azurerm_kubernetes_cluster_node_pool" "main[on-demand]" {
name = var.node_pools.on-demand.name
...
}
至於實際 each.value.name 會取到什麼值,就依照各個 member value 去尋找
node_pools = {
spot = {
name = "spot"
...
},
on_demand = {
name = "on-demand"
...
}
}
最後變成,兩個 resource block
resource "azurerm_kubernetes_cluster_node_pool" "main[spot]" {
name = "spot"
...
}
resource "azurerm_kubernetes_cluster_node_pool" "main[on-demand]" {
name = "on-demand"
...
}
比較兩種寫法
resource "azurerm_kubernetes_cluster_node_pool" "main" {
for_each = var.node_pools
name = each.value.name
kubernetes_cluster_id = azurerm_kubernetes_cluster.main.id
vm_size = each.value.vm_size
node_count = each.value.node_count
mode = each.value.mode
priority = each.value.priority
node_labels = each.value.node_labels
node_taints = each.value.node_taints
}
resource "azurerm_kubernetes_cluster_node_pool" "main[spot]" {
name = "spot"
...
}
resource "azurerm_kubernetes_cluster_node_pool" "main[on-demand]" {
name = "on-demand"
...
}
好處
壞處
實務上我們都會選擇使用 for_each
meta-argument,犧牲可讀性換取精簡的程式碼
Terraform for each meta-argument 也有許多限制
for_each
的 variable 必須是 deterministic,意思是必須是定值for_each
的參數其實仍是 undefinedsentisive 的參數也無法使用在 for_each
上
for_each
需要的可見度,會無法取得 sensitive 數值variable "vpcs" {
type = map(object({
cidr_block = string
}))
}
resource "aws_vpc" "example" {
# One VPC for each element of var.vpcs
for_each = var.vpcs
# each.value here is a value from var.vpcs
cidr_block = each.value.cidr_block
}
resource "aws_internet_gateway" "example" {
# One Internet Gateway per VPC
for_each = aws_vpc.example
# each.value here is a full aws_vpc object
vpc_id = each.value.id
}
output "vpc_ids" {
value = {
for k, v in aws_vpc.example : k => v.id
}
# The VPCs aren't fully functional until their
# internet gateways are running.
depends_on = [aws_internet_gateway.example]
}