不正确的私有 IP EC2 实例,地形



使用 terraform 在 AWS 中部署多个实例。编写代码是为了使用特定的专用 IP 范围。代码循环访问一个范围以提供 IP 上的最后两位数字。

IP_AA_MGMT_Windows = [for i in range(1, var.Number_of_AA_Candidates +1 ) : format("%s%02d", "10.10.8.1", i)]

有关信息,此子网所属的子网具有以下 CIDR 分配

cidr_block = "10.10.8.0/22"

这给出了 10.10.8.0 - 10.10.11.255 的 ip 范围

创建实例时没有实际问题。预期的专用 IP 以与网络接口相同的方式分配。

resource "aws_instance" "Windows" {
instance_type               = "t2.large"
subnet_id                   = aws_subnet.windows.id
vpc_security_group_ids = [aws_security_group.AA_Eng_Windows[count.index].id]
key_name                    = aws_key_pair.ENG-DEV.id
count                       = var.Number_of_AA_Candidates
private_ip                  = local.IP_AA_WINLAN_Windows[count.index]
associate_public_ip_address = false

将创建一个额外的网络接口并将其附加到实例。

resource "aws_network_interface" "Windows_Access_Interface" {  
subnet_id                   = aws_subnet.management.id
private_ip                  = local.IP_AA_MGMT_Windows[count.index]
security_groups             = [aws_security_group.Windows.id]
count                       = var.Number_of_AA_Candidates
attachment {
instance                  = aws_instance.Windows[count.index].id
device_index              = 1
}

所有这些都根据地形正确部署。直到您检查 AWS 中的私有 IP 或通过地形状态显示您意识到网络接口资源已创建,但私有 IP 不正确,而不是代码中预置的私有 IP。注意。地形规划提供的输出表明 IP 分配没有问题。

下面是 terrafrom show 命令的一些输出。

# aws_network_interface.Windows_Access_Interface[0]:
resource "aws_network_interface" "Windows_Access_Interface" {
interface_type            = "interface"
private_ip                = "10.10.10.72"
private_ip_list           = [
"10.10.10.72",
]
private_ip_list_enabled   = false
private_ips               = [
"10.10.10.72",
]

注意 为了安全起见,节目中的某些细节已被故意删除。

现在的问题是,是什么原因造成的?

这里有一些要点需要考虑。首先是每个 VPC 中有五个保留地址 [1]:

每个子网 CIDR 块中的前四个 IP 地址和最后一个 IP 地址不可供您使用,并且无法分配给资源,例如 EC2 实例。

因此,这意味着您必须开始计算可从10.10.8.4分配的地址。这进一步意味着在范围函数中,计数必须在 3 之后开始:

IP_AA_MGMT_Windows = [for i in range(4, var.Number_of_AA_Candidates + 1 ) : format("%s%02d", "10.10.8.1", i)]

由于 IP 地址不是真正的字符串,因此format函数和%02d只会添加0,并且根据Number_of_AA_Candidates字符串末尾添加一定数量的十进制数字。例如,如果Number_of_AA_Candidates等于2,这将产生以下 IP 地址:

> local.IP_AA_MGMT_Windows
[
"10.10.8.101",
"10.10.8.102",
]

请注意,这是针对从 1 开始的原始range。这看起来很好,但请考虑您将添加一个两位数数字(甚至三位数数字以将点带回家)的情况。此外,range的第二部分很好,除非您将Number_of_AA_Candidates设置为大于或等于最大 IP 地址数的值。如果您以某种方式计算错误,范围将超出,并且将创建的 IP 地址将不是有效的 IP 地址。为确保不会超出 CIDR 范围内可用 IP 的最大数量,您可以使用以下公式计算该数字:

2^10 - 5 

10 是从最大位数 32 中扣除子网位后剩余的位数。5 是不能使用的 IP 地址数。这为您提供了 1019 个可能的主机地址。为了确保这种情况不会发生,您可以为range函数的第二部分引入三元运算符:

IP_AA_MGMT_Windows = [for i in range(4, (var.Number_of_AA_Candidates > 1019 ? 1019 : var.Number_of_AA_Candidates + 1) ) : format("%s%02d", "10.10.8.1", i)]

现在,这是两个问题已解决。第三个也是最后一个问题是format函数。为了仅使用可用的IP地址并避免使用format,我建议尝试cidrhost内置函数[2]。cidrhost语法为:

CIDRHOST(前缀,主机编号)

hostnum部分表示 CIDR 范围内所需的主机 IP 地址。例如,如果您要执行以下操作:

cidrhost("10.10.8.0/22", 1)

这将返回范围中的第一个 IP 地址。对于等于 2hostnum,它将返回 2nd,依此类推。

要正确使用它,您必须修改局部变量,使其如下所示:

IP_AA_MGMT_Windows = [for i in range(4, (var.Number_of_AA_Candidates > 1019 ? 1019 : var.Number_of_AA_Candidates + 1)) : cidrhost("10.10.8.0/22", i)]

这适用于主机 IP 地址最大数量之前的任何数字。最后,即使我们知道有 5 个 IP 地址不能使用,cidrhost对此一无所知,并且总是从 CIDR 范围内的第一个数字开始计数到最后一个数字,因此最后一个表达式必须使用 1023 个地址,因为我们不想包含广播地址(覆盖起始 IP 地址,因为我们从 4 开始):

IP_AA_MGMT_Windows = [for i in range(4, (var.Number_of_AA_Candidates > 1023 ? 1023 : var.Number_of_AA_Candidates + 1)) : cidrhost("10.10.8.0/22", i)]

编辑:在聊天中进行讨论后,我们发现aws_network_interface中的论点存在问题(即使terraform没有抱怨)。问题中的参数是private_ip,而提供程序将其列为字符串列表 [3]private_ips。将其更改为:

private_ips = [ local.IP_AA_MGMT_Windows[count.index] ]

应用程序按预期工作。

<小时 />

[1] https://docs.aws.amazon.com/vpc/latest/userguide/configure-subnets.html#subnet-sizing

[2] https://www.terraform.io/language/functions/cidrhost

[3] https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_interface#private_ips

相关内容

  • 没有找到相关文章

最新更新