英文:
Using Rendered Cloud-Init with Node Public DNS in Terraform
问题
I am trying to use cloud-init and terraform to execute scripts on first boot of my instance. A simplified version of what I'm trying to do looks like the following:
#cloud-config
runcmd:
- echo { node_name}
data "template_file" "user_data" {
template = file("../../cloud-init/init-vm.yaml")
# Set variables for the template
vars = {
bacalhauservice = aws_instance.instance.public_dns
}
}
resource "aws_instance" "instance" {
ami = var.instance_ami
instance_type = var.instance_type
subnet_id = var.subnet_public_id
vpc_security_group_ids = var.security_group_ids
key_name = var.key_pair_name
availability_zone = var.availability_zone
user_data = data.template_file.user_data.rendered
}
This doesn't work - it's circular. What are my options?
英文:
I am trying to use cloud-init and terraform to execute scripts on first boot of my instance. A simplified version of what I'm trying to do looks like the following:
#cloud-config
runcmd:
- echo { node_name}
data "template_file" "user_data" {
template = file("../../cloud-init/init-vm.yaml")
# Set variables for the template
vars = {
bacalhauservice = aws_instance.instance.public_dns
}
}
resource "aws_instance" "instance" {
ami = var.instance_ami
instance_type = var.instance_type
subnet_id = var.subnet_public_id
vpc_security_group_ids = var.security_group_ids
key_name = var.key_pair_name
availability_zone = var.availability_zone
user_data = data.template_file.user_data.rendered
}
This doesn't work - it's circular. What are my options?
答案1
得分: 1
以下是翻译的内容:
无法将EC2实例的user_data
值包含在同一实例的IP地址中,因为IP地址直到创建EC2实例的API调用之后才分配,而这个API调用必须包括user_data
值。
因此,您需要找到解决问题的不同方法。有几种不同的选项:
-
如果您只需要代码运行的同一实例的IP地址,那么您不需要在
user_data
字符串中包含它,因为在您提供的任何代码运行时,EC2实例必须已经知道自己的IP地址,因为它已经能够请求user_data
脚本。您可以在所选AMI的操作系统中使用标准功能来确定分配的IP地址。 -
如果您需要此实例以及其他相关IP地址的IP地址,那么一个常见的答案是从启动脚本内部调用EC2 API来访问该信息。为此,您需要为EC2实例分配一个IAM实例配置文件,该配置文件具有调用您选择使用的任何EC2 API操作的权限。
例如,您可以选择使用
ec2:DescribeInstances
来查找属于特定安全组的所有EC2实例,然后确保将您想要包括的所有实例添加到该安全组,以便您可以在运行时动态发现它们的IP地址。如果采用这种策略,那么您需要决定如何处理EC2实例不会同时启动的事实,因此每个实例将看到不同的可用EC2实例子集。一个可能的答案是每一两分钟有礼貌地轮询API,以便您可以看到哪些实例已添加或删除,然后动态地对这些变化做出反应。这种方法还使得在以后需要使用EC2自动缩放时更加可行,因为您的系统将能够自动响应自动缩放系统所做的实例更改。
-
最后一个选项是在创建将使用它们的EC2实例之前单独预分配私有IP地址,这样您可以使用网络接口的私有IP来填充您的模板。
关于这种可能性的更多信息,请参阅Terraform如何为一组AWS EC2实例保留相同的公共IP地址。
此外,请注意,template_file
及其所属的提供程序已经被弃用很长时间了。现代替代方法是内置函数templatefile
,您可以像这样使用:
user_data = templatefile("${path.module}/../../cloud-init/init-vm.yaml", {
bacalhauservice = network_interface.example.private_ip
})
英文:
It isn't possible for the user_data
value for an EC2 instance to include the IP address of that same instance, because the IP address isn't allocated until after the API call to create the EC2 instance, which must include the user_data
value.
Therefore you will need to find a different approach to solve your problem. There are a few different options:
-
If you only need the IP address of the same instance running the code anyway, then you don't need to include it in the
user_data
string because by the time any code you supply there is running the EC2 instance must already know its own IP address from having been able to request theuser_data
script in the first place. You can use standard features of the operating system in your chosen AMI to determine the allocated IP address. -
If you need IP addresses of this and other related IP addresses then one common answer is to access that information by calling the EC2 API from inside your boot script. To do this you will need to assign your EC2 instance an IAM instance profile which has access to call whatever EC2 API actions you choose to use.
For example, you could choose to use
ec2:DescribeInstances
to find all of the EC2 instances belonging to a particular security group, and then make sure you add all of the instances you want to include to that security group so you can discover their IP addresses dynamically at runtime.If you adopt this strategy then you will need to decide how to handle the fact that the EC2 instances won't all start up simultaneously and so each one will see a different subset of available EC2 instances. One possible answer is to politely poll the API every minute or two so that you can see which instances have been added or removed, and then react to those changes dynamically. This approach also makes it more feasible to use EC2 autoscaling if you need to do that later, since your system will be able to respond automatically to changes to the instances made by the autoscaling system.
-
A final option is to preallocate private IP addresses separately from creating the EC2 instances that will use them, in which case you can use the private IP of the network interface to populate your template.
For more on that possibility, see How to keep the same public IP addresses for a set of AWS EC2 instances with Terraform.
Also please note that template_file
and the provider it belongs to have been deprecated for a long time. The modern replacement is the built-in function templatefile
, which you can use like this:
user_data = templatefile("${path.module}/../../cloud-init/init-vm.yaml", {
bacalhauservice = network_interface.example.private_ip
})
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论