【问题标题】:Terraform : How to loop over aws_instance N times as defined within objectTerraform:如何在对象中定义的 aws_instance N 次循环
【发布时间】:2021-03-09 04:47:41
【问题描述】:

我有以下变量

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 个工作人员)并填充 instance_types 的索引值。

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

【问题讨论】:

  • 使用count 作为键的map(object)) 类型比使用for 表达式数据转换的map(list(object)) 更容易。有什么阻碍你选择那种类型吗?
  • 不,我可以随意更改对象结构。您能否在您的建议中展示如何实现这一目标。请记住,对象并不是一个详尽的列表。计数相同的情况下可能会有更多
  • 好的,所以我现在实际上更清楚地看到了您想要实现的目标。您希望将 k8s 工作程序和控制平面节点概括为单个 TF AWS 实例资源。我的评论现在稍微不那么有效了,但无论如何都按照相同的思路回答。
  • 再次关闭实例数量是不够的,因为这两个之外的几种不同实例类型将包含在此映射中
  • 不确定这与我解释前进道路的 cmets 有何关系,但答案很快就会完成。

标签: terraform terraform-provider-aws


【解决方案1】:

使用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

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

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

【讨论】:

  • 现在试试 - 非常感谢您的回复
  • @stackoverflow 我知道你必须进行数据转换才能执行这样的嵌套迭代器看起来有多烦人,但它实际上是记录在案的算法,直到本机功能存在(希望很快):@987654321 @
  • @stackoverflow 对于 map 变量上的 for 表达式中的临时 lambda 迭代器作用域变量,我的大脑放屁了。答案固定。
  • @stackoverflow 添加到答案。
  • @stackoverflow 不,splat 运算符 * 用于在版本
猜你喜欢
  • 2019-06-28
  • 2020-03-05
  • 1970-01-01
  • 2021-07-25
  • 1970-01-01
  • 2021-07-01
  • 2021-03-10
  • 2021-07-16
  • 2022-01-11
相关资源
最近更新 更多