Netmasks and Subnets 文档部分试图提供足够的信息来了解此函数与 IP 地址约定的关系,并提到 Unix 命令ipcalc 作为一种可视化 CIDR 网络掩码表示方式的方法。
让我们看看ipcalc 如何描述您的起始前缀和您的两个预期子网前缀:
$ ipcalc 10.32.0.0/16
Address: 10.32.0.0 00001010.00100000. 00000000.00000000
Netmask: 255.255.0.0 = 16 11111111.11111111. 00000000.00000000
Wildcard: 0.0.255.255 00000000.00000000. 11111111.11111111
=>
Network: 10.32.0.0/16 00001010.00100000. 00000000.00000000
HostMin: 10.32.0.1 00001010.00100000. 00000000.00000001
HostMax: 10.32.255.254 00001010.00100000. 11111111.11111110
Broadcast: 10.32.255.255 00001010.00100000. 11111111.11111111
Hosts/Net: 65534 Class A, Private Internet
$ ipcalc 10.32.1.0/27
Address: 10.32.1.0 00001010.00100000.00000001.000 00000
Netmask: 255.255.255.224 = 27 11111111.11111111.11111111.111 00000
Wildcard: 0.0.0.31 00000000.00000000.00000000.000 11111
=>
Network: 10.32.1.0/27 00001010.00100000.00000001.000 00000
HostMin: 10.32.1.1 00001010.00100000.00000001.000 00001
HostMax: 10.32.1.30 00001010.00100000.00000001.000 11110
Broadcast: 10.32.1.31 00001010.00100000.00000001.000 11111
Hosts/Net: 30 Class A, Private Internet
$ ipcalc 10.32.3.0/27
Address: 10.32.3.0 00001010.00100000.00000011.000 00000
Netmask: 255.255.255.224 = 27 11111111.11111111.11111111.111 00000
Wildcard: 0.0.0.31 00000000.00000000.00000000.000 11111
=>
Network: 10.32.3.0/27 00001010.00100000.00000011.000 00000
HostMin: 10.32.3.1 00001010.00100000.00000011.000 00001
HostMax: 10.32.3.30 00001010.00100000.00000011.000 11110
Broadcast: 10.32.3.31 00001010.00100000.00000011.000 11111
Hosts/Net: 30 Class A, Private Internet
在ipcalc 的符号中,二进制表示中的空格表示地址的网络部分和主机部分之间的边界。我们可以看到,正如您在示例中所展示的那样,两个期望的结果在网络部分中的位比基地址多 11 位。
让我们以其中一个为例来确定“netnum”是什么。我们将使用10.32.1.0/27,并将基地址和子网地址中的“地址”行放在一起,以便更清楚地看到区别:
Address: 10.32.0.0 00001010.00100000. 00000000.00000000
Address: 10.32.1.0 00001010.00100000.00000001.000 00000
netnum 的值是在第二种情况下由这 11 个额外的二进制数字表示的数字:00000001000。该二进制数的十进制等效值为 8,因此该二进制数的 netnum 将是 8,我们可以通过在 terraform console 提示符下调用 cidrsubnet 来确认:
> cidrsubnet("10.32.0.0/16", 11, 8)
"10.32.1.0/27"
为了概括这一点,请注意在 IP 地址中第三个十进制数字上方的二进制表示中,仅代表网络号的一部分:在00000001.000 中,我们可以看到有三个二进制数字属于第四个八位字节.因为第四个二进制位表示八位的数量,所以一般规则是要找到将为第三个八位字节提供特定值的netnum,您需要将该值乘以八。三乘以八是 24,所以如果我们将 netnum 设置为 24,那么我们会得到你想要的另一个前缀:
> cidrsubnet("10.32.0.0/16", 11, 24)
"10.32.3.0/27"
话虽如此,值得注意的是,这种特殊的寻址方案正在“浪费”部分地址空间。如果您将最后三位始终设置为零,那么实际上您只有 8 位的网络编号,因此您只能拥有 256 个网络。如果您想利用网络编号空间的所有 11 位(2,048 个网络),您需要从零开始您的网络编号并从那里正常向上计数,这将密集地占用您的所有网络空间:
> cidrsubnet("10.32.0.0/16", 11, 0)
"10.32.0.0/27"
> cidrsubnet("10.32.0.0/16", 11, 1)
"10.32.0.32/27"
> cidrsubnet("10.32.0.0/16", 11, 2)
"10.32.0.64/27"
> cidrsubnet("10.32.0.0/16", 11, 3)
"10.32.0.96/27"
> cidrsubnet("10.32.0.0/16", 11, 4)
"10.32.0.128/27"
> cidrsubnet("10.32.0.0/16", 11, 5)
"10.32.0.160/27"
> cidrsubnet("10.32.0.0/16", 11, 6)
"10.32.0.192/27"
> cidrsubnet("10.32.0.0/16", 11, 7)
"10.32.0.224/27"
> cidrsubnet("10.32.0.0/16", 11, 8)
"10.32.1.0/27"
因为传统的 IP 地址表示法是从 0 到 255 的四个十进制数字,所以上面的计数可能看起来违反直觉,但在底层二进制表示法中,这只是从零开始向上计数的正常计数,这样可以避免跳过网络编号 0到 7、9 到 15 等等。
如果您正在为一组子网创建一个系统的网络寻址计划,每个子网都有一个特定的目的,您可能会发现使用the hashicorp/subnets/cidr module 提供的更高级别的抽象很有帮助,它只需要位数用于对每个网络进行编号并自行计算合适的 netnum 值:
module "subnets" {
source = "hashicorp/subnets/cidr"
version = "1.0.0"
base_cidr_block = "10.32.0.0/16"
networks = [
{
name = "first",
new_bits = 11
},
{
name = "second",
new_bits = 11
},
]
}
上面会产生一个像这样的network_cidr_blocks 映射:
{
first = "10.32.0.0/27"
second = "10.32.0.32/27"
}
您可以在配置的其他地方写module.subnets.network_cidr_blocks.first 来获取第一个地址。假设您选择有意义的名称而不是我做作的“第一”和“第二”,这将使您的其余配置更易于阅读,因为未来的读者不需要记住每个 IP 地址范围代表什么。