【问题标题】:Terraform target aws_volume_attachment with only its corresponding aws_instance resource from a listTerraform 目标 aws_volume_attachment 仅具有列表中对应的 aws_instance 资源
【发布时间】:2017-07-07 07:54:55
【问题描述】:

我无法通过-target 定位单个aws_volume_attachment 及其对应的aws_instance。 问题是 aws_instance 是使用 count.index 从列表中获取的,这会强制 terraform 刷新该列表中的所有 aws_instance 资源。

在我的具体案例中,我正在尝试使用 terraform 管理领事集群。 目标是能够通过-target 标志重新初始化单个aws_instance 资源,这样我就可以逐个节点升级/更改整个集群而不会停机。

我有以下 tf 代码:

### IP suffixes
variable "subnet_cidr" { "10.10.0.0/16" }

// I want nodes with addresses 10.10.1.100, 10.10.1.101, 10.10.1.102
variable "consul_private_ips_suffix" {
  default = {
    "0" = "100"
    "1" = "101"
    "2" = "102"
  }
}

###########
# EBS
#
// Get existing data EBS via Name Tag
data "aws_ebs_volume" "consul-data" {
  count = "${length(keys(var.consul_private_ips_suffix))}"

  filter {
    name   = "volume-type"
    values = ["gp2"]
  }

  filter {
    name   = "tag:Name"
    values = ["${var.platform_type}.${var.platform_id}.consul.data.${count.index}"]
  }
}

#########
# EC2
#
resource "aws_instance" "consul" {
  count      = "${length(keys(var.consul_private_ips_suffix))}"

  ...

  private_ip = "${cidrhost(aws_subnet.private-b.cidr_block, lookup(var.consul_private_ips_suffix, count.index))}"
}

resource "aws_volume_attachment" "consul-data" {
  count       = "${length(keys(var.consul_private_ips_suffix))}"

  device_name = "/dev/sdh"
  volume_id   = "${element(data.aws_ebs_volume.consul-data.*.id, count.index)}"
  instance_id = "${element(aws_instance.consul.*.id, count.index)}"
}

这非常适合初始化集群。 现在,我对 consul 节点的 user_data init 脚本进行了更改,并希望逐个节点推出。 我运行 terraform plan -target=aws_volume_attachment.consul_data[0] 来重新初始化节点 0。 这是我遇到上述问题的时候,因为instance_id = "${element(aws_instance.consul.*.id, count.index)}",terraform 会渲染所有aws_instance 资源。

有没有办法“强制” tf 只针对单个 aws_volume_attachment 及其对应的 aws_instance 资源?

【问题讨论】:

    标签: terraform


    【解决方案1】:

    在撰写本文时,这种用法是不可能的,因为正如您所见,aws_instance.consul.*.id 之类的表达式在已应用element 函数。

    -target 选项不适合日常使用,而是仅在特殊情况下提供,例如从意外更改中小心恢复。

    对于这种特定情况,最好使用ignore_changes 生命周期设置来防止在user_data 更改时自动替换实例,如下所示:

    resource "aws_instance" "consul" {
      count      = "${length(keys(var.consul_private_ips_suffix))}"
    
      ...
    
      private_ip = "${cidrhost(aws_subnet.private-b.cidr_block, lookup(var.consul_private_ips_suffix, count.index))}"
    
      lifecycle {
        ignore_changes = ["user_data"]
      }
    }
    

    使用此设置,Terraform 将检测但忽略对 user_data 属性的更改。然后,您可以通过手动污染一次一个资源来获得所需的逐步替换行为:

    $ terraform taint aws_instance.consul[0]
    

    在下一个计划中,Terraform 将看到此资源实例被污染并生成一个替换它的计划。这使您可以直接控制何时替换资源,因此您可以确保例如consul leave 步骤有机会首先运行,或者您需要执行的任何其他清理操作。

    推荐使用此工作流程而不是 -target,因为它明确了替换步骤。 -target 在协作环境中可能会令人困惑,因为没有证据表明它的使用,因此没有明确解释如何达到当前状态。而taint 则将您的意图明确标记为其他团队成员可以看到的状态,然后通过正常的计划/应用步骤替换资源。

    【讨论】:

      猜你喜欢
      • 2018-07-09
      • 2020-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-06
      • 2021-07-21
      • 1970-01-01
      • 2020-08-08
      相关资源
      最近更新 更多