尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Terraform实战02:公有子网 + 私有子网 + NAT Gateway

Terraform实战02:公有子网 + 私有子网 + NAT Gateway Terraform实战02公有子网 私有子网 NAT Gateway本篇目标构建生产环境最常见的网络架构——公私网分离。理解为什么需要NAT Gateway以及公有子网和私有子网的本质区别。学完本篇你将掌握公有子网与私有子网的区别本质是路由表NAT Gateway的作用和工作原理Elastic IP的使用场景depends_on显式依赖声明安全组的精细化控制限制来源IP范围前置条件已完成第一篇练习理解VPC、子网、IGW、路由表、安全组的基本概念AWS环境和Terraform已配置好架构图互联网 │ ▼ ┌───────────────┐ │Internet Gateway│ └───────┬───────┘ │ ┌─────────────────┴─────────────────────────────┐ │ VPC (10.0.0.0/16) │ │ │ │ ┌─────────────────┐ ┌─────────────────┐ │ │ │ 公有子网 │ │ 私有子网 │ │ │ │ 10.0.1.0/24 │ │ 10.0.2.0/24 │ │ │ │ │ │ │ │ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ │ │ │NAT Gateway│ │ │ │EC2(私有) │ │ │ │ │ └───────────┘ │ │ └───────────┘ │ │ │ │ │ │ │ │ │ │ ┌───────────┐ │ └────────┬────────┘ │ │ │ │EC2(公有) │ │ │ │ │ │ └───────────┘ │ 路由0.0.0.0/0 │ │ │ │ → NAT Gateway │ │ └────────┬────────┘ │ │ │ │ │ 路由0.0.0.0/0 │ │ → IGW │ └───────────────────────────────────────────────┘与第一篇的对比新增了什么资源/概念第一篇本篇新增私有子网❌✅ 不分配公网IP的子网Elastic IP❌✅ 给NAT Gateway用的固定公网IPNAT Gateway❌✅ 让私有子网能上网但不被外网直接访问两套路由表❌✅ 公有→IGW私有→NAT两套安全组❌✅ 公有开放SSH私有只允许VPC内部depends_on❌✅ 显式声明资源依赖nat_gateway_id❌✅ 路由表中指向NAT的字段完整代码main.tf只标注与第一篇不同的部分terraform { required_providers { aws { source hashicorp/aws version ~ 5.0 } } required_version 1.0 } provider aws { region var.region } # VPC与第一篇相同 resource aws_vpc main { cidr_block 10.0.0.0/16 enable_dns_support true enable_dns_hostnames true tags { Name tf-practice-vpc } } # 公有子网与第一篇相同 resource aws_subnet public { vpc_id aws_vpc.main.id cidr_block 10.0.1.0/24 availability_zone ${var.region}a map_public_ip_on_launch true tags { Name tf-practice-public-subnet } } # # 【新增】私有子网 # 与公有子网的关键区别没有 map_public_ip_on_launch # 这里的实例不会自动获得公网IP # resource aws_subnet private { vpc_id aws_vpc.main.id cidr_block 10.0.2.0/24 availability_zone ${var.region}a # 注意没有 map_public_ip_on_launch true tags { Name tf-practice-private-subnet } } # Internet Gateway与第一篇相同 resource aws_internet_gateway main { vpc_id aws_vpc.main.id tags { Name tf-practice-igw } } # # 【新增】Elastic IP弹性公网IP # NAT Gateway需要一个固定的公网IP来做源地址转换 # domain vpc 表示这个EIP用于VPC内 # resource aws_eip nat { domain vpc tags { Name tf-practice-nat-eip } } # # 【新增】NAT Gateway # 关键点 # 1. 必须放在公有子网中它自己需要通过IGW出去 # 2. 绑定一个弹性IP外网回包通过这个IP找回来 # 3. depends_on显式声明依赖IGW确保IGW先创建好 # resource aws_nat_gateway main { allocation_id aws_eip.nat.id # 绑定弹性IP subnet_id aws_subnet.public.id # 放在公有子网中重要 tags { Name tf-practice-nat-gw } # 【新语法】depends_on显式声明依赖 # 通常Terraform通过引用自动判断依赖但NAT Gateway需要IGW工作 # 而代码中没有直接引用IGW所以要手动声明 depends_on [aws_internet_gateway.main] } # 公有子网路由表与第一篇相同0.0.0.0/0 → IGW resource aws_route_table public { vpc_id aws_vpc.main.id route { cidr_block 0.0.0.0/0 gateway_id aws_internet_gateway.main.id } tags { Name tf-practice-public-rt } } resource aws_route_table_association public { subnet_id aws_subnet.public.id route_table_id aws_route_table.public.id } # # 【新增】私有子网路由表 # 关键区别0.0.0.0/0 → NAT Gateway不是IGW # 用的字段是 nat_gateway_id不是 gateway_id # resource aws_route_table private { vpc_id aws_vpc.main.id route { cidr_block 0.0.0.0/0 nat_gateway_id aws_nat_gateway.main.id # 注意nat_gateway_id不是 gateway_id } tags { Name tf-practice-private-rt } } resource aws_route_table_association private { subnet_id aws_subnet.private.id route_table_id aws_route_table.private.id } # 公有安全组与第一篇相同允许任何IP SSH resource aws_security_group public { name tf-practice-public-sg description Security group for public instances vpc_id aws_vpc.main.id ingress { description SSH from anywhere from_port 22 to_port 22 protocol tcp cidr_blocks [0.0.0.0/0] } egress { from_port 0 to_port 0 protocol -1 cidr_blocks [0.0.0.0/0] } tags { Name tf-practice-public-sg } } # # 【新增】私有安全组 # 关键区别入站只允许VPC内部IP10.0.0.0/16 # 外网即使知道私有EC2的IP也连不上安全组拒绝 # resource aws_security_group private { name tf-practice-private-sg description Security group for private instances vpc_id aws_vpc.main.id ingress { description SSH from VPC from_port 22 to_port 22 protocol tcp cidr_blocks [aws_vpc.main.cidr_block] # 【注意】引用VPC的CIDR只允许内网访问 } egress { from_port 0 to_port 0 protocol -1 cidr_blocks [0.0.0.0/0] } tags { Name tf-practice-private-sg } } # 公有EC2 resource aws_instance public { ami var.ami_id instance_type t3.micro subnet_id aws_subnet.public.id vpc_security_group_ids [aws_security_group.public.id] tags { Name tf-practice-public-ec2 } } # 私有EC2放在私有子网绑定私有安全组 resource aws_instance private { ami var.ami_id instance_type t3.micro subnet_id aws_subnet.private.id vpc_security_group_ids [aws_security_group.private.id] tags { Name tf-practice-private-ec2 } }variables.tfvariable region { description AWS 区域 type string default us-east-1 } variable ami_id { description EC2 使用的 AMI IDAmazon Linux 2023us-east-1 type string default ami-0bdc7d025135d7b49 }outputs.tfoutput vpc_id { description VPC ID value aws_vpc.main.id } output public_subnet_id { description 公有子网 ID value aws_subnet.public.id } output private_subnet_id { description 私有子网 ID value aws_subnet.private.id } output nat_gateway_id { description NAT Gateway ID value aws_nat_gateway.main.id } output nat_eip { description NAT Gateway 的公网IP value aws_eip.nat.public_ip } output public_instance_ip { description 公有子网EC2的公网IP value aws_instance.public.public_ip } output private_instance_private_ip { description 私有子网EC2的私网IP无公网IP value aws_instance.private.private_ip }新增关键字段说明Elastic IP字段含义domain vpc表示这个弹性IP用于VPC内目前只有这一个选项NAT Gateway字段含义allocation_id绑定的弹性IP的IDsubnet_id放在哪个子网必须是公有子网depends_on显式声明依赖确保IGW先创建私有路由表的区别# 公有路由表 → 用 gateway_id 指向 IGW route { cidr_block 0.0.0.0/0 gateway_id aws_internet_gateway.main.id } # 私有路由表 → 用 nat_gateway_id 指向 NAT Gateway route { cidr_block 0.0.0.0/0 nat_gateway_id aws_nat_gateway.main.id }depends_on 语法depends_on [aws_internet_gateway.main]通常Terraform通过字段引用自动判断依赖顺序。但有时候资源之间有隐含的依赖代码里没有直接引用就需要用depends_on手动声明。NAT Gateway需要IGW才能工作但代码中没有直接引用IGW的ID所以必须显式声明。操作步骤与实际输出Step 1初始化cd~/terraform-practice/02-public-private-nat terraform initStep 2预览terraform plan关键输出Plan: 14 to add, 0 to change, 0 to destroy.14个资源VPC 2子网 IGW EIP NAT GW 2路由表 2路由表关联 2安全组 2 EC2Step 3执行terraform apply -auto-approve关键输出aws_vpc.main: Creation complete after 16s [idvpc-0b051b8ee8b88c10d] aws_eip.nat: Creation complete after 4s [ideipalloc-048e24fb6c0537b73] aws_nat_gateway.main: Still creating... [2m0s elapsed] aws_nat_gateway.main: Creation complete after 2m4s [idnat-060b22208f35115bd] Apply complete! Resources: 14 added, 0 changed, 0 destroyed. Outputs: nat_eip 98.90.185.28 nat_gateway_id nat-060b22208f35115bd private_instance_private_ip 10.0.2.198 public_instance_ip 44.223.80.200 vpc_id vpc-0b051b8ee8b88c10d注意NAT Gateway创建耗时约2分钟是所有资源中最慢的。Step 4验证去AWS控制台us-east-1区域检查检查项控制台路径期望结果公有子网VPC → SubnetsAuto-assign public IP: Yes私有子网VPC → SubnetsAuto-assign public IP: NoNAT GatewayVPC → NAT Gateways在公有子网中EIP98.90.185.28公有路由表VPC → Route Tables0.0.0.0/0 → igw-xxx私有路由表VPC → Route Tables0.0.0.0/0 → nat-xxx公有EC2EC2 → Instances有公网IP: 44.223.80.200私有EC2EC2 → Instances无公网IP只有私网IP: 10.0.2.198Step 5销毁terraform destroy -auto-approve关键输出aws_nat_gateway.main: Destruction complete after 1m2s aws_vpc.main: Destruction complete after 1s Destroy complete! Resources: 14 destroyed.原理讲解公有子网 vs 私有子网的本质区别不是创建时选的类型本质区别只有一个——关联的路由表有没有指向IGW公有子网私有子网路由表0.0.0.0/0 → IGW0.0.0.0/0 → NAT Gateway实例有公网IP有没有外网能主动访问能不能实例能访问外网能通过IGW能通过NAT为什么不能私有子网直接指向IGW这是一个常见疑问。两个原因1. 即使指向IGW没有公网IP也出不去IGW做NAT映射需要公网IP。私有子网的EC2没有公网IP → IGW不知道怎么做源地址转换 → 流量出不去。2. 如果给了公网IP又指向IGW就变成公有子网了这样外网也能主动连进来失去了私有的意义。NAT Gateway解决的矛盾“我想让EC2能上网但又不想给它公网IP、不想被外网直接访问。”私有EC2上网的完整流量路径私有EC2(10.0.2.198) 想访问外网 │ ▼ 查私有路由表0.0.0.0/0 → NAT Gateway │ NAT Gateway(在公有子网中私网IP: 10.0.1.6) │ 源地址转换10.0.2.198 → 98.90.185.28NAT的弹性IP ▼ 查公有路由表0.0.0.0/0 → IGW │ IGW → 互联网 │ ▼ 外网回包目标: 98.90.185.28 │ IGW → NAT Gateway │ 反向转换目标从 98.90.185.28 → 10.0.2.198 ▼ 私有EC2 收到回包NAT Gateway为什么必须在公有子网因为NAT Gateway自己也需要上网把流量转发出去。如果放在私有子网它自己都出不去。费用说明资源费用VPC / 子网 / 安全组 / IGW / 路由表 / EIP绑定中免费NAT Gateway~$0.045/小时EC2 t3.micro × 2~$0.021/小时⚠️NAT Gateway按小时计费练完必须立刻destroy本次练习总花费约10分钟 $0.02小结本篇核心收获公私网分离是生产环境的标准网络架构公有vs私有的区别在于路由表指向IGW还是NATNAT Gateway解决了私有子网要上网但不想被外网访问的矛盾depends_on用于声明代码中无法自动推断的隐含依赖安全组可以精细化控制来源IP范围0.0.0.0/0 vs VPC CIDR下一篇预告Terraform实战03数据源与远程状态管理下一篇我们将学习用data source引用已有的AWS资源不是Terraform创建的把terraform.tfstate存到S3远程存储团队协作必备用DynamoDB做状态锁防止多人同时操作冲突参考链接本系列配套代码GitHubTerraform AWS NAT Gateway文档Terraform AWS EIP文档AWS NAT Gateway官方文档Terraform depends_on文档
返回列表