Terraform目标aws_volume_attachment仅包含列表中对应的aws_instance资源

时间:2017-07-06 11:42:25

标签: terraform

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

在我的具体案例中,我正在尝试管理带有terraform的consul集群。 目标是能够通过aws_instance标志重新启动单个-target资源,这样我就可以逐节点地升级/更改整个集群,而无需停机。

我有以下代码:

### 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。 这是当我遇到上述问题时,由于aws_instance,terraform会呈现所有instance_id = "${element(aws_instance.consul.*.id, count.index)}"资源。

有没有办法强迫"强迫"如果只针对单个aws_volume_attachment,只有相应的aws_instance资源?

1 个答案:

答案 0 :(得分: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在其他团队成员可以看到的状态下明确标记您的意图,然后通过正常的计划/应用步骤替换资源。