bigywater.tech
Docker · 62

连接跟踪:NAT 条目与大量短连接

容器的网络是怎么被转换的?端口映射在 iptables 里是哪几条规则?conntrack 表里长什么样?这篇进入 Docker Desktop 的虚拟机读 nat 表和 /proc/net/nf_conntrack,并用包计数验证流量到底走没走 DNAT。

MASQUERADE
172.17.0.0/16 的容器出网时被转换成虚拟机的地址
0 → 0 对 0 → 3
发布端口的 DNAT 规则包计数:Mac 访问 3 次不变,容器经 172.17.0.1 访问 3 次增加 3
262144
虚拟机的 nf_conntrack_max

规则

实测 · 本机执行输出
  虚拟机的 iptables 版本:iptables v1.8.9 (nf_tables)
  默认 bridge(docker0,172.17.0.0/16)相关的 nat 规则:
    -A POSTROUTING -o docker0 -m addrtype --src-type LOCAL -j MASQUERADE
    -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
  发布端口 -p 9830:8000 之后,nat 表新增的规则:
    -A DOCKER -p tcp -m tcp --dport 9830 -j DNAT --to-destination 172.17.0.2:8000
    -A POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 8000 -j MASQUERADE
  filter 表(FORWARD / DOCKER)里新增的与这个端口相关的规则:-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 8000 -j ACCEPT

出网靠 POSTROUTING … MASQUERADE;发布端口增加 DOCKER 链里的 DNAT(目的地址改成容器的 IP 和端口),外加一条 MASQUERADE 和 filter 表的放行规则;容器删除后这些规则被清掉。这台虚拟机的 iptables 是 nf_tables 后端。

conntrack 条目

实测 · 本机执行输出
    ipv4 2 tcp 6 72 SYN_SENT src=<容器IP> dst=20.205.243.166 sport=40525 dport=443 [UNREPLIED] src=20.205.243.166 dst=<本机局域网IP> sport=443 dport=40525
    ipv4 2 tcp 6 116 SYN_SENT src=<容器IP> dst=20.205.243.166 sport=37925 dport=443 [UNREPLIED] src=20.205.243.166 dst=<本机局域网IP> sport=443 dport=37925

一个条目同时记录两个方向:发出去的方向是容器地址,回来的方向目的地址是虚拟机的地址,说明源地址被转换了。我观察到的连接停在 SYN_SENT [UNREPLIED](这个环境里连外网 443 没有成功),所以这里没有看到完整的 ESTABLISHED 条目。

Mac 的流量不走 DNAT

实测 · 本机执行输出
  虚拟机里谁在监听发布端口 9830:LISTEN 0.0.0.0:9830 users:(("dockerd",pid=283,fd=110))
  Mac 上 curl 127.0.0.1:9830 3 次之后,DNAT 规则的包计数:0 → 0
  另一个容器经 172.17.0.1:9830 访问 3 次之后,DNAT 规则的包计数:0 → 3

虚拟机里监听发布端口的是 dockerd 自己;Mac 访问时 DNAT 规则的计数不变,说明这条路径经过 dockerd 的监听而不是 DNAT。而容器经 172.17.0.1 访问发布端口时,DNAT 计数会增加。这是在 Docker Desktop 上的观察,Linux 宿主机上的路径我没有测。

容量

实测 · 本机执行输出
  nf_conntrack_max = 262144;当前 count 约 1352(虚拟机里还有其它容器的连接)
  nf_conntrack_tcp_timeout_established = 432000 秒
  nf_conntrack_tcp_timeout_time_wait = 120 秒
  nf_conntrack_udp_timeout = 30 秒
  nf_conntrack_udp_timeout_stream = 120 秒
  删除服务容器之后,刚才新增的 2 条 nat 规则还在吗?都没了

conntrack 表上限 262144,当前约 1352 条;已建立 TCP 连接的超时是 432000 秒(5 天),TIME_WAIT 120 秒,UDP 30 秒。

分步演示

NAT 与 conntrack
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Docker Desktop(Engine 29.8.2,容器跑在 Docker Desktop 自带的 Linux 虚拟机里,内核与宿主机的 macOS 不同);镜像为 linux/arm64;需要看虚拟机内部时用特权容器 + nsenter;计时用 time / date +%s%N,数字每次运行会有小幅抖动。规则与 conntrack 读自虚拟机(特权容器加 nsenter,方法见 c19);容器 IP 在输出中替换为占位符;虚拟机里同时还有 kind 等其它容器的规则和连接,文中只引用与本实验相关的;实验后已删除容器
    • 没有验证:入站 DNAT 连接的完整 conntrack 条目(我读 /proc/net/nf_conntrack 时没有抓到)、ESTABLISHED 条目、conntrack 表满时的丢包、nftables 视角的规则、--iptables=false 的效果、Linux 宿主机上的 docker-proxy
    京ICP备2026067502号-1京公网安备11010502063487号