Terraform 推送 Cloudformation 堆栈。如何从参数创建字符串列表

Terraform pushing Cloudformation stacks. How to make a string list from parameters

我正在与有线外壳作斗争。 我需要推送使用 terraform 动态参数化的 cloudformation 堆栈。

我的资源是这样的。

resource "aws_cloudformation_stack" "eks-single-az" {
  count = length(var.single_az_node_groups)
  name = "eks-${var.cluster_name}-${var.single_az_node_groups[count.index].name}"

  template_body = <<EOF
Description: "eks-${var.cluster_name}-${var.single_az_node_groups[count.index].name}"

Resources:
  ASG:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      AutoScalingGroupName: "eks-${var.cluster_name}-${var.single_az_node_groups[count.index].name}"
      VPCZoneIdentifier: ["${var.private_subnet_ids[count.index]}"]
      MinSize: "${lookup(var.single_az_node_groups[count.index], "asg_min", "0")}"
      MaxSize: "${lookup(var.single_az_node_groups[count.index], "asg_max", "10")}"
      HealthCheckType: EC2
      TargetGroupARNs: [] < - here is error. 
      MixedInstancesPolicy:
        InstancesDistribution:
          OnDemandBaseCapacity: "0"
          OnDemandPercentageAboveBaseCapacity: "${lookup(var.single_az_node_groups[count.index], "on_demand_percentage", "0")}"
        LaunchTemplate:
          LaunchTemplateSpecification:
            LaunchTemplateId: "${aws_launch_template.eks-single-az[count.index].id}"
            Version: "${aws_launch_template.eks-single-az[count.index].latest_version}"
          Overrides:
            - 
              InstanceType: m5.large
      Tags:
        - Key: "Name"
          Value: "eks-${var.cluster_name}-${var.single_az_node_groups[count.index].name}"
          PropagateAtLaunch: true
        - Key: "kubernetes.io/cluster/${var.cluster_name}"
          Value: "owned"
          PropagateAtLaunch: true
        - Key: "k8s.io/cluster-autoscaler/enabled"
          Value: "true"
          PropagateAtLaunch: true
        - Key: "k8s.io/cluster-autoscaler/${var.cluster_name}"
          Value: "true"
          PropagateAtLaunch: true
    UpdatePolicy:
      AutoScalingRollingUpdate:
        MinSuccessfulInstancesPercent: 80
        MinInstancesInService: "${lookup(data.external.desired_capacity.result, "eks-${var.cluster_name}-${var.single_az_node_groups[count.index].name}", "0")}"
        PauseTime: PT4M
        SuspendProcesses:
          - HealthCheck
          - ReplaceUnhealthy
          - AZRebalance
          - AlarmNotification
          - ScheduledActions
        WaitOnResourceSignals: true
  EOF

depends_on = [
  aws_launch_template.eks-single-az
]

}

我需要从包含 json 个对象的列表中添加目标组:

single_az_node_groups = [
  {
    "name"          : "workload-az1",
    "instance_type" : "t2.micro",
    "asg_min"       : "1",
    "asg_max"       : "7",
    "target_group_arns" : "arnA, arnB, arnC"
  },
  ...
]

我什么都试过了。问题是我尝试了很多 terraform 函数,并且 terraform 一直在添加一些 cloudformation 不支持的双引号,或者 terraform 不会处理 template_body 因为缺少引号..
你知道我有一些偷偷摸摸的技巧是如何实现的吗?

构建表示序列化数据结构的字符串时,使用 Terraform 的内置序列化函数来构建结果要容易得多,而不是尝试使用字符串模板生成有效的字符串。

在这种情况下,我们可以使用jsonencode to construct a JSON string representing the template_body from a Terraform object value, which then allows using all of the Terraform language expression features来构建它:

  template_body = jsonencode({
    Description: "eks-${var.cluster_name}-${var.single_az_node_groups[count.index].name}",

    Resources: {
      ASG: {
        Type: "AWS::AutoScaling::AutoScalingGroup",
        Properties: {
          AutoScalingGroupName: "eks-${var.cluster_name}-${var.single_az_node_groups[count.index].name}",
          VPCZoneIdentifier: [var.private_subnet_ids[count.index]],
          MinSize: lookup(var.single_az_node_groups[count.index], "asg_min", "0"),
          MaxSize: lookup(var.single_az_node_groups[count.index], "asg_max", "10"),
          HealthCheckType: "EC2",
          TargetGroupArns: flatten([
            for g in local.single_az_node_groups : [
              split(", ", g.target_group_arns)
            ]
          ]),
          # etc, etc
        },
      },
    },
  })

正如您在上面看到的,通过对整个数据结构使用 jsonencode,我们可以使用 Terraform 表达式运算符来构建值。对于上例中的 TargetGroupArns,我使用 the flatten function along with a for expression 将嵌套的 local.single_az_node_groups 数据结构转换为目标组 ARN 字符串的平面列表。


CloudFormation 同时支持 JSON 和 YAML,Terraform 也有一个 yamlencode function,您可以在这里使用它来代替 jsonencode。我选择 jsonencode 既是因为 yamlencode 目前被标记为实验性的(它生成的确切 YAML 格式可能会在以后的版本中改变),也是因为 Terraform 在计划输出中对 JSON 格式有特殊支持它可以显示内部数据结构的结构差异,而不是基于字符串的差异。