容器与外部网络通信
决定容器是否可以访问外网取决于两个因素:
主机是否会转发IP数据包。这取决于转发系统内的ip_forward这个参数的配置。如果ip_forward值为1,数据包就可以被转发。Docker会使用—ip_forward=true的默认设置,一旦你docker服务启动docker会将系统的ip_forward的值修改为1。使用-ip_forward=false对系统没有改变。通常设置方法如下:
$ sysctl net.ipv4.conf.all.forwarding
net.ipv4.conf.all.forwarding = 0
$ sysctl net.ipv4.conf.all.forwarding=1
$ sysctl net.ipv4.conf.all.forwarding
net.ipv4.conf.all.forwarding = 1
设置这个值很重要,它将决定你的容器是否可以与外部通信以及容器间的通信。在多网桥系统中,内嵌的容器也需要配置此项。
你的iptables防火墙是否允许特殊连接。当deamon启动的时候,如果你设置—iptables=false,Docker将不会改变主机的iptables的防火墙规则。否则,Docker将追加规则到DOCKER filter chain
Docker 不会删除或修改已经存在在DOCKER filter chain中的规则。这允许用户进一步创建限制访问容器的任何规则。
Docker的默认规则是允许所有的外部IPs。如果只是想允许一个IP连接到容器,在DOCKER filter chain的顶部增加一条否定规则:
$ iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP
这将只允许 8.8.8.8这个IP连接到容器。
容器间互相访问
决定容器能否互相访在系统层面上问取决于两个因素:
网络的拓扑结构是否已经连接到容器的网络接口。默认情况下,Docker会把所有的容器附加到docker0网桥下,并为两个容器间的包传输提供路径。
iptables是否允许特殊连接?如果你把设置 —iptables=false,当守护进程启动时,Docker不会改变你的系统iptables规则。另外,如果你保留默认设置 —icc=true,Docker服务器或向FORWARD链添加一个带有全局ACCEPT策略的默认规则。如果不保留默认设置即—icc=false,系统会把策略设为DROP.
使用docker都希望ip_forward 是打开的,至少使容器间的通讯成为可能。
但是否同意 —icc=true 或者更改为 —icc=false 使得iptables 可以保护容器以及宿主主机不被任意地端口扫描、避免被已经被渗透的容器所访问,这是一个策略问题。
(在ubuntu,是编辑/etc/default/docker文件中的DOCKER_OPTS参数,然后重启docker服务)
如果你选择最安全的设置 —icc=false ,那么当你想让它们彼此提供服务的时候如何让它们相互通讯?
答案是:使用前文提到的 —link=CONTAINER_NAME:ALIAS 选项。如果docker守护进程正在以 —icc=false 和 —iptables=true 参数运行,当以选项 —link= 执行 docker run 命令时,docker服务将插入一部分 iptables ACCEPT 规则使得新容器可以连接其他容器所暴露出来的端口(此端口指前文在 Dockerfile 中提到的EXPOSE这一行)。更多详细文档介绍请看:容器互联。
注意: —link 选项中的 CONTAINER_NAME 的值必须是 docker自动分配的容器名称,比如stupefied_pare,或者是在执行docker run 的时候用—name=指定的容器名称. 这不能使一个docker无法识别的主机名
你可以在你的Docker主机上运行iptables命令,来观察FORWARD链是否有默认的ACCEPT或DROP策略
# When --icc=false, you should see a DROP rule:
$ sudo iptables -L -n
...
Chain FORWARD (policy ACCEPT)
target prot opt source destination
DOCKER all -- 0.0.0.0/0 0.0.0.0/0
DROP all -- 0.0.0.0/0 0.0.0.0/0
...
# When a --link= has been created under --icc=false,
# you should see port-specific ACCEPT rules overriding
# the subsequent DROP policy for all other packets:
$ sudo iptables -L -n
...
Chain FORWARD (policy ACCEPT)
target prot opt source destination
DOCKER all -- 0.0.0.0/0 0.0.0.0/0
DROP all -- 0.0.0.0/0 0.0.0.0/0
Chain DOCKER (1 references)
target prot opt source destination
ACCEPT tcp -- 172.17.0.2 172.17.0.3 tcp spt:80
ACCEPT tcp -- 172.17.0.3 172.17.0.2 tcp dpt:80