Appearance
默认情况下,创建容器如果绑定了端口,则 docker 会自动修改 iptables 打开这个端口。然而 UFW 并不会显示这个规则,这就导致了不管使用 UFW 做什么限制,docker 绑定的这个端口都是开放的。
问题所在
默认情况下,创建容器如果绑定了端口,则 docker 会自动修改 iptables 打开这个端口。然而 UFW(uncomplicated firewall) 并不会显示这个规则,这就导致了不管使用 UFW 做什么限制,docker 绑定的这个端口都是开放的。
可以使用 iptables -L DOCKER
查看 docker 在防火墙上开的洞,而且官方并不打算修复这个问题。
那么现在要做的就是禁止 docker 自作聪明的修改 iptables,并使用 UFW 来限制 docker 的端口开放。
1 启用 UFW
在启动 UFW 之前务必添加规则允许 ssh 通过,否则...
bash
ufw allow ssh
ufw allow from 172.17.0.0/16 # 允许 docker 容器之间相互访问
ufw default deny incoming
ufw default allow outgoing
ufw default allow routed
ufw disable && ufw enable
2 禁止 docker 更新 iptables
Ubuntu 16.04 之后使用 systemd 替代 upstart,所以在 /etc/default/docker
修改 DOCKER_OPTS
加上 --iptables=false
的方式不起作用了。
bash
mkdir -p /lib/systemd/system/docker.service.d
cat << EOF > /lib/systemd/system/docker.service.d/override.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd
EOF
cat << EOF > /etc/docker/daemon.json
{
"hosts": ["fd://"],
"dns": ["8.8.8.8", "8.8.4.4"],
"iptables": false
}
EOF
systemctl daemon-reload && systemctl restart docker
检查 docker 的启动命令
bash
ps aux | grep docker | grep -v grep
3 配置 docker 的 NAT
完成上面两步之后 docker 就应该处于 UFW 的限制之下了。如果重启之后发现 docker 容器无法连接外网的话,还需要这里配置:
bash
cat << EOF >> /etc/ufw/before.rules
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING ! -o docker0 -s 172.17.0.0/16 -j MASQUERADE
COMMIT
EOF
检查 docker 容器是否能连接外网
bash
docker run -it --rm alpine ping -c 1 8.8.8.8
列出 docker 的网络
bash
docker network ls
其他
nginx 无法获取真实 ip
可以使用 host 模式启动容器
bash
docker run --net=host ...
docker for macOS
There is no docker0 bridge on macOS
在 macOS 上是看不到 docker0 这个网桥的,所以容器是无法通过 172.0.0.1
来向宿主机通信,这时候就可以使用 docker.for.mac.localhost
来连接(v17.06+ only)。
然而容器内还是无法获取客户端的真实 IP 的,也是一个几年前的坑。
有人提出3个方案:
一是使用 --net=host
启动容器,二是 disable the userland proxy
,然而在 macOS 上并没什么卵用。
最后一个令人窒息的操作,即在宿主机开一个 nginx 反向代理,在请求头加上 IP。