如何为专用于 Fargate 任务的一组私有和 public 子网重用弹性 IP

How to reuse Elastic IPs for a set of private and public subnets dedicated to Fargate tasks

我得到以下设置来创建 Fargate 设置的网络要求:

resource "aws_vpc" "main" {
  cidr_block = var.cidr
  tags = {
    Environment = var.environment
    DO_NOT_DELETE = true
    CreatedBy = "terraform"
  }
}
 
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id
  tags = {
    Environment = var.environment
    CreatedBy = "terraform"
    Vpc = aws_vpc.main.id
  }
}

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

locals {
  az_count = length(data.aws_availability_zones.region_azs.names)
}

resource "aws_subnet" "private" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = cidrsubnet(aws_vpc.main.cidr_block, 4, count.index)
  availability_zone = data.aws_availability_zones.region_azs.names[count.index]
  count             = local.az_count

  tags = {
    Name = "public-subnet-${data.aws_availability_zones.region_azs.names[count.index]}"
    AvailabilityZone = data.aws_availability_zones.region_azs.names[count.index]
    Environment = var.environment
    CreatedBy = "terraform"
    Vpc = aws_vpc.main.id
    Type = "private"
    DO_NOT_DELETE = true
  }
}
 
resource "aws_subnet" "public" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = cidrsubnet(aws_vpc.main.cidr_block, 4, count.index + local.az_count )
  availability_zone = data.aws_availability_zones.region_azs.names[count.index]
  count             = local.az_count
  map_public_ip_on_launch = true

  tags = {
    Environment = var.environment
    CreatedBy = "terraform"
    Vpc = aws_vpc.main.id
    DO_NOT_DELETE = true
    Type = "public"
  }
}

resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id
  tags = {
    Environment = var.environment
    CreatedBy = "terraform"
    Vpc = aws_vpc.main.id
    Type = "public"
  }
}
 
resource "aws_route" "public" {
  route_table_id         = aws_route_table.public.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.main.id
}
 
resource "aws_route_table_association" "public" {
  count          = local.az_count
  subnet_id      = element(aws_subnet.public.*.id, count.index)
  route_table_id = aws_route_table.public.id
}

resource "aws_nat_gateway" "main" {
  count         = local.az_count
  allocation_id = element(aws_eip.nat.*.id, count.index)
  subnet_id     = element(aws_subnet.public.*.id, count.index)
  depends_on    = [aws_internet_gateway.main]

  tags = {
    Environment = var.environment
    CreatedBy = "terraform" 
    Vpc = aws_vpc.main.id
  }
}
 
resource "aws_eip" "nat" {
  count = local.az_count
  vpc = true

  tags = {
    CreatedBy = "terraform"
    Vpc = aws_vpc.main.id
  }
}

resource "aws_route_table" "private" {
  count  = local.az_count
  vpc_id = aws_vpc.main.id

  tags = {
    Environment = var.environment
    CreatedBy = "terraform"
    Type = "private"
    Vpc = aws_vpc.main.id
  }
}
 
resource "aws_route" "private" {
  count                  = local.az_count
  route_table_id         = element(aws_route_table.private.*.id, count.index)
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id         = element(aws_nat_gateway.main.*.id, count.index)
}
 
resource "aws_route_table_association" "private" {
  count          = local.az_count
  subnet_id      = element(aws_subnet.private.*.id, count.index)
  route_table_id = element(aws_route_table.private.*.id, count.index)
}

resource "aws_security_group" "alb" {
  name   = "${var.resources_name_prefix}-alb-sg"
  vpc_id = aws_vpc.main.id
 
  ingress {
   protocol         = "tcp"
   from_port        = 80
   to_port          = 80
   cidr_blocks      = ["0.0.0.0/0"]
   ipv6_cidr_blocks = ["::/0"]
  }
 
  ingress {
   protocol         = "tcp"
   from_port        = 443
   to_port          = 443
   cidr_blocks      = ["0.0.0.0/0"]
   ipv6_cidr_blocks = ["::/0"]
  }
 
  egress {
   protocol         = "-1"
   from_port        = 0
   to_port          = 0
   cidr_blocks      = ["0.0.0.0/0"]
   ipv6_cidr_blocks = ["::/0"]
  }

  tags = {
    Environment = var.environment
    CreatedBy = "terraform"
    Vpc = aws_vpc.main.id
  }
}

resource "aws_security_group" "ecs_tasks" {
  name   = "${var.resources_name_prefix}-ecs-sg"
  vpc_id = aws_vpc.main.id
 
  ingress {
   protocol         = "tcp"
   from_port        = 3000
   to_port          = 3000
   cidr_blocks      = ["0.0.0.0/0"]
   ipv6_cidr_blocks = ["::/0"]
  }

  egress {
   protocol         = "-1"
   from_port        = 0
   to_port          = 0
   cidr_blocks      = ["0.0.0.0/0"]
   ipv6_cidr_blocks = ["::/0"]
  }

  tags = {
    Environment = var.environment
    CreatedBy = "terraform"
    Vpc = aws_vpc.main.id
  }
}

这对几个可用性区域来说效果很好,但现在我正在为每个区域的每个 AZ 中的 运行 任务动态创建子网,我正在达到每个区域的弹性 IP 的限制。

所以我在尝试创建堆栈时遇到了这个错误:

Error creating EIP: AddressLimitExceeded: The maximum number of addresses has been reached.
       status code: 400

我想知道以下部分:

resource "aws_nat_gateway" "main" {
  count         = local.az_count
  allocation_id = element(aws_eip.nat.*.id, count.index)
  subnet_id     = element(aws_subnet.public.*.id, count.index)
  depends_on    = [aws_internet_gateway.main]

  tags = {
    Environment = var.environment
    CreatedBy = "terraform" 
    Vpc = aws_vpc.main.id
  }
}
 
