Terraform 中的 GCP Classic VPN:让隧道成为基于路由的
在 Classic VPN 中,标签并不决定行为。基于路由意味着本地选择器为 0.0.0.0/0、远端选择器与实际网段一致,以及一条显式路由。
计划顺利应用,隧道也起来了,控制台却称它为基于策略。流量依然不通,而在 Terraform 资源里找基于路由的开关永远找不到,因为根本没有这个字段。在 Classic VPN 中,基于路由的行为不是一个可以选择的模式。它是这样得到的:本地流量选择器为0.0.0.0/0,远端选择器列出你真正想要的网段,并且有一条路由指向该隧道。三件事齐了,标签自然跟上。
误区:隧道模式字段
控制台的标签只反映 API 在选择器里看到的内容。资源里没有任何地方写着基于路由,所以没有可设为真的东西。
找这个字段会花掉问题的第一个小时,而读一遍选择器的值只要最后五分钟。
这里的基于路由是什么意思
Google 把 Classic VPN 的基于路由隧道记录为本地选择器为0.0.0.0/0的基于策略隧道。只有远端网段被点名,本地一侧被当作任意地址。正因如此,你配置里的标记是一个值,而不是一个模式。把两个选择器都写清楚,然后在计划输出里读出来:
local_traffic_selector = ["0.0.0.0/0"]
remote_traffic_selector = ["10.20.0.0/16"]
那段片段里的对端前缀只是示例;形状才是重点。
路由是独立对象
隧道对象不会安装路由。数据包可以匹配隧道策略,却依然无处可去,因为下一跳由 VPC 路由表决定。路由需要目标网段、网络、作为下一跳的隧道,以及一个能压过任何更宽条目的优先级。忘了这一步,得到的就是一条报告已建立的隧道,和一个永远出不了 VPC 的连通性测试。
resource "google_compute_route" "office" {
name = "office-via-vpn"
dest_range = "10.20.0.0/16"
network = google_compute_network.vpc.name
next_hop_vpn_tunnel = google_compute_vpn_tunnel.to_office.id
priority = 1000
}
把路由和隧道放在同一个模块里创建,这样评审时两者不会走偏。
在对端镜像选择器
远端设备必须按镜像方式配置:它的本地网段就是你的远端选择器,它的远端网段必须覆盖你打算使用的 GCP 子网。任何一侧收窄,即使第 1 阶段成功,第 2 阶段也会失败。控制台里看着正确、却带不动流量的配置,最常见的就是这个形状。
变更评审时,把两侧的选择器并排打印出来。
把静态地址拆成两次应用
在一次应用里同时创建预留地址和引用它的隧道,是已知的抖动来源,因为转发规则必须先看到地址存在。先单独应用地址资源,再加上网关、转发规则和隧道重新应用一次。Terraform 第二次运行时会从状态里读到已有地址并复用。跳过这一步,隧道每次应用都可能拿到新的公网地址,每次都把对端配置弄坏。
现在做两次应用,比每次发版都改对端便宜。
验证协商,而不是标签
应用之后,分别核对三件事:隧道报告已建立,路由存在且下一跳符合预期,对端报告第 1 阶段和第 2 阶段都已起来。
隧道已建立而第 2 阶段掉线,说明两侧对选择器的理解不一致:
- 一侧列出了另一侧没有列出的子网。
- 一侧使用的聚合段被另一侧收窄了。
- 路由存在,但指向了另一条隧道。
Classic VPN 是单条隧道,SLA 低于 HA VPN;HA VPN 使用两个接口、两条隧道,以及资源类型不同的 BGP。把经典示例照搬到 HA 配置里,还指望选择器字段表现一致,是另一个值得避免的错误。隧道字段本身记录在google_compute_vpn_tunnel 参考。