docker和mss

下面给出一个较为完整的裸 Docker 网络中,结合 iptables(mangle 表)以及路由转发流程的图示,涵盖了外部流量进入、容器间通信以及容器出站的全部流程。下图以外部服务器到容器为例,同时标注了各个 iptables 链和路由的转发路径。你可以根据下面图示理解数据包如何在 Docker 网络中经过 NAT、mangle 链以及路由表的处理。


1. 外部服务器 → Docker 容器(入站流量)的 iptables 和路由流程

     [外部服务器]
           │
           │  (数据包进入宿主机外网接口,例如 eth0)
           │
           ▼
   ┌─────────────────┐
   │  PREROUTING     │    <---(mangle 表:修改 TOS、TTL、MSS 等;DNAT也可在nat表中处理)
   │   (mangle/     │
   │   nat)          │
   └─────────────────┘
           │
           │  经过 DNAT(目的地址转换:将外部目的地址改为目标容器 IP)
           │
           ▼
   ┌─────────────────┐
   │  FORWARD        │    <---(mangle 表:调整 MSS、其他包标记;filter 表:防火墙规则检查)
   │   (mangle/     │
   │   filter)       │
   └─────────────────┘
           │
           │  路由查表,确定出接口为 docker bridge(通常是 docker0 或 veth 组合)
           │
           ▼
   ┌─────────────────────────┐
   │  veth → 桥接(bridge)  │  <---(容器内部虚拟接口,承载容器通信)
   └─────────────────────────┘
           │
           ▼
      [Docker 容器]

说明

  • 数据包在进入宿主机时首先由 PREROUTING 链处理,此时 NAT(DNAT)将外部目的地址转换为容器 IP;同时 mangle 表可以对包进行 MSS 调整、标记等处理。

  • 经过 PREROUTING 后,数据包进入 FORWARD 链,此处完成进一步的包处理(例如 TCPMSS 调整,确保经过 Docker 桥接后数据包大小符合 MTU 限制)。

  • 路由模块查找路由表,根据转换后的目标 IP 将数据包送入 docker bridge(veth 对),到达容器网络命名空间。


2. Docker 容器 → 外部服务器(出站流量)的 iptables 和路由流程

      [Docker 容器]
           │
           │  数据包通过容器内 veth 发出
           ▼
   ┌─────────────────────────┐
   │   veth → 桥接(bridge) │    <---(容器到宿主机)
   └─────────────────────────┘
           │
           │  数据包经过宿主机 FORWARD 链(mangle/filter),检查允许转发
           ▼
   ┌─────────────────┐
   │    FORWARD      │    <---(在 mangle 表中,TCP MSS规则生效)
   │  (mangle/filter)│
   └─────────────────┘
           │
           │  路由查表,确定下一跳为宿主机外网接口(例如 eth0)
           ▼
   ┌─────────────────┐
   │  POSTROUTING    │    <---(mangle 表 / nat表,进行 SNAT ,同时 TCPMSS 调整)
   │   (mangle/nat)  │
   └─────────────────┘
           │
           │  经过 SNAT(源地址转换为宿主机外网IP)
           ▼
     [外部服务器]

说明

  • 容器内部发出的数据包通过 veth / docker bridge 到达宿主机,进入 FORWARD 链(同时如果容器本地数据包从宿主机发出则走 OUTPUT 链,但这里以转发出的流量为主)。

  • POSTROUTING 链上,会进行 SNAT(把源地址改为宿主机外网地址),同时可通过 mangle 表中的 TCPMSS 规则(如 --clamp-mss-to-pmtu)调整 TCP 数据包的 MSS,确保不会超过实际路径 MTU,避免因 VXLAN 或其它封装导致包过大而丢包或碎片化。

  • 最后路由表确定后,数据包发送至外部服务器。iptables -t mangle -A FORWARD -o eth0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu


3. 重点:为什么在 POSTROUTING 链上加 TCPMSS 调整

  • 场景背景
    在 Docker 网络中,出站流量(以及跨节点的情况,如使用 VXLAN、Flannel 等隧道技术)容易遇到 MTU 不匹配问题。隧道封装会增加额外的报头(例如 VXLAN 通常增加约 50 字节),如果数据包尺寸超过物理链路的 MTU,会导致需要碎片化甚至丢包。

  • POSTROUTING 链的优势
    在数据包离开宿主机前,所有修改已经完成,选择在此阶段进行 TCP MSS 调整可以确保最终发出的 TCP SYN 包中的 MSS 值已经根据实际路径的 MTU(PMTU)进行了限制。
    使用如下规则:

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

    此规则会自动将 TCP MSS 限制为当前出接口的 MTU 减去 IP/TCP 头部,从而避免由于隧道封装等原因导致的数据包过大。

  • 总结
    在 POSTROUTING 阶段调 MSS,确保:

    • 数据包经过所有 NAT 修改后,出接口仍然符合物理链路 MTU 限制;

    • 隧道技术(如 VXLAN)带来的额外头部被考虑在内;

    • 整个出站流程中,TCP连接的建立不会因 MSS 设置不当而引起后续数据包传输失败。


4. 参考完整的裸 Docker 网络流程(包含 iptables 链和路由查找)

                        ┌─────────────────────────────┐
                        │         外部服务器          │
                        └─────────────▲───────────────┘
                                      │
                         (入站数据包通过宿主机外网接口)
                                      │
                                      │
                              ┌───────▼────────┐
                              │ PREROUTING     │
                              │ (mangle / nat) │
                              └───────▼────────┘
                                      │ DNAT(目的地址转换)
                                      │
                              ┌───────▼────────┐
                              │    FORWARD     │
                              │ (mangle/filter)│
                              └───────▼────────┘
                                      │
                              ┌───────▼────────┐
                              │ veth → 桥接    │
                              │ (docker0)      │
                              └───────▼────────┘
                                      │
                              ┌───────▼────────┐
                              │    Docker容器  │
                              └────────────────┘
                                      │
        (容器出站→经过docker0/veth→进入宿主机网络)
                                      │
                              ┌───────▼────────┐
                              │    FORWARD     │
                              │ (mangle/filter)│
                              └───────▼────────┘
                                      │ 路由查表:选择宿主机外网接口
                              ┌───────▼────────┐
                              │ POSTROUTING    │
                              │ (mangle/nat)   │
                              │ (SNAT & TCPMSS)│
                              └───────▼────────┘
                                      │
                              ┌───────▼────────┐
                              │  宿主机外网接口│
                              └───────▼────────┘
                                      │
                        ┌─────────────▼───────────────┐
                        │         外部服务器          │
                        └─────────────────────────────┘

说明

  • 图中展示的流程涵盖了数据包从外部进入到 Docker 容器,以及容器出站到外部的全流程。

  • 在 PREROUTING 阶段进行 DNAT,以确保外部数据包能找到目标容器。

  • FORWARD 阶段处理转发规则和包过滤。

  • POSTROUTING 阶段不仅负责 SNAT(将容器源地址改为宿主机的外网地址),还在 mangle 表中通过 TCPMSS 规则确保数据包 MSS 限制,防止因 MTU 问题产生碎片或丢包。


该流程图详细说明了裸 Docker 网络中 iptables(mangle/nat/filter表)与宿主机路由表配合,确保数据包在进入、转发、离开宿主机时均满足网络的 MTU 和安全要求。如果有其它细节需求,可以进一步展开讨论。

posted on 2025-04-16 11:45  吃草的青蛙  阅读(58)  评论(0)    收藏  举报

导航