云服务器 MTU 调整:容器网络与隧道场景的分片排查

你可能遇到过这样的怪现象:小包 ping 得通,SSH 也能登录,但网页打不开、镜像拉取卡在半路、文件传到一半就停住。这类”能连不上网”的症状,十有八九和 MTU(最大传输单元)有关。云服务器(基于虚拟化技术的弹性服务器)上的容器网络和隧道会额外封装协议头部,让实际可用的报文空间变小,一旦某个环节没有同步调整 MTU,大包就会被丢弃或分片,业务表现为间歇性超时。本文教你如何定位这类分片问题,并给出可以照着执行的调整和验证步骤。

为什么隧道和容器网络容易触发分片问题

标准以太网的 MTU 是 1500 字节,即单个报文最多携带 1500 字节的负载。这个数值假设报文以原始形态直接在物理链路上传输。但云服务器的两类常见架构会打破这个假设:

隧道封装。VPN(虚拟专用网络)、GRE、VXLAN、WireGuard 等隧道技术会在原始报文外面再包一层协议头。以 VXLAN 为例,外层封装要消耗 50 字节左右,如果内层仍按 1500 字节发送,加上封装后就是 1550 字节,超过了物理链路的 1500 上限,路由器只能分片或直接丢弃。开启了”不要分片”标志的报文会被直接丢弃,同时回送一条 ICMP(互联网控制报文协议)”需要分片”错误——而很多云环境的安全组默认拦截 ICMP,导致发送方收不到退回的报文,只能干等超时。

容器虚拟网络。Docker 默认的 bridge 网络、Kubernetes 的多数 CNI(容器网络接口)插件、以及服务网格的 sidecar 代理,都会在报文路径上增加封装或转换层。一个 Pod(容器组)发出的报文,到达物理网卡时可能已经经过 veth pair、bridge、overlay 封装三道处理,每一道都可能改变报文大小。跨节点通信走 overlay 网络时尤其明显:物理网卡 MTU 1500,overlay 网络的 MTU 必须相应下调,否则跨节点的大请求全部失败,而同节点通信却一切正常。

判断是否属于 MTU 问题有个快速方法:用 ping 的大包模式测试。ping -M do -s 1472 目标地址 中,-M do 表示禁止分片,-s 1472 表示负载 1472 字节(1472 + 28 字节的 IP/ICMP 头正好是 1500)。如果这个命令成功而 -s 1473 失败,说明路径 MTU 就是 1500;如果 1472 都失败,说明中间有隧道或封装在吃掉报文空间。这类问题常出现在服务器配置环节,建议在部署隧道或容器集群之前就把 MTU 纳入初始化清单。

云服务器 MTU 调整封面配图:隧道封装导致报文超过链路上限的示意

如何逐层定位 MTU 不匹配的位置

定位的核心思路是”二分探测”:先确定端到端的路径 MTU(PMTU,路径最大传输单元),再逐跳缩小范围找出吃掉报文的环节。

第一步:测出整条路径的最小 MTU。 在云服务器上执行:

# 从小到大二分测试,找到能通过的最大负载值
ping -M do -s 1472 目标地址
ping -M do -s 1400 目标地址
ping -M do -s 1300 目标地址

假设 -s 1472 失败、-s 1400 成功,则路径 MTU 在 1428 到 1500 之间。继续在区间内二分,几分钟就能锁定精确值。负载值加 28(IPv4 头 20 字节 + ICMP 头 8 字节)就是路径 MTU。网络层排查与 TTFB 与主机优化的思路相通:先把传输路径上的瓶颈量化,再动手调整。

第二步:区分本机问题还是路径问题。 在同一台服务器上对多个不同目标执行上面的测试。如果所有目标的最大可用负载一致偏低,问题大概率在本机的隧道或容器接口配置;如果只有特定目标偏低,问题在对端或中间链路。

第三步:检查接口配置。 用 ip link show 逐个查看网卡、隧道口、容器 veth 的 MTU 值:

ip link show
# 重点关注这些接口的 mtu 字段
# eth0: mtu 1500(物理网卡)
# wg0 / tun0 / flannel.1 / vxlan.calico: mtu 1420 或其他
# vethxxxx: mtu 1500 或与容器侧不一致

常见的不匹配模式:容器内 eth0 的 MTU 是 1500,但宿主机 overlay 接口是 1450,容器发出的 1500 字节大包在 overlay 封装后超限。这时要么把容器网络整体下调到 1450,要么在宿主机开启封装协议对应的协商机制。

第四步:抓包确认丢弃点。 如果以上还不能定位,在两端同时用 tcpdump(网络抓包工具)观察:

