Docker Swarm 使用 IPv6 data path 时,确认 overlay MTU 比真实路径大 20 字节的问题,并通过新网络灰度调整与安全回退。
Docker Swarm 把 IPv6 地址用于节点间 data path 时,如果普通小请求正常、大响应或接近 MTU 的连接卡住,先检查 overlay 接口是否仍为 1450,而底层网卡 MTU 是 1500。Moby 上游在 2026 年 9 月记录的边界是:IPv6 外层的 VXLAN 头部需要 70 字节,但当前 overlay 按 50 字节扣减,容器接口因此比真实路径大 20 字节。未加密网络在 1500 底层上应按 1430 验证,而不是直接把防火墙、DNS 或应用判为故障。
本文适用于 Linux Docker Engine 25.0.0 以后、Swarm 节点间使用 IPv6 data path 的场景。只读检查不会收费,也不会修改数据。调整 MTU 需要新建网络并迁移服务,会滚动重启任务;删除现有 overlay 或 ingress 可能直接中断通信。默认做法是先新建测试网络验证,再逐个无状态服务迁移,不能原地删除生产网络。
先确认 data path 确实走 IPv6
在 Swarm 管理节点执行以下只读命令。把 YOUR_NETWORK 和 YOUR_SERVICE 换成实际名称。docker info 与 docker node inspect 用于确认集群和节点地址,网络与服务检查用于确认故障流量经过哪个 overlay。
docker version
docker info --format '{{json .Swarm}}'
docker node ls
docker node inspect self --pretty
docker network inspect YOUR_NETWORK
docker service inspect YOUR_SERVICE --pretty
docker service ps YOUR_SERVICE --no-trunc
如果节点的 data path 地址是 IPv6,且调用方与目标任务分布在不同节点,才符合本问题前提。若只使用 IPv4 data path,或失败发生在公网入口、宿主机端口和 routing mesh,应转向对应网络路径排查,不要套用 20 字节结论。
怎样确认 1450 与 1430 的边界
先进入一个已经带有 ping 工具的测试容器,读取接口 MTU。不要为了测试在生产应用容器内安装软件。以下 eth0 只是常见名称,应先用 ip link 确认真实 overlay 接口。
ip link
cat /sys/class/net/eth0/mtu
ip -6 route
底层网卡 MTU 为 1500、overlay 接口显示 1450,并不代表跨节点一定能承载 1450 字节。用不会写数据的目标容器名做 DF 探测;-M do 表示禁止分片,-s 是 ICMP 数据长度。上游复现中,1402 加 IPv4 ICMP 头后形成 1430 字节包可以通过,1422 对应 1450 字节包会失败。
ping -c 3 -W 2 -M do -s 1402 TARGET_SERVICE
ping -c 3 -W 2 -M do -s 1422 TARGET_SERVICE
若 1430 成功而 1450 稳定失败,同时小请求正常,特征与 Moby #53765 一致。若两者都失败,先检查服务发现、节点间 4789/UDP、7946/TCP+UDP 与底层 IPv6 路由;若两者都成功,则当前路径可能已通过更大的底层 MTU、路径 MTU 发现或其他设置避开该边界。
| 结果 | 判断 | 下一步 |
|---|---|---|
| IPv6 data path,1450 接口;1430 通、1450 不通 | 高度符合 20 字节 MTU 偏差 | 新建较小 MTU 的测试 overlay |
| 1430 与 1450 都不通 | 不只是 MTU 偏差 | 查路由、防火墙、服务发现和任务状态 |
| 小包通,大 TCP 响应卡住 | 可能是 PMTU/MSS 问题 | 结合 tracepath、抓包与应用超时继续确认 |
| 只在同一节点经宿主机 IP 失败 | 属于另一条 Swarm 路径 | 参考 29.8.0 同节点端口回归排查 |
用新网络灰度验证,不要删除原网络
上游给出的临时方案,是创建网络时把 com.docker.network.driver.mtu 设为比底层 MTU 小 20 字节。底层为 1500 时传入 1480,Docker 再扣除当前固定的 50 字节,容器接口得到 1430。以下命令会创建新 overlay,但不会自动迁移任何服务;名称和网段要按现场替换,并避开现有 VPC、VPN 与容器网段。
docker network create \
--driver overlay \
--attachable \
--opt com.docker.network.driver.mtu=1480 \
YOUR_IPV6_MTU_TEST_NETWORK
docker network inspect YOUR_IPV6_MTU_TEST_NETWORK
先把一个无状态测试服务接入新网络,重复接口 MTU、1430/1450 探测和真实健康检查。不要同时迁移数据库、队列或全部反向代理。若启用了 --opt encrypted,还存在 IPsec 额外开销;上游提到的 1404 仍是未实测说明,本文不把它写成生产固定值,应在自己的路径上逐级探测。
迁移服务时怎样控制停机和费用
创建 overlay 网络本身通常不产生单独云资源费用,但跨节点流量、云服务器和负载均衡仍按云厂商规则计费。服务增加或移除网络会触发任务更新,可能出现短暂连接重建。先确认副本数、更新并行度、健康检查和回滚配置,再在低峰迁移一个无状态服务。
docker service inspect YOUR_SERVICE --pretty
docker service update --network-add YOUR_IPV6_MTU_TEST_NETWORK YOUR_SERVICE
docker service ps YOUR_SERVICE --no-trunc
新网络验证通过后,再让调用方和目标服务都使用新网络,并按服务名访问。确认一个完整业务周期稳定后,才评估移除旧网络连接。原网络只有在没有服务与独立容器占用、且回滚窗口结束后才能删除。
失败分支与回退
若接入新网络后 DNS 解析失败,先确认调用方和目标服务是否同时连接该网络;若任务反复重启,检查镜像启动参数、健康检查和调度事件,不要继续扩大迁移。若 1430 仍不能通过,说明底层实际 MTU 可能低于 1500,应用 tracepath 或云网络文档确认真实上限,再重新计算测试值。
回退时先把服务流量切回原网络和原服务地址,再执行 docker service update --network-rm YOUR_IPV6_MTU_TEST_NETWORK YOUR_SERVICE。确认任务恢复、原路径可用后再删除测试网络。回退不会恢复已经删除的数据,因此本流程从不删除卷、镜像或 Docker 数据目录。
修复后如何验收
- 新网络内接口 MTU 与计划值一致,1500 底层的未加密测试网络应看到 1430。
- 跨节点 1430 字节 DF 探测稳定成功,真实 HTTP 健康检查和大响应不再卡住。
docker node ls中节点为 Ready,docker service ps中任务没有持续重启。- 应用错误率、超时与重传恢复到变更前正常范围。
- 记录临时 MTU、底层 MTU、网络名称与回退步骤;上游修复发布后先在测试网络复核,不直接全量恢复默认值。

