AWS VPC Peering 配置实战
AWS 上不同 VPC 之间默认完全隔离。VPC Peering 在两个 VPC 之间建立一条专用通道,让双方通过私网 IP 互相访问。
本文从基础概念讲起,通过一个跨 VPC 访问 RDS 超时的真实案例,演示 Peering 的完整配置过程和常见踩坑点。
1. 基础概念速览
把 AWS 网络想象成一片写字楼园区:
- VPC(Virtual Private Cloud)是一栋独立的大楼。每栋楼有自己的地址段(CIDR),比如
10.42.0.0/16表示所有房间门牌号都以10.42开头。不同大楼之间默认不互通。 - 子网(Subnet)是大楼里的楼层。每个子网占据 CIDR 的一小段,比如
10.42.10.0/24,并且绑定在某个可用区(AZ)。EC2、ECS 任务、RDS 实例都部署在某个子网里。 - 安全组(Security Group)是每扇门上的门禁系统。它控制 “ 谁可以从哪个端口进来 “。比如一条规则
tcp/5432 from 10.42.0.0/16表示:允许来自 10.42 网段的流量访问 PostgreSQL 端口。
1.1 路由表:决定流量往哪走
路由表是整个网络通信的核心,理解它才能理解 Peering 问题。
可以把路由表想象成楼层出口处的路标。每当一个数据包要发出去,系统查路由表,找到匹配的 “ 目的地 “,然后把包送到对应的 “ 下一跳 “:
| 目的地(Destination) | 下一跳(Target) | 含义 |
|---|---|---|
10.42.0.0/16 | local | 目的地在本 VPC 内,直接内部转发 |
0.0.0.0/0 | nat-xxx | 所有其他流量走 NAT 网关出互联网 |
10.43.0.0/16 | pcx-xxx | 目的地在另一个 VPC,走 Peering 通道 |
三点需要注意:
- 匹配规则是最长前缀优先。发往
10.42.10.5的包,10.42.0.0/16和0.0.0.0/0都能匹配,但/16比/0更精确,所以走local。 - 路由表是单向的。你在 A 的路由表加了
10.43.0.0/16 → pcx-xxx,只解决了 A → B 的去程。B 要回包给 A,B 的路由表也必须有10.42.0.0/16 → pcx-xxx。双向都要配。 - 每个子网绑定一张路由表。同一个 VPC 里不同子网可以有不同的路由表。排查问题时,必须看服务所在子网绑定的是哪张表。
有了这些基础,接下来看 VPC Peering 的工作机制和限制条件。
2. VPC Peering 详解
2.1 工作原理
VPC Peering 在两个 VPC 之间建立一条点对点的网络连接。建立后,两边的资源通过私网 IP 直接通信,就像在同一个网络里一样。
建立 Peering 需要三步:
- 创建 Peering 连接(一方发起请求)
- 对方接受(同账号下可以自动接受)
- 双方都添加路由(最容易遗漏的一步)
2.2 关键限制
- 不可传递(Non-transitive):A↔B 有 Peering,B↔C 有 Peering,不等于 A↔C 互通。A 要访问 C 必须单独建 A↔C 的 Peering。
- CIDR 不能重叠:如果两个 VPC 的地址段有重叠(比如都用了
10.0.0.0/16),无法建立 Peering。 - 同账号、跨账号、跨区域都可以建 Peering,但跨区域的流量费用更高。
2.3 计费
VPC Peering 本身不收费——创建和维持连接都免费。费用只产生在数据传输上:
| 场景 | 费用 |
|---|---|
| 同区域、同可用区(AZ) | 免费 |
| 同区域、跨可用区 | $0.01/GB(每个方向) |
| 跨区域 | 按跨区域数据传输费计费(双向,费率因区域而异) |
对于大多数同区域场景,只要服务和数据库在同一个 AZ,Peering 流量几乎零成本。
理解了原理和限制,下面用一个真实案例演示完整的排查和修复过程。
3. 实战场景
3.1 环境说明
我们有三个 VPC:
1 | coding-infra-dev-vpc vpc-0a1b2c3d4e5f60001 10.42.0.0/16 |
- Dev VPC(10.42.0.0/16):运行 ECS Fargate 服务,需要访问 Prod 数据库
- Prod VPC(10.43.0.0/16):运行 Prod RDS(PostgreSQL),地址为
10.43.11.179 - Ops VPC(10.228.0.0/16):运行运维跳板机(
10.228.1.232),用于日常运维
已有一条 Peering 连接:
1 | pcx-0a1b2c3d4e5fa0001 |
运维跳板机通过这条 Peering 可以正常访问 Prod RDS。
3.2 问题现象
Dev VPC 中的 ECS 服务连接 Prod RDS 时报错:
1 | dial tcp 10.43.11.179:5432: i/o timeout |
但从跳板机连接同一个 RDS 完全正常:
1 | nc -zvw5 coding-infra-prod-my-app-postgres.abcdefgh1234.us-west-2.rds.amazonaws.com 5432 |
RDS 本身没有问题,问题出在 Dev VPC 到 Prod VPC 的网络路径上。
3.3 变更前的网络拓扑
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6', 'primaryTextColor': '#1E3A5F', 'primaryBorderColor': '#2563EB', 'lineColor': '#60A5FA', 'secondaryColor': '#10B981', 'tertiaryColor': '#F59E0B'}}}%%
flowchart LR
subgraph dev ["Dev VPC (10.42.0.0/16)"]
ecs["ECS Fargate"]
end
subgraph prod ["Prod VPC (10.43.0.0/16)"]
rds[("Prod RDS")]
end
subgraph ops ["Ops VPC (10.228.0.0/16)"]
jump["运维跳板机"]
end
ops <--->|"Peering pcx-...a0001 ✅"| prod
dev -. "❌ 无 Peering,超时" .-> prod接下来逐层排查,找出问题根因。
4. 问题分析
两个 VPC 之间的通信需要同时满足三个条件:
- 两个 VPC 之间存在 Peering 连接
- 双方的路由表都有指向 Peering 的路由
- 安全组允许对应端口的访问
逐一排查。
4.1 安全组:已放通 ✅
Prod RDS 的安全组(sg-0a1b2c3d4e5f80002)已经包含:
1 | tcp/5432 from 10.228.0.0/16 |
Dev VPC 的网段 10.42.0.0/16 已被放通,安全组不是瓶颈。
4.2 去程不通:Dev 路由表缺少到 Prod 的路由 ❌
ECS 服务所在子网的路由表(rtb-0a1b2c3d4e5f90001):
1 | 10.42.0.0/16 → local |
ECS 服务(10.42.10.142)发包到 RDS(10.43.11.179)时:
- 查路由表:
10.43.11.179匹配10.42.0.0/16(local)?❌ 不匹配 - 匹配兜底路由
0.0.0.0/0→ 走 NAT 网关 → 出公网 10.43.11.179是私网地址,公网上不可达 → 超时
根因:Dev VPC 和 Prod VPC 之间没有 Peering 连接,路由表里自然没有对应的路由条目。
4.3 回程也错:Prod 路由表指向错误的 Peering ❌
Prod RDS 所在子网的路由表(rtb-0a1b2c3d4e5f90002):
1 | 10.42.0.0/16 → pcx-0a1b2c3d4e5fa0001 # ❌ 错误 |
pcx-...a0001 是 Ops VPC ↔ Prod VPC 的 Peering。
第二条没问题:Prod 回包给 Ops 跳板机(10.228.x.x),走这条 Peering 正确。
第一条有问题:Prod 回包给 Dev VPC(10.42.x.x),却指向了 Ops↔Prod 这条 Peering。这条 Peering 只连接 10.228.0.0/16 和 10.43.0.0/16,不通向 10.42.0.0/16。
Peering 不可传递——流量不能 Dev → Ops → Prod 这样中转。即使 Prod RDS 收到了请求,回程包也会被丢弃。
4.4 小结
去程:Dev 路由表没有到 Prod 的路由,流量走 NAT 出公网后丢失。回程:Prod 路由表中 10.42.0.0/16 指向了错误的 Peering,回程包同样丢失。双向都不通。
修复需要同时解决两个方向的问题。
5. 修复步骤
5.1 创建 Dev ↔ Prod Peering
1 | aws ec2 create-vpc-peering-connection \ |
得到新的 Peering ID:
1 | pcx-0a1b2c3d4e5fa0002 |
5.2 接受 Peering
1 | aws ec2 accept-vpc-peering-connection \ |
5.3 开启 DNS 解析
让 Peering 两端可以解析对方的私有 DNS 名称(比如 RDS 端点域名):
1 | aws ec2 modify-vpc-peering-connection-options \ |
5.4 添加 Dev → Prod 去程路由
在 ECS 服务所在子网的路由表中,添加到 Prod VPC 的路由:
1 | aws ec2 create-route \ |
5.5 修正 Prod → Dev 回程路由
把 Prod RDS 子网路由表中 10.42.0.0/16 的下一跳,从错误的旧 Peering 改到新建的 Dev↔Prod Peering:
1 | aws ec2 replace-route \ |
5.6 确认旧链路不受影响
Ops VPC → Prod VPC 的路由保持不变:
1 | 10.228.0.0/16 → pcx-0a1b2c3d4e5fa0001 |
运维跳板机访问 Prod RDS 的能力不受影响。
5.7 变更后的网络拓扑
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6', 'primaryTextColor': '#1E3A5F', 'primaryBorderColor': '#2563EB', 'lineColor': '#60A5FA', 'secondaryColor': '#10B981', 'tertiaryColor': '#F59E0B'}}}%%
flowchart LR
subgraph dev ["Dev VPC (10.42.0.0/16)"]
ecs["ECS Fargate"]
end
subgraph prod ["Prod VPC (10.43.0.0/16)"]
rds[("Prod RDS")]
end
subgraph ops ["Ops VPC (10.228.0.0/16)"]
jump["运维跳板机"]
end
ops <--->|"旧 Peering pcx-...a0001 ✅"| prod
dev <--->|"新 Peering pcx-...a0002 ✅"| prod变更后的路由表:
Dev 私网路由表(rtb-0a1b2c3d4e5f90001):
1 | 10.42.0.0/16 → local |
Prod RDS 子网路由表(rtb-0a1b2c3d4e5f90002):
1 | 10.42.0.0/16 → pcx-0a1b2c3d4e5fa0002 # 已修正 |
路由配置完成后,验证双向链路是否正常。
6. 验证
6.1 连接 Prod RDS
通过 Dev VPC 中的服务连接 Prod RDS,执行查询确认:
1 | SELECT current_database(), current_user, inet_server_addr(); |
1 | current_database | current_user | inet_server_addr |
连接成功,目标地址确实是 Prod RDS 10.43.11.179。
6.2 确认旧链路正常
从运维跳板机执行:
1 | nc -zvw5 coding-infra-prod-my-app-postgres.abcdefgh1234.us-west-2.rds.amazonaws.com 5432 |
旧 Peering 链路不受影响。
验证通过后,最后准备好回滚方案,确保出问题时能快速恢复。
6.3 回滚方案
如果变更引发问题,按以下顺序回滚:
1 | # 1. 删除 Dev → Prod 的路由 |
7. 经验总结
- 不要从名字推断网络归属。看到服务在
coding-infra-dev-cluster,不能假设它经过vis-server-vpc。ECS Fargate 服务的真实网络归属由awsvpc模式下的子网决定,必须查任务 ENI 确认。 - Peering 不可传递。A↔B 和 B↔C 互通,不代表 A↔C 互通,需要单独建 Peering。
- 路由必须双向配。光配了去程路由还不够,回程路由也要指向正确的 Peering。很多 “ 超时 “ 问题的根因就是回程路不通。
- 排查跨 VPC 连接失败时的检查清单:
- Peering 连接是否存在且状态为
active - 请求方子网的路由表是否有去程路由
- 目标方子网的路由表是否有回程路由
- 安全组是否放通了源网段和目标端口
- Peering 连接是否存在且状态为
- 善用信号区分故障层次。比如
502 cannot reach database说明网络层不通。如果变成400 Bad Request,说明网络已通,只是应用层协议不对。这种变化本身就是有价值的诊断信号。