Terraform:如何按照对象内的定义循环 aws_instance N 次

Terraform : How to loop over aws_instance N times as defined within object

我有以下变量

variable "instance_types" {

  default = {

    instances : [
      {
        count                  = 1
        name                   = "control-plane"
        ami                    = "ami-xxxxx"
        instance_type          = "t2.large"
        iam_instance_profile   = "xxx-user"
        subnet_id              = "subnet-xxxxx"
      },
      {
        count                  = 3
        name                   = "worker"
        ami                    = "ami-xxxxx"
        instance_type          = "t2.large"
        iam_instance_profile   = "xxx-user"
        subnet_id              = "subnet-xxxxx"
      }
    ]
  }
}

使用以下实例声明(我正在尝试迭代)

resource "aws_instance" "k8s-node" {

  # Problem here : How to turn an array of 2 objects into 4 (1 control_plane, 3 workers)
  for_each = {for x in var.instance_types.instances:  x.count => x}

  ami                    = lookup(each.value, "ami")
  instance_type          = lookup(each.value, "instance_type")
  iam_instance_profile   = lookup(each.value, "iam_instance_profile")
  subnet_id              = lookup(each.value, "subnet_id")

  tags = {
    Name      = lookup(each.value, "name")
    Type      = each.key
  }
}

目标: 获取 aws_instance 迭代 4 次(1 control_plane + 3 个工人)并填充 [=14= 的索引值].

问题: 无法使用所需结果正确迭代对象数组。在典型的编程语言中,这将在双 for 循环中实现。

输入变量的数据类型 map(object)) 可以更容易地解决这个问题。转换后的数据结构如下所示:

variable "instance_types" {
  ...
  default = {
    "control-plane" = {
      count                  = 1
      ami                    = "ami-xxxxx"
      instance_type          = "t2.large"
      iam_instance_profile   = "xxx-user"
      subnet_id              = "subnet-xxxxx"
    },
    "worker" = {
      count                  = 3
      ami                    = "ami-xxxxx"
      instance_type          = "t2.large"
      iam_instance_profile   = "xxx-user"
      subnet_id              = "subnet-xxxxx"
    }
  }
}

请注意 object 中的 name 键包含在 map 键中以提高效率和清洁度。

如果资源在控制平面和工作节点之间分配,那么我们就完成了,可以立即在 for_each 元参数中利用此变量的值。但是,合并资源现在需要进行数据转换:

locals {
  instance_types = flatten([ # need this for final structure type
    for instance_key, instance in var.instance_types : [ # iterate over variable input objects
      for type_count in range(1, instance.count + 1) : { # sub-iterate over objects by "count" value specified; use range function and begin at 1 for human readability
        new_key              = "${instance_key} ${type_count}" # for resource uniqueness
        type                 = instance_key # for easier tag value later
        ami                  = instance.ami # this and below retained from variable inputs
        instance_type        = instance.instance_type
        iam_instance_profile = instance.iam_instance_profile
        subnet_id            = instance.subnet_id
      }
    ]
  ])
}

现在我们可以使用 for_each 元参数在资源内进行迭代,并利用 for 表达式重建输入以在资源内适当使用。

resource "aws_instance" "k8s-node" {
  # local.instance_types is a list of objects, and we need a map of objects with unique resource keys
  for_each = { for instance_type in local.instance_types : instance_type.new_key => instance_type }

  ami                  = each.value.ami
  instance_type        = each.value.instance_type
  iam_instance_profile = each.value.iam_instance_profile
  subnet_id            = each.value.subnet_id

  tags = {
    Name = each.key
    Type = each.value.type
  }
}

这将为您提供所需的行为,您可以根据需要修改它以适应样式偏好或不同用途。

请注意,lookup 函数已被删除,因为它们仅在将默认值指定为第三个参数时才有用,这在变量声明中的对象类型中是不可能的,除非作为 0.14 中的实验性功能。

这些资源的导出资源属性的绝对命名空间为:

(module?.<declared_module_name>?.)<resource_type>.<resource_name>[<resource_key>].<attribute>

例如,给定模块内资源、第一个工作节点和私有 ip 地址导出属性:

aws_instance.k8s-node["worker 1"].private_ip

请注意,您还可以通过在 <resource_name> 处终止命名空间来访问所有资源的导出属性(保留所有资源的映射而不是访问单个资源值)。然后,您还可以在 output 声明中使用 for 表达式,为所有类似资源及其相同的导出属性创建自定义聚合输出。

{ for node_key, node in aws_instance.k8s-node : node_key => node.private_ip }