![Docker 容器无法与子网通信,但 docker 主机可以,我如何找到数据包被丢弃的位置?](https://linux22.com/image/777972/Docker%20%E5%AE%B9%E5%99%A8%E6%97%A0%E6%B3%95%E4%B8%8E%E5%AD%90%E7%BD%91%E9%80%9A%E4%BF%A1%EF%BC%8C%E4%BD%86%20docker%20%E4%B8%BB%E6%9C%BA%E5%8F%AF%E4%BB%A5%EF%BC%8C%E6%88%91%E5%A6%82%E4%BD%95%E6%89%BE%E5%88%B0%E6%95%B0%E6%8D%AE%E5%8C%85%E8%A2%AB%E4%B8%A2%E5%BC%83%E7%9A%84%E4%BD%8D%E7%BD%AE%EF%BC%9F.png)
我们有一个设置,其中有一个 docker 容器,需要通过 ipv6 与 VPN(openvpn)上的设备通信。这是通过在 docker 网络和主机上的 tap0 接口之间构建桥梁来实现的。
终端设备将消息推送到 Docker 容器并期望收到确认消息。但是,它们位于不同的子网上,容器和主机位于子网中bbbb::/64
,设备位于子网中abcd::/64
(为了便于说明)。有一个网关位于子网上,用于将bbbb::abcd:2
流量从一个子网路由到另一个子网,而 Docker 主机具有用于此的网关配置。
要明确的是:
bbbb::4001 <--> bbbb::2105 <--> bbbb::abcd:2 <--> abcd::/64
其中,bbbb::4001
是容器的地址;bbbb::2105
是主机的地址;bbbb::abcd2
是网关设备的地址;abcd::/64
是终端设备所在的子网。
tshark
在主机和网关上使用,我们观察到以下情况:
- 主机可以直接与 abcd 子网上的终端设备通信(通过 traceroute 检查,可以看到主机和网关上的数据包);
- docker 容器可以与网关通信(通过 ping 检查,可以看到主机和网关上的数据包);
- Docker 容器不能直接与 abcd 子网上的终端设备对话:我们可以看到主机上的数据包,就像我们看到主机通信时的数据包一样,但我们没有看到任何东西到达网关。
我们尝试修改iptables
规则以允许转发数据包(例如,将链的默认策略设置FORWARD
为ACCEPT
),但无济于事。
我们不清楚该从哪里查找这个问题,因为看起来来自docker容器的数据包发往它不所在的子网被丢弃了某处在主机上,或者可能被发送到错误的地方,但我们确实在主机的br0
接口上看到它们,它们只是从未到达网关。当docker容器尝试与同一子网上的东西对话时,它就会工作。
我应该从哪里开始寻找这个?
答案1
问题与 docker 的网络有关。我们设置了一个 docker 网络,使用网络桥接器连接到 VPN。该桥接器是/etc/network/interfaces.d/br0.cfg
通过网关地址设置的(通过)bbbb::2105
,docker 网络是在桥接器接口之后创建的。创建 docker 网络时,未指定网关地址,docker 默认使用bbbb::1
网关地址,并强制br0
使用该地址。该地址与 VPN 服务器的地址相同。结果是数据包实际上并没有在主机上被丢弃,而是被转发到 VPN 服务器的tap
接口,而 VPN 服务器没有设置路由表,因此它不知道如何处理这些数据包,因此一旦它们到达 VPN 服务器,它们就会被黑洞化。
通过使用 tshark 监控 VPN 服务器的tap
接口以及tap
网关和 docker 主机上的接口,我们可以清楚地看到这一点。然后,我们尝试从 docker 容器内部 ping 终端设备,我们在 docker 主机和 VPN 服务器上看到了数据包,但在网关上看不到。如果我们在 docker 主机上尝试同样的事情,我们会在 docker 主机和网关上看到数据包,但在 VPN 服务器上看不到,这表明 docker 容器配置为将流量发送到 VPN 服务器而不是主机网络接口。
--gateway
通过在创建 docker 网络时引入该选项解决了该问题。
尚未解决的部分是为什么由于该设置自 2016 年以来一直有效,并在 2022 年 6 月的某一天随机停止工作,因此它突然开始表现出这种行为。