基于不同可用区域的Gre隧道搭建

miao7 发布于 2026-05-28 147 次阅读


在云上做多可用区(Availability Zone)架构时,经常会遇到这样的需求:两个不同可用区的 VPC 内网之间需要互通,但又不想把内网直接暴露到公网。GRE 隧道就是解决这类问题最轻量的方案之一。

GRE(Generic Routing Encapsulation,通用路由封装)本质上是一种 IP-over-IP 隧道协议:它把一种网络层协议的数据报整个封装进另一种网络层协议里,让原本无法直接路由的数据包可以在 IPv4/IPv6 网络中穿行。隧道的两端各自负责「加封装」和「解封装」,对中间的承载网络来说,看到的只是一对普通的点对点连接。

一、GRE 解决了什么问题

不同可用区、不同地域之间的内网,在逻辑上像是彼此隔离的孤岛。常规做法要么走公网(慢、不安全、容易被劫持),要么拉专线(贵)。

用 GRE 隧道可以在两端的公网地址之间打一条虚拟的点对点通路,让两侧的私网网段像在同一个局域网里一样互相访问,而且全程只走一条封装后的链路。

典型适用场景

  • 跨可用区 / 跨地域的 VPC 内网互通
  • 把分散在不同机房的私网段连成一张大内网
  • 作为 IPsec、BGP 等更复杂方案的底层承载(GRE over IPsec)
  • 网络实验与拓扑教学

实验目标

本次实验的拓扑如下:A 区有一台 A1 作为隧道端点,其内网有一台 A2;B 区有一台 B1 作为隧道端点,其内网有一台 B2。

要求实现:A2 与 B2、A2 与 B1 之间的通信全部经由 GRE 隧道,而不是走各自的内网直连。

完成后可以在 B1 的网卡上用 tcpdump 抓到隧道流量,验证流量确实走了隧道。

二、开始搭建

2.1 确认 ip_gre 内核模块

Linux 上创建 GRE 隧道依赖 ip_gre 内核模块,它是 GRE over IPv4 的驱动。先加载并确认:

modprobe ip_gre
lsmod | grep ip_gre

2.2 两端都开启路由转发

隧道要转发「不属于本机」的流量,因此端点必须开启内核转发:

vim /etc/sysctl.conf
# 加入或确认这一行
net.ipv4.ip_forward = 1

# 生效
sysctl -p
# 确认
cat /etc/sysctl.conf | grep ip_forward

A1 和 B1 两端都要做这一步。

2.3 建立隧道

约定 A1 内网地址为 192.168.1.10,B1 内网地址为 192.168.2.10。先在 A1 上执行:

# tun1 为隧道名;local 是本机地址,remote 是对端地址
# 执行前请先确认两端可以互通
ip tunnel add tun1 mode gre remote 192.168.2.10 local 192.168.1.10 ttl 255

# 启用隧道接口
ip link set tun1 up

# 给隧道两端分配一个私有网段内的地址(本端 .1,对端 .2)
ip addr add 10.10.10.1 peer 10.10.10.2 dev tun1

# 查看结果
ip addr show

然后在 B1 上做对称配置:

ip tunnel add tun1 mode gre remote 192.168.1.10 local 192.168.2.10 ttl 255
ip link set tun1 up
ip addr add 10.10.10.2 peer 10.10.10.1 dev tun1

2.4 验证隧道连通性

  • A1 侧隧道地址:10.10.10.1
  • B1 侧隧道地址:10.10.10.2
# 在 B1 上抓隧道接口的包
tcpdump -i tun1

# 另一端 ping 隧道对端地址验证
ping 10.10.10.2   # 在 A1 上执行

三、配置路由与 NAT 转发

3.1 让两个内网段互相可达

隧道通了不等于内网通。还需要告诉各自的机器「去对端网段要走隧道」,并把跨网段的流量做 NAT。

在 A1 上:

# 去往 B 区内网段的路由走隧道
ip route add 192.168.2.0/24 dev tun1 via 10.10.10.2

# 把从隧道过来的 10.10.10.2 的源地址 NAT 成本机出口地址
iptables -t nat -A POSTROUTING -o eth0 -s 10.10.10.2 -j MASQUERADE
iptables -A FORWARD -s 10.10.10.2 -o eth0 -j ACCEPT

# 把 B 区内网段过来的包 NAT 成隧道地址
iptables -t nat -A POSTROUTING -o tun1 -s 192.168.2.0/24 -j MASQUERADE
iptables -A FORWARD -s 192.168.2.0/24 -o tun1 -j ACCEPT

# 查看规则
iptables -t nat -L -n
iptables -L -n

在 B1 上做对称配置:

ip route add 192.168.1.0/24 dev tun1 via 10.10.10.1

iptables -t nat -A POSTROUTING -o eth0 -s 10.10.10.1 -j MASQUERADE
iptables -A FORWARD -s 10.10.10.1 -o eth0 -j ACCEPT
iptables -t nat -A POSTROUTING -o tun1 -s 192.168.1.0/24 -j MASQUERADE
iptables -A FORWARD -s 192.168.1.0/24 -o tun1 -j ACCEPT

保存规则并设置开机自启:

# 持久化规则
netfilter-persistent save      # Debian/Ubuntu
# 或
service iptables save          # CentOS 系

# 开机自启
systemctl enable netfilter-persistent   # Debian/Ubuntu
systemctl enable iptables               # CentOS 系

3.2 让内网主机找到网关

最后一步:告诉 A2「去 B 区内网要经过 A1」,告诉 B2「去 A 区内网要经过 B1」。

# 在 A2 上
ip route add 192.168.2.0/24 via 192.168.1.10

# 在 B2 上(方向相反)
ip route add 192.168.1.0/24 via 192.168.2.10

做完这一步,A2 就能 ping 通 B2,而且中间确实经过隧道。

3.3 拆除隧道

ip link set tun1 down
ip tunnel del tun1

四、两个常见的坑

4.1 MTU / MSS 问题

GRE 会把一个数据包再封装一层,封装后的大小会超过原接口的 MTU。典型表现是:小包能通,ping 得通,但一传大文件、一开网页就卡死。

解决办法是在隧道接口上调整 MSS:

iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN 
         -j TCPMSS --clamp-mss-to-pmtu
# 或手动指定
iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN 
         -j TCPMSS --set-mss 1436

4.2 隧道没有状态检测

GRE 本身是无状态的:一端已经挂了,另一端可能还傻傻地以为隧道是通的,流量发出去就石沉大海。

解决方式是启用 keepalive,让两端定时互发探测包,超时未收到就把隧道接口置为 down:

ip tunnel change tun1 mode gre remote 192.168.2.10 local 192.168.1.10 
     ttl 255 keepalive 10 3

五、关于安全性

GRE 本身不做任何加密,封装后的流量在公网上是明文的,抓包就能看到内容。

如果涉及敏感数据,有两个选择:

  • 在隧道上用 ip tunnel ... key 设一个密钥(本质是明文口令,只防误配不防抓包)
  • 更靠谱的是 GRE over IPsec,用 IPsec 给 GRE 流量加密,但配置复杂度和运维成本都会上去