tcpdump -ni eth0 'icmp[type=3 code=4]'   # 监听"需要分片"的 ICMP 错误
tcpdump -ni eth0 '(ip[6:2] & 0x2000 != 0)'  # 监听带不分片标志的大包

如果本机发出大包后只看到对方回的”需要分片”错误被安全组拦掉、或根本没有响应,就能确认是中间设备丢弃而非应用层问题。

用大包 ping 逐级测试路径 MTU 的示意

容器网络的 MTU 调整方案

定位到容器网络后,按宿主机 overlay 接口的实际 MTU 来统一调整。原则是:容器内 MTU ≤ 宿主机 overlay 接口 MTU ≥ 物理 MTU 减去封装开销。

Docker 场景。修改 /etc/docker/daemon.json,加入全局配置后重启 Docker 服务:

{
  "mtu": 1450
}

注意重启 Docker 会重建默认 bridge 网络并短暂中断容器网络,生产环境应在维护窗口操作。对自定义 bridge 网络,可以在 docker network create 时用 --opt com.docker.network.driver.mtu=1450 单独指定。已运行中的容器不会自动生效,需要重建。

Kubernetes 场景。CNI 插件不同,配置位置也不同。Calico 在安装配置中设置 vxlanMTU 或 ipipMTU;Flannel 的 net-conf.json 里写 mtu 字段;Cilium 直接在 ConfigMap 中指定。配置生效后新调度的 Pod 会拿到新的 MTU,存量 Pod 需要滚动重建。集群层面的经验值:VXLAN 封装按物理 MTU 减 50 配置,IPIP 减 20,WireGuard 减 60 到 80(视加密套件而定)。

调整后的验证不要只看 ping。用 ip link show 确认容器内接口值,再用大包 ping 验证跨节点路径,最后用真实业务流量(如拉取镜像、下载大文件)确认稳定。有一个容易忽略的细节:某些应用层协议(如 PMTUD,路径 MTU 发现依赖 ICMP 回包)在安全组拦截 ICMP 时会退化,可以在云平台安全组中放行 ICMP type 3 code 4,这是专门用于”需要分片”通知的报文,放行它不会带来额外风险。如果你的业务同时依赖站点访问速度,网络层修复后还可以参考这些网站性能优化方法做应用层的进一步提升。

容器与隧道分层 MTU 结构图:物理链路、隧道、容器三层逐层递减

隧道场景的 MTU 设置与验证

隧道场景的关键是让隧道内层负载加上封装头不超过物理链路 MTU。各常见协议的推荐配置值如下:

隧道协议 封装开销 物理链路 1500 时的推荐 MTU
WireGuard 60 字节 1420
GRE 24 字节 1476
VXLAN 50 字节 1450
IPIP 20 字节 1480
OpenVPN (UDP/TUN) 28-58 字节 1420-1450

以 WireGuard 为例,在配置文件中写入:

[Interface]
MTU = 1420

配置后用 wg show 确认接口状态,再用大包 ping 验证隧道对端。如果隧道两端的内网还要再套一层容器网络,要按”逐层递减”原则:物理 1500 → 隧道 1420 → 容器 1370,任何一层超出上一层可用空间都会复现同样的问题。

过渡期有一种保守做法值得了解:把两端 MSS(最大段大小)钳制到比 MTU 推算值更小的数值,让 TCP(传输控制协议)主动声明较小的分段,绕过路径上的分片:

iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

这是排障期的临时手段,治标不治本——它只对 TCP 生效,UDP(用户数据报协议)流量不受影响。定位并修正 MTU 配置后,应移除这条规则,避免双重调整带来的混乱。

隧道两端 MTU 统一调整后报文顺利通过的示意

在 Hostease 的云服务器上,如果遇到跨可用区组网或容器集群的网络异常,可以先按本文方法自查路径 MTU;确认需要机房侧配合排查时,提交工单说明”大包 ping 失败的具体负载值和目标地址”,能让支持团队更快定位链路环节。

总结与行动建议

MTU 问题的排查可以收敛成一个固定动作序列:先用 ping -M do -s <负载> 二分测出路径 MTU,再用 ip link show 核对各接口配置,然后按封装开销逐层下调隧道和容器网络,最后用真实业务流量验证。

给出三条具体建议:

  • 新建容器集群或隧道前,先按封装协议预留字节并统一规划各层 MTU,比事后排障成本低得多
  • 云平台安全组放行 ICMP type 3 code 4,保证 PMTUD 机制可用,这是很多”偶发超时”的隐藏根源
  • 把 ping -M do -s 1472 测试地址 加进日常巡检脚本,路径 MTU 突然变小往往比业务报错更早暴露链路变更

如果你需要进一步核对具体的封装开销数值,建议以所用协议的官方文档为准,不同版本实现可能有几字节的差异,但排查思路和本文完全一致。

发表评论