我刚刚花了大约一个小时试图理解为什么我的 docker 容器无法连接到互联网,特别是无法解析任何 DNS 名称。现在我已经找到了解决方法,但我仍然不明白这一点。
症状是,根据 Wireshark 的说法,数据包将通过虚拟 docker 网络发送出去,但永远不会通过我的物理网卡传输,尽管我启用了 IPv4 转发。根据iptables
数据包计数器,它们记录在表链MASQUERADE
规则中,但不记录在表链中。POSTROUTING
nat
FORWARD
filter
我这里涉及以下网络设备:
- 网络0是我的物理 LAN 设备,IP 为 192.168.1.5,位于 192.168.1.1 的 DSL 路由器后面
- 屯1是连接到我的办公室网络的 VPN 链接
- 码头工人0是 docker 自动设置的虚拟网桥设备,docker 容器使用 172.17.0.0/16 网络,网桥位于 172.17.42.1
关键点是VPN。当我在办公室时,我希望能够通过 DSL 路由器设置的 DynDNS 记录连接到我的计算机。因此,从我的办公室到我的计算机的数据包不会通过 VPN,而是通过路由器中的 NAT。这意味着为了建立连接,回复数据包必须遵循反向路径,而不是通过 VPN。为了实现这一目标,我为来自 LAN 的传出数据包设置了一个特殊的路由表:
# ip rule list
0: from all lookup local
50: from all to 127.0.0.0/8 lookup main
51: from all to 192.168.1.0/24 lookup main
100: from 192.168.1.0/24 lookup net0
32766: from all lookup main
32767: from all lookup default
# ip route list table net0
default via 192.168.1.1 dev net0
192.168.1.0/24 dev net0 scope link
# ip route list table main
default via 192.168.1.1 dev net0 metric 3
10.0.0.0/8 dev tun1 scope link
127.0.0.0/8 dev lo scope host
127.0.0.0/8 via 127.0.0.1 dev lo
<VPN gateway> via 192.168.1.1 dev net0 src 192.168.1.5
<VPN network> dev tun1 scope link
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.42.1
192.168.1.0/24 dev net0 proto kernel scope link src 192.168.1.5 metric 3
最终我发现添加另一个规则来使用main
到 docker 网络的数据包表足以使这项工作成功。但为什么?我可以看到特殊的路由表可能如何影响来自我的路由器的回复数据包。但为什么它会影响传出的数据包,导致它们完全消失呢?是否有更灵活的方式来表达这样一个事实:我希望以响应数据包传入的方式路由每个答复数据包,以便每当我设置某种新的虚拟网络时都不必添加规则?
答案1
您难道不想通过确保不绕过 VPN 链接来解决问题的根本原因吗?如果是这样,为什么不创建一组单独的 DNS 条目以供连接 VPN 时使用?您可以输入 192.168。和172.17。位于公共 DNS 的 A 记录中,因此仍然可以通过您的办公室 DNS 服务器解析它们。