|
1 | 1 | ## Subnet calculation logic |
2 | 2 |
|
3 | | -`terraform-aws-dynamic-subnets` creates a set of subnets based on `${var.cidr_block}` input and number of Availability Zones in the region. |
4 | | - |
5 | | -For subnet set calculation, the module uses Terraform interpolation |
6 | | - |
7 | | -[cidrsubnet](https://www.terraform.io/docs/configuration/interpolation.html#cidrsubnet-iprange-newbits-netnum-). |
| 3 | +`terraform-aws-dynamic-subnets` creates a set of subnets based on various CIDR inputs and |
| 4 | +the maximum possible number of subnets, which is `max_subnet_count` when specified or |
| 5 | +the number of Availability Zones in the region when `max_subnet_count` is left at |
| 6 | +its default value of zero. |
8 | 7 |
|
| 8 | +You can explicitly provide CIDRs for subnets via `ipv4_cidrs` and `ipv6_cidrs` inputs if you want, |
| 9 | +but the usual use case is to provide a single CIDR which this module will subdivide into a set |
| 10 | +of CIDRs as follows: |
9 | 11 |
|
| 12 | +1. Get number of available AZ in the region: |
10 | 13 | ``` |
11 | | -${ |
12 | | - cidrsubnet( |
13 | | - signum(length(var.cidr_block)) == 1 ? |
14 | | - var.cidr_block : data.aws_vpc.default.cidr_block, |
15 | | - ceil(log(length(data.aws_availability_zones.available.names) * 2, 2)), |
16 | | - count.index) |
17 | | -} |
| 14 | +existing_az_count = length(data.aws_availability_zones.available.names) |
| 15 | +``` |
| 16 | +2. Determine how many sets of subnets are being created. (Usually it is `2`: `public` and `private`): `subnet_type_count`. |
| 17 | +3. Multiply the results of (1) and (2) to determine how many CIDRs to reserve: |
| 18 | +``` |
| 19 | +cidr_count = existing_az_count * subnet_type_count |
18 | 20 | ``` |
19 | 21 |
|
| 22 | +4. Calculate the number of bits needed to enumerate all the CIDRs: |
| 23 | +``` |
| 24 | +subnet_bits = ciel(log(cidr_count, 2)) |
| 25 | +``` |
| 26 | +5. Reserve CIDRs for private subnets using [`cidrsubnet`](https://www.terraform.io/language/functions/cidrsubnet): |
| 27 | +``` |
| 28 | +private_subnet_cidrs = [ for netnumber in range(0, existing_az_count): cidrsubnet(cidr_block, subnet_bits, netnumber) ] |
| 29 | +``` |
| 30 | +6. Reserve CIDRs for public subnets in the second half of the CIDR block: |
| 31 | +``` |
| 32 | +public_subnet_cidrs = [ for netnumber in range(existing_az_count, existing_az_count * 2): cidrsubnet(cidr_block, subnet_bits, netnumber) ] |
| 33 | +``` |
20 | 34 |
|
21 | | -1. Use `${var.cidr_block}` input (if specified) or |
22 | | - use a VPC CIDR block `data.aws_vpc.default.cidr_block` (e.g. `10.0.0.0/16`) |
23 | | -2. Get number of available AZ in the region (e.g. `length(data.aws_availability_zones.available.names)`) |
24 | | -3. Calculate `newbits`. `newbits` number specifies how many subnets |
25 | | - be the CIDR block (input or VPC) will be divided into. `newbits` is the number of `binary digits`. |
26 | | - |
27 | | - Example: |
28 | | - |
29 | | - `newbits = 1` - 2 subnets are available (`1 binary digit` allows to count up to `2`) |
30 | | - |
31 | | - `newbits = 2` - 4 subnets are available (`2 binary digits` allows to count up to `4`) |
32 | | - |
33 | | - `newbits = 3` - 8 subnets are available (`3 binary digits` allows to count up to `8`) |
34 | | - |
35 | | - etc. |
36 | | - |
37 | | - 1. We know, that we have `6` AZs in a `us-east-1` region (see step 2). |
38 | | - 2. We need to create `1 public` subnet and `1 private` subnet in each AZ, |
39 | | - thus we need to create `12 subnets` in total (`6` AZs * (`1 public` + `1 private`)). |
40 | | - 3. We need `4 binary digits` for that ( 2<sup>4</sup> = 16 ). |
41 | | - In order to calculate the number of `binary digits` we should use `logarithm` |
42 | | - function. We should use `base 2` logarithm because decimal numbers |
43 | | - can be calculated as `powers` of binary number. |
44 | | - See [Wiki](https://en.wikipedia.org/wiki/Binary_number#Decimal) |
45 | | - for more details |
46 | | - |
47 | | - Example: |
48 | | - |
49 | | - For `12 subnets` we need `3.58` `binary digits` (log<sub>2</sub>12) |
50 | | - |
51 | | - For `16 subnets` we need `4` `binary digits` (log<sub>2</sub>16) |
52 | | - |
53 | | - For `7 subnets` we need `2.81` `binary digits` (log<sub>2</sub>7) |
54 | | - |
55 | | - etc. |
56 | | - 4. We can't use fractional values to calculate the number of `binary digits`. |
57 | | - We can't round it down because smaller number of `binary digits` is |
58 | | - insufficient to represent the required subnets. |
59 | | - We round it up. See [ceil](https://www.terraform.io/docs/configuration/interpolation.html#ceil-float-). |
60 | | - |
61 | | - Example: |
62 | | - |
63 | | - For `12 subnets` we need `4` `binary digits` (ceil(log<sub>2</sub>12)) |
64 | | - |
65 | | - For `16 subnets` we need `4` `binary digits` (ceil(log<sub>2</sub>16)) |
66 | | - |
67 | | - For `7 subnets` we need `3` `binary digits` (ceil(log<sub>2</sub>7)) |
68 | | - |
69 | | - etc. |
70 | 35 |
|
71 | | - 5. Assign private subnets according to AZ number (we're using `count.index` for that). |
72 | | - 6. Assign public subnets according to AZ number but with a shift according to the number of AZs in the region (see step 2) |
| 36 | +Note that this means that, for example, in a region with 4 availability zones, if you specify only 3 availability zones |
| 37 | +in `var.availability_zones`, this module will still reserve CIDRs for the 4th zone. This is so that if you later |
| 38 | +want to expand into that zone, the existing subnet CIDR assignments will not be disturbed. If you do not want |
| 39 | +to reserve these CIDRs |
0 commit comments