英文:
Terraform AWS: How to provision one public subnet per AZ and multiple subnets for private and database subnets per AZ?
问题
Sure, here is the translated code:
以下是 provisions 的代码,用于定义 private_subnets、database_subnets 和 public_subnets 的子网(参考 cidrsubnets(var.cidr, 4, 4, 4))。
有三个可用区。它 provisions 六个 private_subnets、六个 database_subnets 和六个 public_subnets。每个可用区有两个子网(参考代码:cidrsubnets(cidr_block, 4, 4, 4, 4, 4, 4))。
azs = slice(data.aws_availability_zones.available.names, 0, 3)
subnets = [for cidr_block in cidrsubnets(var.cidr, 4, 4, 4) : cidrsubnets(cidr_block, 4, 4, 4, 4, 4, 4)]
private_subnets = local.subnets[0]
database_subnets = local.subnets[1]
public_subnets = local.subnets[2]
Outputs:
private_subnet_ids_per_az = {
"us-west-2a" = tolist([
"subnet-01bc44399240a22c2",
"subnet-0465fe06d7826ef05",
])
"us-west-2b" = tolist([
"subnet-08abc356b49f09b5c",
"subnet-006dd6b818f7afb89",
])
"us-west-2c" = tolist([
"subnet-00319273cb1a389af",
"subnet-058adb50bf65377e8",
])
}
public_subnet_ids_per_az = {
"us-west-2a" = tolist([
"subnet-01134239b0849264e",
"subnet-06748362d73fd82b3",
])
"us-west-2b" = tolist([
"subnet-0e6fbc9252f72b32c",
"subnet-03aca82e1973fb2d9",
])
"us-west-2c" = tolist([
"subnet-00015dec4d8525c01",
"subnet-0fd832a71b9b1bd88",
])
}
请注意,这段代码描述了如何为每个可用区 provision 多个子网。如果您想要每个可用区只 provisions 一个 public 子网,以及两个 private 和 database 子网,可能需要修改代码以实现这个目标。
英文:
The code as follows provisions subnets of private_subnets, database_subnets and public_subnets (refer to cidrsubnets(var.cidr, 4, 4, 4)).
There are three AZs. It provisions six private_subnets, six database_subnets and six public_subnets. Each AZ has two subnets (refer to the code: cidrsubnets(cidr_block, 4, 4, 4, 4, 4, 4).
azs = slice(data.aws_availability_zones.available.names, 0, 3)
subnets = [for cidr_block in cidrsubnets(var.cidr, 4, 4, 4) : cidrsubnets(cidr_block, 4, 4, 4, 4, 4, 4)]
private_subnets = local.subnets[0]
database_subnets = local.subnets[1]
public_subnets = local.subnets[2]
Outputs:
private_subnet_ids_per_az = {
"us-west-2a" = tolist([
"subnet-01bc44399240a22c2",
"subnet-0465fe06d7826ef05",
])
"us-west-2b" = tolist([
"subnet-08abc356b49f09b5c",
"subnet-006dd6b818f7afb89",
])
"us-west-2c" = tolist([
"subnet-00319273cb1a389af",
"subnet-058adb50bf65377e8",
])
}
public_subnet_ids_per_az = {
"us-west-2a" = tolist([
"subnet-01134239b0849264e",
"subnet-06748362d73fd82b3",
])
"us-west-2b" = tolist([
"subnet-0e6fbc9252f72b32c",
"subnet-03aca82e1973fb2d9",
])
"us-west-2c" = tolist([
"subnet-00015dec4d8525c01",
"subnet-0fd832a71b9b1bd88",
])
}
I would like to only provision one public subnet per AZ. And two private and database subnets per AZ. Is it possible?
As follows is the entire code:
main.tf
provider "aws" {
region = var.region
}
terraform {
# The configuration for this backend will be filled in by Terragrunt
backend "s3" {}
}
data "aws_availability_zones" "available" {
state = "available"
}
locals {
tags = {
EKS = var.cluster_name
ProvisionedBy = "Terraform"
Environment = var.environment
}
number_azs = var.number_azs
azs = slice(data.aws_availability_zones.available.names, 0, local.number_azs)
subnets = [for cidr_block in cidrsubnets(var.cidr, 4, 4, 4) : cidrsubnets(cidr_block, 4, 4, 4, 4, 4, 4)]
private_subnets = local.subnets[0]
database_subnets = local.subnets[1]
public_subnets = local.subnets[2]
public_subnet_ids_azs = {for k, v in data.aws_subnets.public_subnets_azs : tolist(v.filter)[0].values[0] => v.ids if length(v.ids) > 0}
private_subnet_ids_azs = {for k, v in data.aws_subnets.private_subnets_azs : tolist(v.filter)[0].values[0] => v.ids if length(v.ids) > 0}
}
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.0.0"
cidr = var.cidr
name = "vpc-${var.cluster_name}"
azs = local.azs
private_subnets = local.private_subnets
public_subnets = local.public_subnets
database_subnets = local.database_subnets
enable_nat_gateway = true
single_nat_gateway = false
one_nat_gateway_per_az = true
create_database_subnet_route_table = true
enable_dns_hostnames = true
enable_dns_support = true
tags = local.tags
public_subnet_tags = {
"subnet" = "public"
}
private_subnet_tags = {
"subnet" = "private"
}
}
data "aws_subnets" "public_subnets_azs" {
for_each = toset(data.aws_availability_zones.available.names)
filter {
name = "vpc-id"
values = [module.vpc.vpc_id]
}
filter {
name = "tag:subnet"
values = ["public"]
}
filter {
name = "availability-zone"
values = ["${each.value}"]
}
}
data "aws_subnets" "private_subnets_azs" {
for_each = toset(data.aws_availability_zones.available.names)
filter {
name = "vpc-id"
values = [module.vpc.vpc_id]
}
filter {
name = "tag:subnet"
values = ["private"]
}
filter {
name = "availability-zone"
values = ["${each.value}"]
}
}
outputs.tf
output "vpc_id" {
description = "The ID of the VPC"
value = module.vpc.vpc_id
}
output "azs" {
description = "A list of availability zones specified as argument"
value = local.azs
}
output "public_subnet_ids_per_az" {
description = "List of IDs of public subnets"
value = local.public_subnet_ids_azs
}
output "private_subnet_ids_per_az" {
description = "List of IDs of private subnets"
value = local.private_subnet_ids_azs
}
variables.tf
variable "region" {
description = "Region for the VPC"
default = "us-west-2"
}
variable "cluster_name" {
type = string
default = "eks-test"
}
variable "environment" {
default = "test"
}
variable "cidr" {
default = "10.2.0.0/16"
}
variable "number_azs" {
type = number
description = "Number of Availability Zones to create resources in the VPC."
default = 3
validation {
condition = var.number_azs > 0 && var.number_azs < 4
error_message = "The number of AZs to configure has to be between 1 - 3."
}
}
Note: I am working on provision AWs network firewall. It requires to have one firewall subnets per AZ. I will be able to do it if I am able to provision one public subnet per AZ. Thank you.
When I replaced the line, public_subnets = local.subnets[2] with
public_subnets = slice(local.subnets[2], 0, 2) # takes the first 3 items from the list, I got errors as follows:
data.aws_availability_zones.available: Reading...
data.aws_availability_zones.available: Read complete after 0s [id=us-west-2]
╷
│ Error: Error in function call
│
│ on .terraform/modules/vpc/main.tf line 142, in resource "aws_route_table_association" "public":
│ 142: subnet_id = element(aws_subnet.public[*].id, count.index)
│ ├────────────────
│ │ while calling element(list, index)
│ │ aws_subnet.public is empty tuple
│ │ count.index is 0
│
│ Call to function "element" failed: cannot use element function with an
│ empty list.
╵
╷
│ Error: Error in function call
│
│ on .terraform/modules/vpc/main.tf line 142, in resource "aws_route_table_association" "public":
│ 142: subnet_id = element(aws_subnet.public[*].id, count.index)
│ ├────────────────
│ │ while calling element(list, index)
│ │ aws_subnet.public is empty tuple
│ │ count.index is 1
│
│ Call to function "element" failed: cannot use element function with an
│ empty list.
╵
╷
│ Error: Error in function call
│
│ on .terraform/modules/vpc/main.tf line 1067, in resource "aws_nat_gateway" "this":
│ 1067: subnet_id = element(
│ 1068: aws_subnet.public[*].id,
│ 1069: var.single_nat_gateway ? 0 : count.index,
│ 1070: )
│ ├────────────────
│ │ while calling element(list, index)
│ │ aws_subnet.public is empty tuple
│ │ count.index is 0
│ │ var.single_nat_gateway is false
│
│ Call to function "element" failed: cannot use element function with an
│ empty list.
╵
╷
│ Error: Error in function call
│
│ on .terraform/modules/vpc/main.tf line 1067, in resource "aws_nat_gateway" "this":
│ 1067: subnet_id = element(
│ 1068: aws_subnet.public[*].id,
│ 1069: var.single_nat_gateway ? 0 : count.index,
│ 1070: )
│ ├────────────────
│ │ while calling element(list, index)
│ │ aws_subnet.public is empty tuple
│ │ count.index is 1
│ │ var.single_nat_gateway is false
│
│ Call to function "element" failed: cannot use element function with an
│ empty list.
╵
╷
│ Error: Error in function call
│
│ on .terraform/modules/vpc/main.tf line 1067, in resource "aws_nat_gateway" "this":
│ 1067: subnet_id = element(
│ 1068: aws_subnet.public[*].id,
│ 1069: var.single_nat_gateway ? 0 : count.index,
│ 1070: )
│ ├────────────────
│ │ while calling element(list, index)
│ │ aws_subnet.public is empty tuple
│ │ count.index is 2
│ │ var.single_nat_gateway is false
│
│ Call to function "element" failed: cannot use element function with an
│ empty list.
╵
Releasing state lock. This may take a few moments...
ERRO[0007] Terraform invocation failed in /home/perryluo/firewall/try
ERRO[0007] 1 error occurred:
* exit status 1
答案1
得分: 1
以下是翻译好的部分:
如果您不介意非连续的区块,一个简单的选择是使用slice
函数从列表中获取前三个项目。
subnets = [for cidr_block in cidrsubnets(var.cidr, 4, 4, 4) : cidrsubnets(cidr_block, 4, 4, 4, 4, 4, 4)]
private_subnets = local.subnets[0]
database_subnets = local.subnets[1]
public_subnets = slice(local.subnets[2], 0, 3) # 从列表中获取前3个项目
更改之前的计划输出尝试创建62个资源
计划:62个添加,0个更改,0个销毁。
Outputs的更改:
+ azs = [
+ "us-west-2a",
+ "us-west-2b",
+ "us-west-2c",
]
+ private_subnet_ids_per_az = (申请后已知)
+ public_subnet_ids_per_az = (申请后已知)
+ vpc_id = (申请后已知)
更改后的计划将仅创建56个资源
计划:56个添加,0个更改,0个销毁。
Outputs的更改:
+ azs = [
+ "us-west-2a",
+ "us-west-2b",
+ "us-west-2c",
]
+ private_subnet_ids_per_az = (申请后已知)
+ public_subnet_ids_per_az = (申请后已知)
+ vpc_id = (申请后已知)
英文:
If you don't mind having non-consecutive blocks, a straightforward option is to get the first three items from the list using the slice
function.
subnets = [for cidr_block in cidrsubnets(var.cidr, 4, 4, 4) : cidrsubnets(cidr_block, 4, 4, 4, 4, 4, 4)]
private_subnets = local.subnets[0]
database_subnets = local.subnets[1]
public_subnets = slice(local.subnets[2], 0, 3) # takes the first 3 items from the list
Slice function in terraform docs
The plan output before the change tries to create 62 resources
Plan: 62 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ azs = [
+ "us-west-2a",
+ "us-west-2b",
+ "us-west-2c",
]
+ private_subnet_ids_per_az = (known after apply)
+ public_subnet_ids_per_az = (known after apply)
+ vpc_id = (known after apply)
After the change the plan will only create 56 resources
Plan: 56 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ azs = [
+ "us-west-2a",
+ "us-west-2b",
+ "us-west-2c",
]
+ private_subnet_ids_per_az = (known after apply)
+ public_subnet_ids_per_az = (known after apply)
+ vpc_id = (known after apply)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论