Docker: 如何重新创建Docker的额外iptables规则?

54
当docker守护进程启动时,它会向iptables添加一些规则。当所有规则通过`iptables -F`删除时,我必须停止和重新启动docker守护进程以重新创建docker规则。
有没有一种方法可以让docker重新添加它的附加规则?
4个回答

57

最佳方法是重新启动您的docker服务,这样它将重新将docker规则添加到iptables中。(在基于deb的系统中: sudo service docker restart)

但是,如果您只想恢复这些规则而无需重启服务,我已经保存了我的规则,因此您可以检查并调整它以使其适用于您,然后使用sudo iptables-restore ./iptables-docker-ports.backup加载。

编辑并保存到./iptables-docker-ports.backup

# Generated by iptables-save v1.4.21 on Thu Apr 30 20:48:42 2015
*nat
:PREROUTING ACCEPT [18:1080]
:INPUT ACCEPT [18:1080]
:OUTPUT ACCEPT [22:1550]
:POSTROUTING ACCEPT [22:1550]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A POSTROUTING -s 172.17.0.1/32 -d 172.17.0.1/32 -p tcp -m tcp --dport 80 -j MASQUERADE
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 3001 -j DNAT --to-destination 172.17.0.1:80
COMMIT
# Completed on Thu Apr 30 20:48:42 2015
# Generated by iptables-save v1.4.21 on Thu Apr 30 20:48:42 2015
*filter
:INPUT ACCEPT [495:53218]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [480:89217]
:DOCKER - [0:0]
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER -d 172.17.0.1/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 80 -j ACCEPT
COMMIT
# Completed on Thu Apr 30 20:48:42 2015

1
非常感谢,这是我找到的唯一一篇帖子,其中提供了重置我的iptables规则的默认docker配置,太完美了! - meucaa
8
这将停止您的容器! 重新启动docker服务会停止所有容器。 这不是解决方案。 - John
实际上,我简直不敢相信这是被接受的答案。 :-) - Tony
现在我的容器无法访问互联网。 - undefined

10
如果您在主机上运行Ubuntu,可以在启动docker守护程序后使用iptables-save实用程序将iptables规则保存到文件中。然后,一旦清除旧规则,您只需使用iptables-restore和保存的规则文件即可恢复原始docker规则。
如果不想恢复所有旧的iptables规则,可以修改保存的规则文件以仅保留所需的规则。
如果您正在运行另一个操作系统,则可能会找到类似的替代方案。

3
Docker的规则是否总是不变的?我能将它们永久地添加到我的iptables-restore配置文件中吗? - Hubro
具体来说:我使用iptables-persistent和自定义规则文件作为防火墙。每当我需要打开一个端口时,我编辑我的规则文件并使用iptables-apply应用它。我在规则文件中保持清晰的结构和大量注释以进行文档记录,因此覆盖它不是一个选项。 - Hubro
1
在盲目保存/恢复规则时要小心,因为容器的IP地址在重新启动时可能会发生变化! - pHiL

9

在默认配置下,当Docker以bridge模式运行时,会(大量)操作iptables 除非你禁用它(然后你需要配置自己的NAT规则)。

默认的网络相关配置可能如下,尽管配置文件/etc/docker/daemon.json可能不存在(目前无法打印有效配置):

{
"userland-proxy": true,
"iptables": true,
"ip-forward": true,
"ip-masq": true,
"ipv6": false
}

在Docker守护进程启动后,它会注入以下规则(在filter中):
-N DOCKER
-N DOCKER-ISOLATION-STAGE-1
-N DOCKER-ISOLATION-STAGE-2
-N DOCKER-USER

-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT

-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN

为了理解Docker的作用,这里有一份由Docker生成的iptables规则列表iptables rules),并配有简短的说明。如果在Docker守护程序和一些容器正在运行时清除iptables规则,则可能会破坏对现有容器的访问(但可能不会破坏任何内容,有关此事的更多信息请参见下文)。
在执行service docker restart之后,所有默认规则都将被注入到防火墙中(您可以通过运行iptables-saveiptables -Siptables -S -t nat来检查)。假设您想要保持容器运行,并仅生成缺少的NAT规则。 docker ps给出了正在运行的容器列表:
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                         NAMES
865569da8d36        nginx               "nginx -g 'daemon of…"   17 hours ago        Up 17 hours         0.0.0.0:4564->80/tcp, 0.0.0.0:32237->80/tcp   jovial_sammet

通过 docker inspect 命令,我们可以获取端口映射信息。

$ docker inspect -f '{{.NetworkSettings.Ports}}' 865569da8d36
map[80/tcp:[{0.0.0.0 4564} {0.0.0.0 32237}]]

现在我们只需要 Docker 容器的内部 IP 地址:
$ docker inspect -f '{{.NetworkSettings.IPAddress}}' 865569da8d36
172.17.0.2

现在我们可以使用一些bash/jq生成动态的iptables规则
$ bash docker_iptables --noop
iptables -A DOCKER -d 172.17.0.2
iptables -t nat -A DOCKER ! -i docker0 -p tcp -m tcp --dport 4564 -j DNAT --to-destination 172.17.0.2:80
iptables -A DOCKER -d 172.17.0.2
iptables -t nat -A DOCKER ! -i docker0 -p tcp -m tcp --dport 32237 -j DNAT --to-destination 172.17.0.2:80

因此,回答这个问题是:不行,除非停止所有容器。但规则可以手动重新添加(注意:此脚本不涵盖所有Docker功能,例如,如果您正在公开运行在其他网络中的某些服务)。
当您使用暴露端口(-p)启动Docker容器时:
docker run --rm -d -p 32237:80 -p 4564:80 nginx

Docker还会启动 docker-proxy。那是什么?

$ netstat -tulpn | grep docker-proxy
tcp        0      0 0.0.0.0:32237           0.0.0.0:*               LISTEN      20487/docker-proxy  
tcp        0      0 0.0.0.0:4564            0.0.0.0:*               LISTEN      20479/docker-proxy

Linux内核不允许路由环回流量,因此无法对源自127.0.0.0/8的数据包应用netfilter NAT规则。docker-proxy通常被视为解决此类问题的不优雅方法

当您恢复不带Docker规则的iptables时,容器端口可能仍然可通过docker-proxy使用。但是这可能会在网络方面带来一些性能问题,因为docker-proxy不会像内核的netfilter那样快。


0
除了上面所有的好答案之外,还应该删除Docker创建的网络设备,ip route del xxx/x,找出Docker创建的所有虚拟设备,并将它们删除。
今天我在清理一个糟糕的安装时,一开始就错过了这一步,网络问题一直存在。为了完全清除,必须删除这些路由。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接