刚开始搞云计算那会儿,我也觉得VPC这玩意儿挺虚的。
控制台点进去一堆名词往脸上砸:Subnet、Route Table、Internet Gateway、NAT Gateway、Security Group、NACL、Endpoint、Peering……看着像网络,又不像传统机房那种网络。以前在机房里,交换机、路由器、防火墙、网线,摸得着看得见,排障还能去机柜边上看灯闪不闪。到了云上,啥都在页面里点来点去,概念全靠想象,理解起来总感觉隔了一层。
后来自己踩过几次坑,才慢慢把VPC这东西给整明白了。
这篇文章我就按我平时做云上网络规划的思路,拿AWS从头到尾搭一个贴近生产的小型VPC。不是那种点几下创建EC2能上网就完事的入门教程,而是把里面每个组件为什么这么配、出了问题怎么查、哪些地方容易踩坑都聊清楚。

image-20260702220259137
VPC,全称Virtual Private Cloud,翻译过来就是虚拟私有云。
你可以把它理解成:AWS在它那个巨大的全球网络基础设施里面,给你圈出来的一块“逻辑上完全隔离的私有网络空间”。
这个空间里,你自己说了算:
它不是一台具体的物理设备,也不是一个单一的网关服务。它更像一个容器,所有EC2、RDS、EKS节点、ALB、ElastiCache,只要放进去,就都得遵守这个VPC定下的网络规则。
我之前给团队新来的同事解释VPC,喜欢打个不太严谨的比方:

image-20260702220341838
VPC是小区,Subnet是楼栋,Route Table是小区里的指路牌,Internet Gateway是通往外面市政道路的大门,NAT Gateway是专门帮内网机器代购外网资源的代购员,Security Group是每户人家的门禁卡,NACL是小区大门口的保安。
比喻不准确,但先建立个画面感再说。
AWS每个Region创建账号之后都会自带一个default VPC,你直接在控制台Launch Instance,它默认就塞进这个VPC里,机器起来就能上网,对新手非常友好。
但生产环境我基本不用它。
原因很简单:默认VPC的IP段通常是172.31.0.0/16,子网和路由表都是AWS自动建好的,你不知道里面有啥也不知道改了对业务有啥影响。特别是当团队变大、多个人同时操作的时候,一个不留神把默认VPC的路由表改了,整组人集体断网,那场面真的挺刺激的。
所以我现在不管是搭测试环境还是生产环境,第一步永远是先Create Your Own VPC,从头规划,自己掌控。

image-20260702220434952
这是最容易被忽略但其实最关键的一步。
IP段选大了浪费,选小了以后扩容麻烦。我一般会问自己几个问题:
拿我现在给一个中小型SaaS服务搭的VPC举例,我选了10.100.0.0/16这个段。
为什么是这个段?没什么硬性要求,主要是我司IDC用的是10.50.0.0/16,云上用10.100.0.0/16,两边不打架,好记。以后要是真拉专线打通,路由也好配。
然后把这个大段拆成几个子网:
10.100.1.0/24 — 公网子网,AZ110.100.2.0/24 — 公网子网,AZ210.100.11.0/24 — 私网子网,AZ110.100.12.0/24 — 私网子网,AZ210.100.21.0/24 — 数据库子网,AZ110.100.22.0/24 — 数据库子网,AZ2公网子网放什么?ALB、NAT Gateway、需要对外提供服务的EC2。
私网子网放什么?应用服务器,Web服务器那些跑业务代码的。
数据库子网放什么?RDS、ElastiCache,那些不放公网、只允许应用层访问的。
子网划分没有标准答案,但有个原则要记住:公网和私网一定要分开,别为了省事把数据库直接塞公网子网里。

拥有位于 2 个可用区的子网、3 个路由表、互联网网关和网关端点的 VPC
好了,规划完了,开始动手。
在AWS控制台顶部搜索VPC,进入VPC控制台:
点击 Create VPC,弹窗里这样填:
IPv4 CIDR block: 10.100.0.0/16
IPv6 CIDR block: No IPv6 CIDR Block
Tenancy: DefaultName tag写 saas-prod-vpc,点 Create。
VPC创建好了,现在建子网。
点击左侧 Subnets → Create subnet:
先建AZ1的公网子网:
VPC: saas-prod-vpc
Subnet name: public-subnet-az1
Availability Zone: us-east-1a(你选你自己的AZ)
IPv4 CIDR block: 10.100.1.0/24点 Add new subnet,继续建AZ1的私网子网:
Subnet name: private-subnet-az1
Availability Zone: us-east-1a
IPv4 CIDR block: 10.100.11.0/24然后是数据库子网、AZ2的子网,都按规划填进去。六个子网全部建好之后,大概是这么个布局:
10.100.1.0/2410.100.2.0/2410.100.11.0/2410.100.12.0/2410.100.21.0/2410.100.22.0/24这里有个小细节我要说一下:AWS的子网必须关联到一个AZ,不能跨AZ。所以每个AZ都要单独建子网。另外,如果你想在里面Launch实例的时候自动分配公有IP,记得把子网的"Auto-assign public IPv4 address"那个选项打开。