resource "aws_eip" "nat" {
  count = local.az_count
  vpc = true

  tags = {
    CreatedBy = "terraform"
    Vpc = aws_vpc.main.id
  }
}

如果可行,可以构建为在内部使用单个 EIP 和路由。

我稍微修改了你的代码,但还是一团糟。例如,所有私有子网都称为“public”。它现在创建了两个 NAT。显然,如果您有子网,比方说,6 个 AZ,将有一些 cross-AZ 流量到达这些 NAT。

或者,不要创建跨越这么多可用区的 VPC。通常只有 two-three 个 AZ 用于 VPC。拥有更多,并不是真正需要的。

最后,如果您想保留您的原始设置,您可以请求 AWS 支持为您提供更多的 EIP。

resource "aws_vpc" "main" {
  cidr_block = var.cidr
  tags = {
    Environment = var.environment
    DO_NOT_DELETE = true
    CreatedBy = "terraform"
  }
}
 
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id
  tags = {
    Environment = var.environment
    CreatedBy = "terraform"
    Vpc = aws_vpc.main.id
  }
}

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

locals {
  az_count = length(data.aws_availability_zones.region_azs.names)
}

resource "aws_subnet" "private" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = cidrsubnet(aws_vpc.main.cidr_block, 4, count.index)
  availability_zone = data.aws_availability_zones.region_azs.names[count.index]
  count             = local.az_count

  tags = {
    Name = "private-subnet-${data.aws_availability_zones.region_azs.names[count.index]}"
    AvailabilityZone = data.aws_availability_zones.region_azs.names[count.index]
    Environment = var.environment
    CreatedBy = "terraform"
    Vpc = aws_vpc.main.id
    Type = "private"
    DO_NOT_DELETE = true
  }
}
 
resource "aws_subnet" "public" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = cidrsubnet(aws_vpc.main.cidr_block, 4, count.index + local.az_count )
  availability_zone = data.aws_availability_zones.region_azs.names[count.index]
  count             = local.az_count
  map_public_ip_on_launch = true

  tags = {
    Name = "public-subnet-${data.aws_availability_zones.region_azs.names[count.index]}"  
    Environment = var.environment
    CreatedBy = "terraform"
    Vpc = aws_vpc.main.id
    DO_NOT_DELETE = true
    Type = "public"
  }
}

resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id
  tags = {
    Environment = var.environment
    CreatedBy = "terraform"
    Vpc = aws_vpc.main.id
    Type = "public"
  }
}
 
resource "aws_route" "public" {
  route_table_id         = aws_route_table.public.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.main.id
}
 
resource "aws_route_table_association" "public" {
  count          = local.az_count
  subnet_id      = element(aws_subnet.public.*.id, count.index)
  route_table_id = aws_route_table.public.id
}

resource "aws_nat_gateway" "main" {
  count         = 2
  allocation_id = element(aws_eip.nat.*.id, count.index)
  subnet_id     = element(aws_subnet.public.*.id, count.index)
  depends_on    = [aws_internet_gateway.main]

  tags = {
    Environment = var.environment
    CreatedBy = "terraform" 
    Vpc = aws_vpc.main.id
  }
}
 
resource "aws_eip" "nat" {
  count = 2
  vpc = true

  tags = {
    CreatedBy = "terraform"
    Vpc = aws_vpc.main.id
  }
}

resource "aws_route_table" "private" {
  count  = local.az_count
  vpc_id = aws_vpc.main.id

  tags = {
    Environment = var.environment
    CreatedBy = "terraform"
    Type = "private"
    Vpc = aws_vpc.main.id
  }
}
 
resource "aws_route" "private" {
  count                  = local.az_count
  route_table_id         = element(aws_route_table.private.*.id, count.index)
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id         = element(aws_nat_gateway.main.*.id, count.index)
}
 
resource "aws_route_table_association" "private" {
  count          = local.az_count
  subnet_id      = element(aws_subnet.private.*.id, count.index)
  route_table_id = element(aws_route_table.private.*.id, count.index)
}

resource "aws_security_group" "alb" {
  name   = "${var.resources_name_prefix}-alb-sg"
  vpc_id = aws_vpc.main.id
 
  ingress {
   protocol         = "tcp"
   from_port        = 80
   to_port          = 80
   cidr_blocks      = ["0.0.0.0/0"]
   ipv6_cidr_blocks = ["::/0"]
  }
 
  ingress {
   protocol         = "tcp"
   from_port        = 443
   to_port          = 443
   cidr_blocks      = ["0.0.0.0/0"]
   ipv6_cidr_blocks = ["::/0"]
  }
 
  egress {
   protocol         = "-1"
   from_port        = 0
   to_port          = 0
   cidr_blocks      = ["0.0.0.0/0"]
   ipv6_cidr_blocks = ["::/0"]
  }

  tags = {
    Environment = var.environment
    CreatedBy = "terraform"
    Vpc = aws_vpc.main.id
  }
}

resource "aws_security_group" "ecs_tasks" {
  name   = "${var.resources_name_prefix}-ecs-sg"
  vpc_id = aws_vpc.main.id
 
  ingress {
   protocol         = "tcp"
   from_port        = 3000
   to_port          = 3000
   cidr_blocks      = ["0.0.0.0/0"]
   ipv6_cidr_blocks = ["::/0"]
  }

  egress {
   protocol         = "-1"
   from_port        = 0
   to_port          = 0
   cidr_blocks      = ["0.0.0.0/0"]
   ipv6_cidr_blocks = ["::/0"]
  }

  tags = {
    Environment = var.environment
    CreatedBy = "terraform"
    Vpc = aws_vpc.main.id
  }
}