主机能到 IPsec 对端,Docker 容器却不行
桥接容器使用另一个源地址并通过转发进入,所以主机隧道能证明的很少。重启 Docker 之前,先核对选择器。
你从 Linux 机器上 ping 远端主机,它回应了,说明隧道是通的。旁边的容器却仍然超时,而最自然的下一个动作就是重启 Docker。桥接网络里的容器通常以另一个源地址起步,并且是通过转发进入主机,而不是走主机应用自己的出口路径,所以 那次成功的测试测到的是另一个数据包。对于基于策略的 strongSwan 隧道,当被转发的数据包与已安装的 IPsec 策略不匹配时,一条通往远端网段的普通路由并不够。
下面的排查沿着「一个目的地、两个源」展开,先读状态,再动手改。
从一个目的地和两个源开始
先按 IP 选一个已知服务,免得同时还在排查 DNS。记下三件事实:容器的桥接前缀、那次成功的主机请求的源地址,以及隧道协商出的本地与远端流量选择器。这三个数字几乎能解释这一类症状的全部情形。
然后从容器内部重放那次失败的请求,抓到它真正使用的源地址。如果这个地址不在本地选择器覆盖范围内,结果其实已经注定,重建容器并不会改变它。
动 Docker 之前先读策略
只读的主机检查覆盖三类信息:路由决策、策略数据库,以及在两者之间做选择的规则。
ip rule show
ip route show table all
ip xfrm policy策略列表会显示选择器与方向,不必导出满是密钥材料的 IPsec 状态,所以可以安全地贴进工单。找一条覆盖主机地址、但不覆盖桥接前缀的本地选择器。还要检查重叠:某条容器路由若把远端目的地当成直连本地,就永远不会产生你期望的那份被转发数据包,而隧道却背了锅。把这份列表和容器的源地址放在一起,两者合起来才是完整的对比。
如果容器前缀缺失,先停下来,把架构定下来,再去改别的东西。本排查的其余部分假设你们已经就「哪个源地址应该出现在线路上」达成一致。
按顺序检查过滤与地址转换
Docker 的 Linux 桥接防火墙可以独立于 IPsec 阻断转发。在 iptables 后端下,查看 FORWARD 链与 DOCKER-USER 的判定,并记住:如果前面已有结论,后面追加的规则可能永远不会被执行。nftables 后端集成方式不同,所以不要只因为某个 iptables 示例这么命名就新建 DOCKER-USER 链;先确认你的守护进程实际用的是哪个后端。
接着检查源地址转换。一条宽泛的 MASQUERADE 规则,会把原本匹配 IPsec 选择器的数据包变成不再匹配的包,而故障表现看起来完全像路由问题。strongSwan 转发指南说明了在转换之前、对已匹配策略的流量所需的那条例外。
这条例外并不是把未覆盖的容器源塞进隧道的办法。它只保护本来就符合设计的流量,所以先把选择器与回程路径的问题定下来,再让 NAT 与过滤和答案保持一致。如果你发现自己是在扩大例外范围,那该改的是选择器,不是 NAT 规则。
然后决定:走路由,还是走转换
路由式的容器网段要求两端都接受该网段,并且远端有回到它的回程路径,这通常意味着两端都要改选择器,还要和远端一侧的负责人沟通。刻意做转换的设计则必须在相关的查找阶段呈现出策略覆盖的地址,这通常意味一条狭窄且有文档的规则,而不是默认的 MASQUERADE。
这两种安排都不会从主机那条能用的隧道里自动推出来,而二选一是需要有人负责的设计决策。把选择写下来,否则下一位工程师会再从防火墙计数器里重新推导一遍。
还要留意混合故障:一半规则做了转换、一半没做,于是成功时好时坏,取决于目的端口,而不是网络本身的任何性质。
用新连接验证,而不是靠重启
用一条全新的应用连接,同时盯住范围很窄的防火墙计数器和远端接收端,这样每次观察都有出处。重启 Docker 可能改变规则状态,也会打断工作负载,反而让你丢掉那个本来想拿到的干净信号。
能长期立住的结果是四条可以摆出来的陈述:容器源地址、匹配的受保护路径、被放行的转发,以及一条能回来的回复。四条都成立时,容器到达对端的原因和主机一样。