两个名称可以描述同一个分支,却回答完全不同的问题。vpn.branch.example 告诉远端对等方去哪里找 VPN 端点,它必须在任何隧道建立之前完成解析。inventory.branch.example 告诉获授权用户私有应用位于何处,它只在隧道建立之后才有意义。维护其中一个,对另一个毫无作用。

在调试任何一条记录之前,先给两条记录命名

把两条记录连同各自的负责人一起写下来。对端点,记录谁更新公网地址,以及 VPN 客户端如何刷新它得到的答案。对服务,记录谁拥有私有地址、由哪个区保存该记录,以及哪些解析器应当为它作答。

这份短清单能挡住这一领域最常见的误诊:为了让一条完全存在于隧道内部的记录恢复,去重启一条本来正常的站点隧道。隧道是服务名称的传输通道,而不是它的权威来源。

当有人提出变更时,先问它触及两条记录中的哪一条。如果没人答得上来,这项变更就还没准备好排期。

端点必须在任何隧道建立之前完成解析

假设分支的互联网连接获得了新的公网地址。端点更新程序发布新地址,远端 VPN 实现必须能够读到改变后的答案。提供该答案的解析器必须在不依赖隧道的情况下可达,否则客户端就在追一个名字——它只有先连上自己找不到的东西,才能解析这个名字。

这条启动依赖值得明说,因为当所有内部解析器都位于 VPN 之后时,很容易无意中造出它。为端点查询保留一条隧道之前的路径,并确认客户端的重连行为,而不是想当然地认为新答案会立刻被采用。

动态 DNS 也有记录更新无法跨越的边界。更新一条记录不会打开任何防火墙端口,不会建立 NAT 映射,也不能证明对等方身份。已发布的地址配上关闭的端口,只会得到一个解析正确却仍然连不上任何东西的客户端。

最后,正在运行的客户端可能一直使用缓存的端点,直到它重新连接。在笔记里把发布、缓存和重连策略分开,这样就不会把过期的对等方误当成坏掉的更新程序。

服务名称描述应用所在的位置

现在假设隧道保持健康,但清单服务器从 172.26.14.20 搬到 172.26.14.35。公网端点记录不受影响,而私有服务记录必须改变。为该服务保留地址或采用静态分配会让这种情况更少见;获得授权的更新路径负责处理那些确实有意为之的情形。

这里混用了两种更新机制。RFC 2136 定义了在一个区内添加和删除 DNS 记录的协议,而商业动态 DNS 提供商可能为了另一个目的提供完全不同的 HTTP API。用了其中一种,并不代表另一种在你的环境里存在。在针对它编写更新程序之前,先确认你的区实际接受哪种机制。

正确的私有答案只是第一个条件。要让远端调用方用得上,客户端需要一条承载私有区的解析器、一条允许向该解析器查询的策略,以及针对返回地址的转发。一个解析到客户端无法抵达地址的名称,会造成看起来像服务器故障的超时。

分别测试这两条路径

从隧道之外检查端点,从隧道之内检查服务,并把结果当作两个独立事实保留下来:

$ dig +short vpn.branch.example @1.1.1.1
$ dig +short inventory.branch.example @172.26.0.53
$ ip route get 172.26.14.35

如果第一个查询失败,问题在于公网发布或隧道之前的解析路径,任何内部改动都帮不上忙。如果第二个返回了地址,但第三个没有显示经过隧道的路由,那么 DNS 层是好的,而转发策略不是。

每次地址变更后都跑一遍这对检查,并记下是哪条记录动了。只说「DNS 已更新」的交接,会让下一位工程师去猜两个生命周期里究竟跑了哪一个。

相关文章