容器的网络是怎么被转换的?端口映射在 iptables 里是哪几条规则?conntrack 表里长什么样?这篇进入 Docker Desktop 的虚拟机读 nat 表和 /proc/net/nf_conntrack,并用包计数验证流量到底走没走 DNAT。
虚拟机的 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 后端。
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 条目。
虚拟机里谁在监听发布端口 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 秒。