拥有位于 2 个可用区的子网、3 个路由表、互联网网关和网关端点的 VPC
路由表是VPC的核心,理解透了VPC就理解了一大半。
每个VPC默认会带一张主路由表,但我一般会新建两张独立的路由表:公网路由表和私网路由表,职责分离,清晰明了。
先建公网路由表:
VPC控制台左侧点 Route Tables → Create route table:
Name: public-rt
VPC: saas-prod-vpc建好之后点进去,在 Routes tab 点 Edit routes:
需要加两条路由:
第一条是本地流量,10.100.0.0/16 的流量都local,这个VPC创建时就带上了,不用动。
第二条是关键:
Destination: 0.0.0.0/0
Target: igw-xxxxxxx(IGW的ID,下面马上创建)这条的意思是:所有发往VPC外部的流量,全部扔给Internet Gateway处理。
然后Subnet associations tab里,把 public-subnet-az1 和 public-subnet-az2 关联进来。
公网路由表搞定。
现在建私网路由表:
同样 Create route table,Name写 private-rt,VPC选 saas-prod-vpc。
私网机器要访问外网,但它没有公有IP,不能直接走IGW。怎么办?靠NAT Gateway。
路由这样配:
Destination: 10.100.0.0/16 → Target: local
Destination: 0.0.0.0/0 → Target: nat-xxxxxxx(NAT Gateway的ID)把 private-subnet-az1、private-subnet-az2、db-subnet-az1、db-subnet-az2 都关联到这个路由表。

带有互联网网关的 VPC
Internet Gateway,简称IGW,是VPC连接公网的出口。没有它,VPC里的机器就算有公有IP也上不了网。
建起来很简单:
左侧点 Internet Gateways → Create internet gateway:
Name tag: prod-igw点 Create。
刚建好的IGW是 Detached 状态,需要手动 attach 到VPC上。选中这个IGW,点 Actions → Attach to VPC,选 saas-prod-vpc,点 Attach。
attach成功之后,它会显示关联的VPC ID。
这就是之前路由表里引用的那个 igw-xxxxxxx。

两个可用区中的区域 NAT 网关与跨区的区域 NAT 网关的比较。
Internet Gateway只接受有公网IP的实例主动发起流量,私网里的EC2没有公有IP,它想访问外网(比如拉镜像、更新系统包)怎么办?
靠NAT Gateway。
NAT Gateway是AWS托管的服务,你不用自己维护EC2当NAT用,它自己高可用,按流量和小时数收费,贵是贵点但省心。
怎么建?
左侧菜单找 NAT Gateways → Create NAT Gateway:
Subnet: public-subnet-az1(注意,是公网子网!)
Elastic IP allocation ID: 点Allocate Elastic IP让AWS给你分配一个点 Create。
NAT Gateway创建完之后,记得去公网路由表 public-rt 里确认一下,0.0.0.0/0 是不是指向了这个NAT Gateway——我在实际操作中就犯过把NAT Gateway建到私网子网的错误,结果私网流量根本出不去。
NAT Gateway建好之后会有一个从 initializing 到 available 的过程,大概一两分钟。状态变成 available 之后,私网子网的EC2就能通过它访问外网了,但只允许从内向外发起连接,外面的流量想主动进来?门都没有。这就是NAT的意思,Network Address Translation,网络地址转换,它会把自己的公有IP替换掉私网机器的内网IP去访问外网,然后回来的流量再转换回去。

