我在Terraform中创建了三个模块,一个用于EC2、VPC和安全组。我为这三个模块运行了全栈,并在EC2模块中使用了安全组和VPC模块的输出,但我得到了错误:
creating EC2 Instance: InvalidSubnetID.NotFound: The subnet ID 'module.vpc_main.primary_private_subnets_id.value[0]' does not exist
status code: 400, request id: d94befb9-a846-47f9-a7c2-c588996a723c
on .terraform/modules/main_ec2/main.tf line 66, in resource "aws_instance" "create_instance":
66: resource "aws_instance" "create_instance" {
VPC模块的输出:
output "primary_public_subnets_id" {
description = "public subnet ID"
value = aws_subnet.primary_public_subnets[*].id
}
output "primary_private_subnets_id" {
description = "public subnet ID"
value = aws_subnet.primary_private_subnets[*].id
}
状态文件中的输出
outputs": {
"primary_private_subnets_id": {
"value": [
"subnet-098d3aab6a102656c",
"subnet-073699d0e266072d6",
"subnet-07755f92e02ca8756",
"subnet-0a2f21a6e9b80d91e"
],
"type": [
"tuple",
[
"string",
"string",
"string",
"string"
]
]
},
"primary_public_subnets_id": {
"value": [
"subnet-0aea672a2f19cee51",
"subnet-0a014df85bc56acd3"
],
"type": [
"tuple",
[
"string",
"string"
]
]
},
变量
variable "subnet_id" {
type = list(string)
default = [ "module.vpc_main.primary_public_subnets_id[0]", "module.vpc_main.primary_private_subnets_id[1]" ]
}
EC2模块的一部分:
resource "aws_instance" "create_instance" {
ami = "${element(data.aws_ami.ami_id.*.id, count.index)}"
instance_type = var.EC2_Type[count.index]
subnet_id = var.subnet_id[count.index]
associate_public_ip_address = var.associate_public_ip_address[count.index]
vpc_security_group_ids = [ var.vpc_security_group_ids[count.index] ]
key_name = "${local.name}-KP-${var.Server_Name[count.index]}"
iam_instance_profile = aws_iam_instance_profile.iam_profile.name
private_ip = var.EC2_IP[count.index]
count = length(var.ami_name)
}
EC2调用模块:
module "main_ec2" {
source = "/home/reham/Data/projectes/terraform/modules/EC2Module"
EC2_Type = var.EC2_Type
EC2_IP = var.EC2_IP
subnet_id = var.subnet_id
associate_public_ip_address = var.associate_public_ip_address
vpc_security_group_ids = var.vpc_security_group_ids
}
请注意,任何模块都可以以良好的方式单独工作。请问我如何从Terraform中模块输出的元组中获得任何值?
如果我们认为VPC模块也被调用,那么您不必将默认值添加到变量subnet_id
中。相反,您可以将变量定义保留为没有任何值:
variable "subnet_id" {
type = list(string)
}
请注意,您使用的是list(string)
类型的变量,而EC2实例的参数只需要一个值,因此它的类型为string
。此外,在EC2模块中,您将count
元参数设置为取决于变量ami_name
的长度。所以,即使你做出了正确的价值分配,我认为你也会得到很多意想不到的结果。在对EC2模块进行任何调用之前,我建议将其修复为更像:
resource "aws_instance" "create_instance" {
count = length(var.subnet_id)
ami = element(data.aws_ami.ami_id.*.id, count.index)
instance_type = var.EC2_Type[count.index]
subnet_id = var.subnet_id[count.index]
associate_public_ip_address = var.associate_public_ip_address[count.index]
vpc_security_group_ids = [var.vpc_security_group_ids[count.index]]
key_name = "${local.name}-KP-${var.Server_Name[count.index]}"
iam_instance_profile = aws_iam_instance_profile.iam_profile.name
private_ip = var.EC2_IP[count.index]
}
将元参数移动到resource
块的顶部也是一种很好的做法,因为它对读者更可见。我已经将count
设置为使用subnet_id
变量的长度,因为我猜您希望在每个子网中都有一个EC2实例。
另一件不清楚的事情是,您是否希望在私有子网、公共子网或两者中都有EC2实例。为了简单起见,假设您希望它们位于公共子网中(因为您已经定义了associate_public_ip_address
参数(。在这里,您犯了另一个错误,即试图将bool
参数(只能有true
或false
值(设置为使用具有count.index
(var.associate_public_ip_address[count.index]
(的变量。除非变量associate_public_ip_address
是布尔值列表,否则这将不起作用。如果是这样,则该代码可以保持原样。最后,但并非最不重要的是,由于VPC模块正在提供您想要的输出,因此使用这些输出的方法如下:
module "vpc" {
... your module call goes here ...
}
module "main_ec2" {
source = "/home/reham/Data/projectes/terraform/modules/EC2Module"
EC2_Type = var.EC2_Type
EC2_IP = var.EC2_IP
subnet_id = module.vpc.primary_public_subnets_id
associate_public_ip_address = var.associate_public_ip_address
vpc_security_group_ids = var.vpc_security_group_ids
}
如果VPC模块提供了其他输出(例如,安全组ID(,您可以将其称为与子网ID相同的输出:
module.vpc.<name of the output>
即使有了我答案中的细节,也不能保证它会起作用。要使代码正常工作,需要进行大量的重构。此外,我强烈建议您理解资源期望中的值参数的类型[1](string
、list(string)
、bool
等(。您还需要确保了解如何引用模块输出[2]。
[1]https://www.terraform.io/language/expressions/types
[2]https://www.terraform.io/language/expressions/references#child-模块输出