【问题标题】:Automatically create a subnet for each AWS availability zone in Terraform在 Terraform 中为每个 AWS 可用区自动创建一个子网
【发布时间】:2021-01-07 11:32:00
【问题描述】:

有没有更好的方法来优化下面的代码,这样我就不必一次又一次地询问可用区,而是可以一次完成。由于该区域是可变的,因此我无法定义硬编码的可用区。请问各位,我希望我的公共子网是/24

provider "aws" {
    region = var.region
}

resource "aws_vpc" "app_vpc" {
  cidr_block           = var.vpc_cidr
  enable_dns_support   = true
  enable_dns_hostnames = true
  tags = {
    Name = var.vpc_name
  }
}


data "aws_availability_zones" "available" {
  state = "available"
}

#provision public subnet
resource "aws_subnet" "public_subnet_01" {
  vpc_id     = aws_vpc.app_vpc.id
  cidr_block = var.public_subnet_01
  availability_zone = data.aws_availability_zones.available.names[0]
  tags = {
    Name = "public_subnet_01"
  }
  depends_on = [aws_vpc_dhcp_options_association.dns_resolver]
}
resource "aws_subnet" "public_subnet_02" {
  vpc_id     = aws_vpc.app_vpc.id
  cidr_block = var.public_subnet_02
  availability_zone = data.aws_availability_zones.available.names[1]
  tags = {
    Name = "public_subnet_02"
  }
  depends_on = [aws_vpc_dhcp_options_association.dns_resolver]
}
resource "aws_subnet" "public_subnet_03" {
  vpc_id     = aws_vpc.app_vpc.id
  cidr_block = var.public_subnet_03
  availability_zone = data.aws_availability_zones.available.names[2]
  tags = {
    Name = "public_subnet_03"
  }
  depends_on = [aws_vpc_dhcp_options_association.dns_resolver]
}

【问题讨论】:

    标签: amazon-web-services terraform


    【解决方案1】:

    aws_availability_zones 数据源需要考虑的一个重要风险是可用区域集可能会随时间而变化,因此编写配置非常重要,这样您就不会陷入 Terraform 认为的情况您打算替换当前正在使用的子网,因此无法销毁。

    其中一个关键部分是确保 Terraform 了解每个子网都属于特定的可用区,以便当可用区集发生变化时,Terraform 可以为新的可用区添加新子网或删除现有的可用区已删除的可用区的子网,而不会影响其他未更改的可用区。实现这一目标的最简单方法是将resource for_each 与可用区集一起使用:

    resource "aws_subnet" "public" {
      for_each = aws_avaiability_zones.available.names
    
      # ...
    }
    

    上面将声明子网实例,每个实例的地址都包含可用区名称,如下所示:

    • aws_subnet.public["eu-west-1a"]
    • aws_subnet.public["eu-west-1b"]
    • aws_subnet.public["eu-west-1e"]

    由于它们由可用区名称标识,因此 Terraform 可以看到每个子网都属于特定的可用区。

    特别是对于子网,还有一个额外的挑战:我们必须为每个子网分配其自己的 CIDR 块,这意味着我们需要一种系统的方法来将 IP 地址空间分配给可用区,这样网络就不会因未来的变化而重新编号到可用区域集。

    the aws_availability_zone data source 的文档包括一个声明映射表的示例,该映射表为每个区域和每个可用区分配一个 1 到 14 之间的数字,然后用于填充 IP 地址的八位字节之一以创建单独的前缀每个(地区,AZ)对。该示例仅创建一个 VPC 和一个子网,但我们可以通过使用 for_each 来扩展它,为每个可用区执行此操作,只要我们在使用新区域或新区域时更新映射表分配了可用区后缀字母(每个最多 14 个):

    variable "region_number" {
      # Arbitrary mapping of region name to number to use in
      # a VPC's CIDR prefix.
      default = {
        us-east-1      = 1
        us-west-1      = 2
        us-west-2      = 3
        eu-central-1   = 4
        ap-northeast-1 = 5
      }
    }
    
    variable "az_number" {
      # Assign a number to each AZ letter used in our configuration
      default = {
        a = 1
        b = 2
        c = 3
        d = 4
        e = 5
        f = 6
        # and so on, up to n = 14 if that many letters are assigned
      }
    }
    
    data "aws_region" "current" {}
    
    # Determine all of the available availability zones in the
    # current AWS region.
    data "aws_availability_zones" "available" {
      state = "available"
    }
    
    # This additional data source determines some additional
    # details about each VPC, including its suffix letter.
    data "aws_availability_zone" "all" {
      for_each = aws_avaiability_zones.available.names
    
      name = each.key
    }
    
    # A single VPC for the region
    resource "aws_vpc" "example" {
      cidr_block = cidrsubnet("10.1.0.0/16", 4, var.region_number[data.aws_region.current.name])
    }
    
    # A subnet for each availability zone in the region.
    resource "aws_subnet" "example" {
      for_each = aws_availability_zone.all
    
      vpc_id            = aws_vpc.example.id
      availability_zone = each.key
      cidr_block        = cidrsubnet(aws_vpc.example.cidr_block, 4, var.az_number[each.value.name_suffix])
    }
    

    例如,如果我们在us-west-2 工作并且有可用区us-west-2a 和us-west-2c,则上面会声明:

    • 带有 CIDR 块 10.1.48.0/20 的单个 aws_vpc.example,其中 48 是十六进制 0x30 的十进制表示,其中 3 是 us-west-2 的数字。
    • us-west-2a 中的子网 aws_subnet.example["us-west-2a"] 带有 CIDR 块 10.1.49.0/24,其中 49 是十六进制 0x31 的十进制表示。
    • us-west-2c 中的子网 aws_subnet.example["us-west-2c"] 带有 CIDR 块 10.1.51.0/24,其中 51 是十六进制 0x33 的十进制表示。

    请注意,10.1.50.0/24 没有子网,因为 50(十六进制 0x32)是为假设的 us-west-2b 保留的。通过按子网字母静态分配这些地址,我们可以确保它们不会随着时间的推移而随着可用性区域的添加和删除而改变。

    【讨论】:

      【解决方案2】:

      您可以使用count 和cidrsubnets 自动创建子网。

      一个例子是:

      resource "aws_subnet" "public_subnet" {
      
        count             = length(data.aws_availability_zones.available.names)
      
        vpc_id            = aws_vpc.app_vpc.id
        cidr_block        = cidrsubnet(aws_vpc.app_vpc.cidr_block, 8, count.index)
        availability_zone = data.aws_availability_zones.available.names[count.index]
        
        tags = {
          Name = "public_subnet_${count.index}"
        }
        
        depends_on = [aws_vpc_dhcp_options_association.dns_resolver]
      }
      

      上面将自动在每个 AZ 中创建子网以及 assing cidr 块(/24,假设 vpc 为 /16)。

      【讨论】:

      • 我知道,但我无法弄清楚如何提供 /24 能否请您帮助我也可以获取 cidr 的用户数据吗?
      • 嗨 cidrsubnet(aws_vpc.app_vpc.cidr_block, 8, count.index) 这会从您的 VPC 的苹果酒系列中创建 /24。您想将自己的范围硬编码为变量吗?
      • 是的,我想从用户那里获取数据,这样可以在不依赖 cidr 的情况下多次使用相同的设置
      猜你喜欢
      • 2019-11-22
      • 1970-01-01
      • 1970-01-01
      • 2021-12-09
      • 2018-12-14
      • 1970-01-01
      • 1970-01-01
      • 2018-07-29
      • 2019-02-27
      相关资源
      最近更新 更多