全栈应用服务器

  • 全栈应用服务器 > 常见问题 > MTU 黑洞导致 Docker 容器网络异常处理

    MTU 黑洞导致 Docker 容器网络异常处理

    最近更新时间: 2026-05-29 10:21:16

    标准网络下的虚拟机 MTU 上限通常为 1480,Docker 默认 1500 会导致大包被分片或丢弃。需要把 Docker daemon 与已创建网络的 MTU 都改成 1480。

    常见现象

    MTU 不匹配的典型表现是「小包通、大包挂」——三次握手正常,业务数据一上量就异常:

    • curlwget 拉小页面正常,拉大文件中途 hang 住或长时间无进度
    • apt update / apt installyumpipnpm 拉到一半卡住、超时、Connection reset
    • git cloneReceiving objects 阶段卡死或反复重试
    • HTTPS 握手能完成,但加载页面长时间空白;HTTP 请求超时但 ping 正常
    • 容器之间或容器到外网 SSH 能登录但执行 ls 大目录、scp 大文件就断
    • 数据库连接能建立,但跑大结果集查询超时

    问题确认

    虚拟机内执行:

    ip link show eno1 | grep mtu
    # 期望看到 mtu 1480
    # ip link show en0 | grep mtu # CentOS 系统
    
    ip link show docker0 | grep mtu
    # 看到 mtu 1500
    

    或者通过容器执行:

    docker run --rm nicolaka/netshoot ping -M do -s 1452 -c 3 8.8.8.8   # 应该通
    docker run --rm nicolaka/netshoot ping -M do -s 1453 -c 3 8.8.8.8   # 应该失败:Message too long 或丢包
    

    处理办法

    1. 修改 Docker daemon 默认 MTU

    编辑 /etc/docker/daemon.json(不存在则新建):

    sudo mkdir -p /etc/docker
    sudo tee /etc/docker/daemon.json > /dev/null <<'EOF'
    {
      "mtu": 1480
    }
    EOF
    

    如果文件已存在其他配置,只需在 JSON 中加入 "mtu": 1480 字段,不要整体覆盖。

    然后重启 Docker:

    sudo systemctl restart docker
    

    确认默认 bridge 网络配置:

    docker network inspect bridge | grep -i mtu
    # 期望看到 "com.docker.network.driver.mtu": "1480"
    

    2. 已存在的自定义网络

    daemon.jsonmtu 只对默认 bridge 网络生效。已经用 docker network create 创建的网络需要重建,或在创建时显式指定:

    docker network create \
      --opt com.docker.network.driver.mtu=1480 \
      my-net
    

    3. docker-compose 场景

    docker-compose.yml 中为自定义网络指定 MTU:

    networks:
      default:
        driver: bridge
        driver_opts:
          com.docker.network.driver.mtu: 1480
    

    验证 MTU 配置

    改完后先确认新容器的网卡 MTU 已生效:

    docker run --rm nicolaka/netshoot ip link show eth0 | grep mtu
    # 期望看到 mtu 1480
    

    再跑一次不分片边界测试,确认 1480 的包能通过,超过 1480 的包会被拦住:

    docker run --rm nicolaka/netshoot ping -M do -s 1452 -c 3 8.8.8.8
    # -s 1452 = 1480 - 20 (IP头) - 8 (ICMP头),应该通
    
    docker run --rm nicolaka/netshoot ping -M do -s 1453 -c 3 8.8.8.8
    # -s 1453 会让 IP 包超过 1480,应该失败:Message too long 或丢包
    
    以上内容是否对您有帮助?