具有 2 个子网、2 个安全组的 VPC,子网中的服务器关联了不同的安全组
路由表控制的是“能不能出这个VPC”,到了具体某个实例层面,谁能和它通信,就要靠Security Group。
我见过太多人把Security Group当成防火墙来理解,这也没大错,但有个关键区别要记住:Security Group是有状态的,NACL是无状态的。
有状态的意思是:只要入方向允许了一条规则,出方向会自动放行,不需要手动配置。比如你允许了22端口入,那22端口出的流量自动是通的。
怎么理解这个"有状态"?就像你进小区门的时候保安让你进去了,你出来的时候保安不会再拦你。
但NACL不一样,它是小区大门保安,你出去也要看它脸色。
好,先建一个Web层的安全组:
Network & Security → Security Groups → Create security group:
Name: web-sg
VPC: saas-prod-vpc
Description: Security group for web servers入方向规则这样配:
Type: SSH | Source: 10.100.0.0/16(只允许内网SSH)
Type: HTTP | Source: 0.0.0.0/0
Type: HTTPS | Source: 0.0.0.0/0出方向默认全放行,一般不用改。
再建一个App层的安全组:
Name: app-sg
VPC: saas-prod-vpc入方向:
Type: SSH | Source: 10.100.0.0/16
Type: Custom TCP | Port: 8080 | Source: web-sg的安全组ID(允许来自Web层的访问)这里有个细节:Source那里可以直接引用另一个安全组ID,而不是写死IP地址。这意味着只要属于web-sg的实例,不管IP怎么变,都能访问app层的8080端口。这比写死IP灵活太多了,生产里强烈建议用这种方式。
再建一个DB层的安全组:
Name: db-sg
VPC: saas-prod-vpc入方向:
Type: MySQL/Aurora | Port: 3306 | Source: app-sg的安全组ID这样只有App层的机器能连数据库,其他地方一概拒绝。

