在机器上安装Docker之后,运行一个MySQL容器

sudo docker run mysql:5.7 -p 3306:3306

使用ufw设置除了内网机器172.16.0.100以外,拒绝任何网络访问

sudo ufw default deny incoming
sudo ufw allow from 172.16.0.100 to any port 3306

经过测试验证发现无效,其他机器依旧可以正常访问3306端口,查询iptables规则

~ ➤ sudo iptables -L -n                                                                                                                  
[sudo] password for chancel: 
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy DROP)
target     prot opt source               destination         
DOCKER-USER  all  --  0.0.0.0/0            0.0.0.0/0     
DOCKER-ISOLATION-STAGE-1  all  --  0.0.0.0/0            0.0.0.0/0      
...

Chain DOCKER-ISOLATION-STAGE-1 (1 references)
target     prot opt source               destination         
DOCKER-ISOLATION-STAGE-2  all  --  0.0.0.0/0            0.0.0.0/0           
DOCKER-ISOLATION-STAGE-2  all  --  0.0.0.0/0            0.0.0.0/0           
DOCKER-ISOLATION-STAGE-2  all  --  0.0.0.0/0            0.0.0.0/0           
DOCKER-ISOLATION-STAGE-2  all  --  0.0.0.0/0            0.0.0.0/0           
RETURN     all  --  0.0.0.0/0            0.0.0.0/0           
        

Chain DOCKER-USER (1 references)
target     prot opt source               destination         
RETURN     all  --  0.0.0.0/0            0.0.0.0/0 

发现DOCKER有自己的一套iptables规则,在官方文档Docker and iptables有着如下描述

All of Docker’s iptables rules are added to the DOCKER chain. Do not manipulate this chain manually. If you need to add rules which load before Docker’s rules, add them to the DOCKER-USER chain. These rules are applied before any rules Docker creates automatically.

所以ufwfirewalld设置的规则对Docker来说是无效的,如果要实现控制容器的外部访问,可以对DOCKER-USER链进行操作,如下

iptables -I DOCKER-USER -i eth0 ! -s 172.16.0.100 -j DROP

其中eth0是你的外部接口名称,使用ip a可以查询外部接口名称