虽然我没有在主机或两个容器上添加任何 iptables 规则,但是来自一个 docker 容器的数据包被修改并赋予了 docker 网络网关的 IP:
容器 1:
bash-5.0# ip route
default via 172.16.238.2 dev eth0
10.6.0.0/24 via 172.16.238.1 dev eth0
172.16.238.0/24 dev eth0 scope link src 172.16.238.7
bash-5.0# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
23: eth0@if24: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:10:ee:07 brd ff:ff:ff:ff:ff:ff
inet 172.16.238.7/24 brd 172.16.238.255 scope global eth0
valid_lft forever preferred_lft forever
bash-5.0# ping 1.1.1.1
PING 1.1.1.1 (1.1.1.1): 56 data bytes
--- 1.1.1.1 ping statistics ---
7 packets transmitted, 0 packets received, 100% packet loss
容器 2:
root@c8d6fa7eab4d:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
3: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
link/none
inet 100.71.37.47/32 scope global wg0
valid_lft forever preferred_lft forever
17: eth0@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:10:ee:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.16.238.2/24 brd 172.16.238.255 scope global eth0
valid_lft forever preferred_lft forever
root@c8d6fa7eab4d:/# tcpdump -i eth0 dst 1.1.1.1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
16:34:06.910548 IP 172.16.238.1 > one.one.one.one: ICMP echo request, id 5632, seq 36, length 64
16:34:07.910920 IP 172.16.238.1 > one.one.one.one: ICMP echo request, id 5632, seq 37, length 64
16:34:08.911322 IP 172.16.238.1 > one.one.one.one: ICMP echo request, id 5632, seq 38, length 64
16:34:09.911709 IP 172.16.238.1 > one.one.one.one: ICMP echo request, id 5632, seq 39, length 64
16:34:10.912143 IP 172.16.238.1 > one.one.one.one: ICMP echo request, id 5632, seq 40, length 64
16:34:11.912504 IP 172.16.238.1 > one.one.one.one: ICMP echo request, id 5632, seq 41, length 64
16:34:12.912932 IP 172.16.238.1 > one.one.one.one: ICMP echo request, id 5632, seq 42, length 64
^C
7 packets captured
9 packets received by filter
0 packets dropped by kernel
主持人:
root@raspberrypi:~# iptables -t nat -L
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DOCKER all -- anywhere anywhere ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- !172.16.238.0/24 172.16.238.2
MASQUERADE all -- !172.16.238.0/24 172.16.238.2
MASQUERADE all -- 172.17.0.0/16 anywhere
MASQUERADE all -- 172.16.238.0/24 anywhere
MASQUERADE all -- !172.16.238.0/24 172.16.238.2
MASQUERADE all -- 10.6.0.0/24 anywhere /* wireguard-nat-rule */
MASQUERADE all -- !172.16.238.0/24 172.16.238.2
MASQUERADE all -- 172.16.238.0/24 anywhere
MASQUERADE tcp -- 172.16.238.4 172.16.238.4 tcp dpt:https
MASQUERADE tcp -- 172.16.238.4 172.16.238.4 tcp dpt:http
MASQUERADE tcp -- 172.16.238.4 172.16.238.4 tcp dpt:domain
MASQUERADE udp -- 172.16.238.4 172.16.238.4 udp dpt:domain
MASQUERADE tcp -- 172.16.238.5 172.16.238.5 tcp dpt:https
MASQUERADE tcp -- 172.16.238.5 172.16.238.5 tcp dpt:http
MASQUERADE tcp -- 172.16.238.5 172.16.238.5 tcp dpt:domain
MASQUERADE udp -- 172.16.238.5 172.16.238.5 udp dpt:domain
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
DOCKER all -- anywhere !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain DOCKER (2 references)
target prot opt source destination
RETURN all -- anywhere anywhere
RETURN all -- anywhere anywhere
DNAT tcp -- anywhere 192.168.178.2 tcp dpt:https to:172.16.238.4:443
DNAT tcp -- anywhere 192.168.178.2 tcp dpt:http to:172.16.238.4:80
DNAT tcp -- anywhere 192.168.178.2 tcp dpt:domain to:172.16.238.4:53
DNAT udp -- anywhere 192.168.178.2 udp dpt:domain to:172.16.238.4:53
DNAT tcp -- anywhere 192.168.178.3 tcp dpt:https to:172.16.238.5:443
DNAT tcp -- anywhere 192.168.178.3 tcp dpt:http to:172.16.238.5:80
DNAT tcp -- anywhere 192.168.178.3 tcp dpt:domain to:172.16.238.5:53
DNAT udp -- anywhere 192.168.178.3 udp dpt:domain to:172.16.238.5:53
# Warning: iptables-legacy tables present, use iptables-legacy to see them
root@raspberrypi:~# iptables-legacy -S -t nat
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
答案1
容器间连接 (ICC) 默认启用,并且自动将容器链接在一起无需使用--link
或定义network
。
如果你想禁用它,请icc: false
在 Docker 守护进程配置中设置(/etc/daemon.json
)
未定义或设置为 true 会使 Docker 守护进程在创建容器的同时创建连接的网络。这些网络就是您看到的 iptables 规则的来源。
更多内容请见官方 Docker桥接网络教程。
答案2
我遇到了同样的问题,对我来说,我相信这与以下因素有关:
https://github.com/moby/moby/issues/43440
问题是我创建了一个 Docker 网络,然后删除它并再次创建另一个。Docker 足够智能,可以重用相同的 IP 范围(在我的情况下为 172.18.0.0/16),但防火墙似乎会跟踪前一个 Docker 网络:
# iptables -t nat -S
...
-A POSTROUTING -s 172.18.0.0/16 ! -o br-4a99e748fcc1 -j MASQUERADE
-A POSTROUTING -s 172.18.0.0/16 ! -o br-9dbbf26e610f -j MASQUERADE
...
其中 br-4a99e748fcc1 确实是现有的接口,但 br-9dbbf26e610f 是剩余的接口……(已从firewalld 中删除但并未永久抑制)。
# ip add show br-9dbbf26e610f
Device "br-9dbbf26e610f" does not exist.
如果我删除了错误的行,一切都会恢复正常:NAT发夹(源IP被网关地址替换)不再发生:
# iptables -t nat -D POSTROUTING -s 172.18.0.0/16 ! -o br-9dbbf26e610f -j MASQUERADE
这完全说得通:规则规定,任何数据包
- 源自源范围 172.18.0.0/16
- 不通过 br-9dbbf26e610f 出去
应该经过伪装......当然,没有数据包通过那个不存在的接口出去(!)所以这会导致伪装 Docker 网络中的所有 IP。
编辑:firewall-cmd--reload 再次创建规则!
正如上面的 Docker 问题中所述,我最终决定firewall-cmd
从区域中删除僵尸接口docker
。这必须在 Docker 守护进程关闭时完成,因为否则它似乎会跟踪这些僵尸接口……
systemctl stop docker
for interface in $(firewall-cmd --zone=docker --list-interfaces)
do
if ! ip link ls "${interface}" >/dev/null 2>&1
then
firewall-cmd --zone=docker --remove-interface="${interface}"
firewall-cmd --runtime-to-permanent
firewall-cmd --reload
fi
done
systemctl start docker