kubectl 无法通过 OpenVPN 解析私有集群 API
隧道可用并不等于私有区域可解析。比较推送 VNet 解析器与 hosts 或条件转发这两种做法,然后验证 API 端点。
隧道已经建立、API 的私有地址也仍能响应 ping,kubectl 却在名称解析处失败。路由没有问题;客户端问的是一个从未听说过该集群私有区域的解析器。最常用的两种修法是:把虚拟网络的解析器推送给每个 VPN 客户端,或用 hosts 记录、条件转发器把名称固定在本地。两者解决同一症状,但归属不同;把它们混为一谈,团队就会在端点重建时反复改 hosts 文件。
解析与可达性在不同的层上失败
动手之前先自己跑一次查询。Linux 上的 getent hosts 或 Windows 上的 nslookup 能告诉你客户端到底有没有拿到应答;超时或 NXDOMAIN 指向解析器,而返回错误地址的应答则指向陈旧记录或公网回退。
接着 确认 kubectl 实际连接的是哪台服务器。kubeconfig 上下文保存的是 URL,VPN 路由不会改写它:如果上下文写的是公网端点,DNS 再完美,命令照样失败。
getent hosts api.internal.example
kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}'
kubectl -v=8 get nodes 2>&1 | head -40
第三个信号是查询之后失败的样子。名称解析到私有地址后出现 TCP 超时,是防火墙或授权网络的问题;名称解析到公网地址,说明查询跑出了私有区域。把这三种结果分开看。每一种都对应不同的负责人。
方案 A:把虚拟网络的解析器推进隧道
当 VPN 服务器运行在虚拟网络内部时,客户端可以使用与服务器主机相同的解析器。在 OpenVPN Community 中由服务器推送 DNS 选项;Access Server 在管理界面提供同样的设置,而客户端必须重新下载配置文件,因为 DNS 指令是在配置文件里传输的。
# server.conf
push "dhcp-option DNS 10.0.0.4"
push "route 10.0.0.4 255.255.255.255"
在 split tunnel 配置里,路由那一行很关键。推送解析器地址不等于让它可以到达:如果只有集群子网走隧道,发往 10.0.0.4 的查询会从本地 LAN 出去然后消失。为解析器推送一条主机路由,或者把它的子网纳入隧道。
接收侧也有策略。从客户端地址段可达的解析器,仍可能拒绝来自该段的查询;而绑定到虚拟网络的私有区域,只应答经由该网络 DNS 路径进入的客户端。如果推送之后查询超时,先看解析器自己的日志,再去动客户端。
在客户端上核对实际生效的配置:systemd-resolved 的 Linux 用 resolvectl status,macOS 用 scutil --dns,Windows 用 ipconfig /all。推送的 DNS 服务器从未出现,说明配置文件没有重新加载。
方案 B:hosts 记录与条件转发
hosts 记录是最小的修法,也是最脆的。它把一台机器上的一个名称映射到一个地址,做演示可以,私有端点或其 IP 一旦重建就会失效。它还会把真正的缺口对团队其他人隐藏起来。
条件转发器扩展性更好,不必给每个客户端推送 DNS。dnsmasq 可以把一个区域送到 VNet 解析器,其余一概不管:server=/cluster.internal/10.0.0.4。Windows DNS 有条件转发器,Windows 客户端也可以用 NRPT 规则做同样的拆分。转发器仍然需要一条通往 VNet 解析器的路由。
转发让正常浏览保持在本地,这在 split tunnel 下很重要。它还给你一处集中记录私有区域查询的位置,以及一处会在转发主机迁移时出故障的位置。
按归属选,不要按方便选
当你掌控 VPN 配置、并且希望所有私有名称都能解析而不只是 API 时,就推送解析器。当客户端必须为其他一切保留本地 DNS,或者 VPN 由集群之外的团队管理时,就选转发器。
hosts 记录是诊断手段,不是部署方案。用它证明 API 可达,然后删掉它并修正解析器路径;把它留在那里,路由问题以后就会变成一场寻宝。无论选哪种方案,都把区域、解析器地址和承载查询的路由写下来。
测试 API 端点,而不只是名称
解析成功后,用集群 CA 获取 API 的版本端点。curl --cacert ca.crt https://api.internal.example:6443/version 能把 TLS 与授权失败同 DNS 区分开。403 说明名称和连接都正常,问题在身份。
还要检查客户端地址段是否被集群的授权网络或防火墙允许。私有集群往往只接受来自 VNet 或对等网段的 API 流量,所以从另一个地址池分配地址的隧道在网络层能连上,却会在 API 处被丢弃。
升级时记录四件事:客户端使用的解析器、它返回的地址、所选 kubeconfig 上下文里的服务器 URL,以及第一个失败的操作。这份记录告诉下一位工程师该改 DNS、路由还是防火墙策略,也能阻止下一次 hosts 文件编辑。
先做查询,再选与区域归属方匹配的解析器路径,最后验证端点。三项都通过,剩下的问题就是授权,而不是名称解析。