当 MTU 不一致导致容器间 SSH 卡顿,如何调优

解读

在国内云主机、专线、混合云场景下,容器网络插件(Flannel、Calico、Weave 等)默认 MTU 往往比宿主机物理网卡或云厂商 VPC 网络小 50 字节,而 SSH 会话又依赖 TCP 大包交互。一旦路径上某段 MTU 小于容器内网卡 MTU,就会出现 IP 分片甚至被丢弃,表现为 SSH 输入延迟、Tab 补全卡顿、文件传输掉速。面试官想考察的是:

  1. 能否快速定位 MTU 不一致
  2. 能否在不中断业务的前提下完成端到端调优
  3. 是否理解 Docker 网络栈与宿主机、Overlay、VXLAN、IPIP 之间的封装开销

知识点

  • MTU(Maximum Transmission Unit):链路层单帧最大 payload,以太网默认 1500
  • Docker 网络驱动:bridge、host、overlay、macvlan、ipvlan,各自封装开销不同
  • VXLAN 额外开销:50 字节(14 ETH + 20 IP + 8 UDP + 8 VXLAN + 14 ETH inner),故 overlay 网络 MTU 需 ≤1450
  • TCP MSS(Maximum Segment Size):MTU − IP/TCP 头,通常 40 字节;路径上 MSS 不一致会触发 ICMP Fragmentation Needed,若被云厂商安全组丢弃则导致“黑洞”
  • 国内云厂商限制:阿里云 ECS 安全组默认放行 ICMP 3/4,腾讯云 CVM 需手动放通;部分金融云干脆禁止 ICMP,只能降 MTU
  • 容器运行时配置:daemon.json 中 "mtu": 1450、docker-compose.yml 中 driver_opts.mtu、Swarm service 创建时 --opt mtu=1450
  • CNI 插件级配置:Flannel 的 --iface-mtu、Calico 的 veth_mtu、Weave 的 WEAVE_MTU
  • 在线热调整:ip link set dev eth0 mtu 1450、systemctl reload docker、kubectl patch felixconfiguration 等
  • 验证手段ping -M do -s 1472 <podIP> 测 PMTU、tcpdump 抓 ICMP Type 3 Code 4、ss -i 看 TCP MSS、iftop 看重传率

答案

  1. 定位
    a. 在宿主机执行 ping -M do -s 1472 <对端容器IP> 若返回“Frag needed”则确认 MTU 黑洞
    b. tcpdump -i any icmp and 'icmp[0]=3 and icmp[1]=4' 抓包看是否收到 ICMP 需要分片报文
    c. docker exec 容器 ss -i 查看 TCP MSS 值是否大于路径最小 MTU

  2. 计算安全值
    若走 VXLAN Overlay,MTU = 1500 − 50 = 1450;若走 IPIP 隧道,MTU = 1500 − 20 = 1480;若宿主机网卡本身被云厂商限制为 1460,则再减 50 取 1410

  3. 统一调整
    a. Docker daemon 级/etc/docker/daemon.json 新增 "mtu": 1450systemctl reload docker(reload 不重启容器,业务无感知)
    b. Compose 项目级:docker-compose.yml 中

    networks:
      app:
        driver: bridge
        driver_opts:
          com.docker.network.driver.mtu: "1450"
    

    c. Swarm 级docker network create -d overlay --opt mtu=1450 --attachable ov1450
    d. CNI 级:修改 kube-flannel-cfg ConfigMap 的 net-conf.json.Network.MTU=1450,滚动重启 Flannel DaemonSet;Calico 则 kubectl patch felixconfiguration default --patch '{"spec":{"vethMTU":1450}}'

  4. 宿主机物理网卡同步
    若宿主机 MTU 被云厂商限制为 1460,需 ip link set dev eth0 mtu 1460 并写入 /etc/sysconfig/network-scripts/ifcfg-eth0MTU=1460,防止重启回退

  5. 验证
    再次 ping -M do -s 1422 <对端IP>(1422+28=1450)通即 OK;SSH 登录后 dd if=/dev/zero bs=1M count=100 | ssh 对端 'cat >/dev/null' 观察带宽是否恢复且无重传

  6. 兜底
    若云环境禁止 ICMP,无法依赖 PMTUD,则强制容器内 TCP MSS Clamp
    iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
    或在 Calico 的 Felix 配置中开启 FELIX_DEFAULTENDPOINTTOHOSTACTION=Accept 并启用 FELIX_TCPMSSCLAMP=1

拓展思考

  • IPv6 场景:VXLAN over IPv6 额外再减 20 字节,MTU 需 ≤1430,国内双栈网络需同步调整
  • Service Mesh 层:Istio 开启 mTLS 后,Sidecar 之间再增 24 字节 TLS Header,MTU 需再降 24,建议统一 1426
  • 金融云合规:部分银行私有云要求加密机透明代理,MTU 降到 1400 以下,需提前在 CI 流水线里做 iperf3 PMTU 探测 并自动写回 Helm values
  • 多集群混合云:跨 Region 专线 MTU 8500,但云主机只有 1500,不可盲目调大,需用 GRE Tunnel 拆包云企业网 提供的 Jumbo Frame 白名单
  • 监控闭环:在 Prometheus 中采集 node_network_mtucontainer_network_mtu,建立 Grafana 告警node_network_mtu != container_network_mtu 即触发,防止后续扩容再出现“隐形”卡顿