Quarter

一个还没怎么睡醒的前端开发

让 Docker 向 UFW 低头

默认分类 0 评

默认情况下,创建容器如果绑定了端口,则 docker 会自动修改 iptables 打开这个端口。然而 UFW 并不会显示这个规则,这就导致了不管使用 UFW 做什么限制,docker 绑定的这个端口都是开放的。

问题所在

默认情况下,创建容器如果绑定了端口,则 docker 会自动修改 iptables 打开这个端口。然而 UFW 并不会显示这个规则,这就导致了不管使用 UFW 做什么限制,docker 绑定的这个端口都是开放的。

可以使用 iptables -L DOCKER 查看 docker 在防火墙上开的洞,而且官方并不打算修复这个问题。

那么现在要做的就是禁止 docker 自作聪明的修改 iptables,并使用 UFW 来限制 docker 的端口开放。

1 启用 UFW

在启动 UFW 之前务必添加规则允许 ssh 通过,否则...

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 的方式不起作用了。

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": ["114.114.114.114", "223.5.5.5"],
  "iptables": false
}
EOF

systemctl daemon-reload && systemctl restart docker

检查 docker 的启动命令

ps aux | grep docker | grep -v grep

3 配置 docker 的 NAT

完成上面两步之后 docker 就应该处于 UFW 的限制之下了。如果重启之后发现 docker 容器无法连接外网的话,还需要这里配置:

cat << EOF >> /etc/ufw/before.rules

# docker
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING ! -o docker0 -s 172.17.0.0/16 -j MASQUERADE
COMMIT
EOF

ufw disable && ufw enable

检查 docker 容器是否能连接外网

docker run -it --rm alpine ping -c 1 114.114.114.114

列出 docker 的网络

docker network ls

其他

nginx 无法获取真实 ip

可以使用 host 模式启动容器

docker run --net=host ...