具有两个子网的 VPC 和每个子网的网络 ACL。
NACL,网络访问控制列表,它是子网级别的防护。每个子网必须关联一个NACL,默认NACL允许所有流量进和出。
NACL和Security Group的主要区别:
什么场景下用NACL?比如你想拒绝某个特定IP段访问某个子网,SG做不到拒绝,只能允许。但NACL可以。
我一般会建一个严格的NACL:
Name: strict-nacl
VPC: saas-prod-vpc入方向规则:
Rule #: 100 | Type: All Traffic | Source: 10.100.0.0/16 | Allow
Rule #: 200 | Type: All Traffic | Source: 0.0.0.0/0 | Deny(拒绝其他所有)出方向同理,放行内网和必要的端口出去。
然后把私网子网和数据库子网关联到这个NACL。公网子网可以保持默认的允许所有NACL,因为Security Group已经够用了。
现在我们把各层组件串起来测试。
在EC2控制台Launch Instance:
Name: web-server-01
Network: saas-prod-vpc
Subnet: public-subnet-az1
Auto-assign public IP: Enable(这台要能被外网访问)
Security Group: web-sg
Key Pair: 选你的密钥对创建完成后,AWS会给你分配一个公有IP。复制这个IP,终端里:
ssh -i your-key.pem ec2-user@54.xxx.xxx.xxx能连上说明这台机器网络通了。
然后在这台机器上测试:
curl https://aws.amazon.com能返回HTML,说明从公网子网访问外网没问题,IGW工作正常。
现在Launch一台App层的EC2:
Name: app-server-01
Network: saas-prod-vpc
Subnet: private-subnet-az1(注意是私网子网)
Auto-assign public IP: Disable
Security Group: app-sg这台机器没有公有IP,你怎么SSH进去?有两个办法:
方法一:通过公网EC2跳板机跳转
# 先连上公网的web-server
ssh -i your-key.pem ec2-user@54.xxx.xxx.xxx
# 然后从web-server连app-server(内网IP互访)
ssh -i your-key.pem ec2-user@10.100.11.xxx前提是web-server能访问app-server的22端口——也就是说web-sg要允许到app-sg的SSH,或者干脆让web-server和app-server用同一个安全组。
方法二:用SSM Session Manager
AWS Systems Manager的Session Manager可以直接管理EC2,不需要开放SSH端口,也不需要机器有公网IP。只要EC2装了SSM Agent,IAM角色有相应权限,从浏览器里就能开一个终端会话连到私网EC2。
aws ssm start-session --target i-xxxxxxxxxx这个方式安全很多,生产环境我建议用SSM。
好,app-server起来了。在上面测试:
curl https://aws.amazon.com能通,说明NAT Gateway在正常工作,私网机器通过NAT代理访问了外网。
再看一个:
ping -c 3 10.100.1.10这是web-server的内网IP,能ping通说明VPC内部的私有通信没问题。
EC2访问S3、DynamoDB、Secrets Manager这些AWS服务,默认会走公网。不光是流量成本的问题,数据出公网还有安全合规的风险,尤其是金融、医疗这类行业。
VPC Endpoint就是来解决这个问题的。
它让你的EC2在访问AWS服务时,走AWS内部网络,不经过公网,有两种类型:
先看Gateway Endpoint:
VPC左侧菜单点 Endpoints → Create Endpoint:
Service category: AWS services
Service: com.amazonaws.us-east-1.s3(选你的Region)
VPC: saas-prod-vpc
Route Table: private-rt(把私网路由表关联上)
Policy: Full Access(先用全访问,后续可以细化)创建完成之后,在private-rt的路由表里会多一条:
Destination: pl-xxxxxxxxx(S3的VPC Endpoint前缀) → Target: vpce-xxxxxxxxx现在从app-server测试:
aws s3 ls能列出S3桶,说明访问走的是内网。
然后是Interface Endpoint。拿Secrets Manager举例:
Create Endpoint,服务选 com.amazonaws.us-east-1.secretsmanager,Subnet那里选 private-subnet-az1 和 private-subnet-az2(多AZ部署),安全组选 app-sg。
建好之后,EC2访问Secrets Manager的地址会从公网DNS变成VPC内网DNS:secretsmanager.us-east-1.amazonaws.com 自动解析到 vpce-xxx 这个地址。
有时候业务需要,两个不同的VPC之间要互相访问。比如测试环境VPC和生产环境VPC要互通,或者集团子公司各自有VPC要内网互联。
VPC Peering就是干这个的。
假设你现在有个测试VPC:10.200.0.0/16,想和刚才的生产VPC 10.100.0.0/16 打通。
在生产VPC这端操作:
左侧点 Peering Connections → Create peering connection:
Name: prod-to-test-peering
VPC Requester: saas-prod-vpc
VPC Accepter: test-vpc(需要另一个VPC的ID或者账号授权)点 Create Peering Connection。
然后去测试VPC那端,Accept这个Peering请求。
接下来两边都要配置路由表:
在生产VPC的 private-rt 里加一条:
Destination: 10.200.0.0/16 → Target: pcx-xxxxxxx(Peering Connection ID)在测试VPC的路由表里加一条:
Destination: 10.100.0.0/16 → Target: pcx-xxxxxxx加完之后,两边的EC2就能通过内网IP互相访问了。
有一点要提醒:VPC Peering不支持传递路由。什么意思?假设A和B打通,B和C打通,A和C还是不通,必须单独建立A和C的Peering。
坑1:子网配错了路由表。 刚建VPC的时候经常把公网子网绑到了私网路由表,然后公网EC2死活出不去。一查路由表,发现0.0.0.0/0指向的是NAT Gateway而不是IGW,改过来就好了。
坑2:安全组引用了自己。 想让同一安全组的机器之间互访,写规则时Source填了自己的安全组ID,结果发现根本不通。这是因为SG引用自己的时候只对入方向生效,出方向流量会被同组的另一条规则拦截。这个问题比较隐蔽,要特别注意。
坑3:NAT Gateway放错子网。 有一次图省事把NAT Gateway塞进了私网子网,然后私网机器配置0.0.0.0/0指向它,结果全部断网。NAT Gateway必须放在公网子网,它自己是需要能访问公网才能代理流量的。
坑4:修改了默认VPC的路由表。 前面说过我不爱用默认VPC,就是因为大家共用一套路由表,你改了我就得遭殃。某次团队有人不小心把默认VPC路由表里指向IGW那条规则删了,十几台测试机集体上不了网,排障排查了两个小时才定位到。
坑5:跨AZ通信以为走了专线。 在一个AZ里的EC2发流量到另一个AZ的EC2,误以为走了内网专线所以很快。实际上AZ间的流量走的是AWS骨干网,延迟会比同AZ高一些,而且是有流量费用的。别把跨AZ当同AZ用。
VPC这东西,说难不难,说简单也不简单。核心就那么几个组件:VPC本身、子网、路由表、IGW、NAT Gateway、Security Group、NACL、Endpoint、Peering。但怎么组合、怎么规划、出了问题怎么排查,需要实际操练才能有感觉。
建议你真的动手搭一遍,别光看文章。看十篇教程不如踩一次坑,踩过坑你才能真正理解流量是怎么走的、安全边界是怎么划的、高可用是怎么实现的。
搭完之后,可以试试这样验证网络连通性:
# 在私网EC2上
curl ifconfig.me # 看返回的IP是不是NAT Gateway的IP
traceroute aws.amazon.com # 看路径有没有经过NAT Gateway
# 在公网EC2上
curl ifconfig.me # 看返回的是不是自己的公有IP
traceroute aws.amazon.com # 看路径有没有经过IGW搞懂这些,你对VPC的理解就上了一个台阶。