如何在一个远程执行器、terraform、aws 中获取所有实例的私有 IP

How to get private IPs of all instances in one remote-exec, terraform, aws

提问人:Sonia 提问时间:6/20/2023 最后编辑:theherkSonia 更新时间:6/20/2023 访问量:125

问:

我使用 terraform 创建了 2 种类型的 EC2 实例;实例计数始终不同。我想将所有实例的私有 IP 获取到其中一个实例到一个文件中。

目前,我创建了第一个实例的 IP,但无论数量如何,我都没有得到其余的 IP。

resource "aws_instance" "name1" {
  ...
  count         = 3
  ...
}

resource "aws_instance" "name2" {
  ...
  count         = 1
  ...
  provisioner "remote-exec" {
    inline = [
      ...
      "sudo echo '${aws_instance.name1[count.index].private_ip}' >> test.txt",
      "sudo echo '${aws_instance.name2[count.index].private_ip}' >> test2.txt",
    ]
  }
}

所以 test2.txt 获取创建的那个实例的 1 个 IP,这很好。 但是 test.txt 只获取三个实例中创建的第一个实例的 IP。我正在尝试不同的方法,但我认为我可能以错误的方式接近它。for_each

另一种方法是使用 local-exec 在本地保存 IP,但随后我必须运行远程脚本来获取文件,并且我运行时遇到了手动工作的问题(我运行 terraform 的地方可能会发生变化,因此必须更改远程 scp 命令,所以 remote-exec 会更干净)。

amazon-web-services amazon-ec2 terraform 远程执行

评论

1赞 theherk 6/20/2023
我实际上不清楚你想做什么。实际的最终目标是什么?实际上,使用任何一个配置程序都很少是一个好主意。我的意思是,这是行不通的,因为您只使用来自一种资源的计数索引,但我相信,在弄清楚您实际要做什么之前,这有点无关紧要。
0赞 Sonia 6/20/2023
我正在尝试将每个新创建的实例的 IP 获取到其中一个实例上的 /etc/hosts。我得到的第一个实例的 IP 数为 3,但其余的都没有。我也在尝试这样的事情,但不能在 remote-exec 中为我在“${aws_instance.name1[@]}”;做回声“$i”;做

答:

1赞 theherk 6/20/2023 #1

我不确定你所寻求的东西在地球形态中是否完全可能。您将需要在实例上编写一些额外的脚本来扫描其他实例或在某个地方。每个实例如何知道在它之后创建的实例?

但是,如果您同意让实例的所有 IP 地址和当前实例的 IP 地址运行置备程序,则应该可以通过以下操作实现:name1name2

resource "aws_instance" "name1" {
  count = 3
}

resource "aws_instance" "name2" {
  count = 1

  provisioner "remote-exec" {
    inline = [
      for ip in concat(aws_instance.name1[*].private_ip, [self.private_ip])
      : "echo ${ip} >> ips.txt"
    ]
  }
}

但我还没有测试过。然而,它不受循环依赖关系的影响。不过,我强烈建议通过输出获取 IP 地址,然后将其推送到 SSM 参数或 S3 blob。然后,您可以让 cloud-init 用户数据提取这些值来写入 hosts 文件。

您可以获取所有 IP 地址,例如:

resource "aws_instance" "name1" {
  count = 3
}

resource "aws_instance" "name2" {
  count = 1
}

output "ips" {
  value = concat(aws_instance.name1[*].private_ip, aws_instance.name2[*].private_ip)
}

代替此输出,您可以使用相同的列表将值存储在运行 cloud-init 时实例可访问的位置。


我的意思的一个例子是这样的:

resource "aws_instance" "name1" {
  count = 3

  user_data = base64encode(templatefile("${path.module}/cloud-init.sh", {
    SSM_PATH = "ec2/ips"
  }))
}

resource "aws_instance" "name2" {
  count = 1

  user_data = base64encode(templatefile("${path.module}/cloud-init.sh", {
    SSM_PATH = "ec2/ips"
  }))
}

resource "aws_ssm_parameter" "ips" {
  name  = "ec2/ips"
  type  = "String"
  value = concat(aws_instance.name1[*].private_ip, aws_instance.name2[*].private_ip)
}

其中 cloud-init.sh 是:

#!/usr/bin/env sh
sleep 30
# Better to wait until the parameter is present.
# But this is a bad way to do it.
aws ssm get-parameter --name "${SSM_PATH}" | jq -r .Parameter.Value
echo "some loop that writes your /etc/hosts file"

但我还没有验证这一点,所以你的里程可能会有所不同。