Iptables 规则集,以便 docker 容器可以访问主机 IP 上的服务

Iptables 规则集,以便 docker 容器可以访问主机 IP 上的服务

我无法从 docker 容器访问主机私有接口 (ip)。我相当确定这与我的 Iptables 规则(或可能是路由)有关。当我将标志添加--net=host到 时docker run,一切都按预期工作。同样,当我指定 INPUT 策略遵循自由 时-P INPUT ACCEPT,一切也按我预期的方式工作。然而,这些都是我想要避免的不受欢迎和不安全的选择。

由于它不是特定于我的服务(DNS)的,因此我将其排除在问题之外,因为将其与docker结合搜索会产生不同的(流行的)问题区域,从而给搜索结果增加噪音。

另外,Docker 容器的链接也不是一个可行的选择,因为某些容器需要使用 --net=host 选项运行,从而阻止链接,并且我想在可能的情况下创建一致的情况。

我有以下 Iptables 规则。我假设是 CoreOS、Digital Ocean 和 Docker 的组合。

-P INPUT DROP
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N DOCKER
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth1 -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 3 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 11 -j ACCEPT
-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

我的(相关)主机接口:

3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    inet 10.129.112.210/16 brd 10.129.255.255 scope global eth1
       valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    inet 172.17.42.1/16 scope global docker0
       valid_lft forever preferred_lft forever

我运行一个docker容器:

$ docker run --rm -it --dns=10.129.112.210 debian:jessie # Specifying the DNS is so that the public DNS servers aren't used.

此时我希望能够使用本地服务,绑定在 10.129.112.210:53。因此以下内容应该会产生回复:

$ ping google.com
^C
$ ping user.skydns.local
^C

当我从我的主机运行相同的命令时:

$ ping photo.skydns.localPING photo.skydns.local (10.129.112.206) 56(84) bytes of data.
64 bytes from 10.129.112.206: icmp_seq=1 ttl=64 time=0.790 ms
^C

我的 resolv.conf

$ cat /etc/resolv.conf
nameserver 10.129.112.210
nameserver 127.0.0.1
nameserver 8.8.8.8
nameserver 8.8.4.4

这里的重点不是访问公共主机,而是使用主机上可用的本地 DNS 服务(通过另一个 docker 实例)访问内部主机。

为了进一步说明这一点(我的 ascii 艺术设计技能超越了我的 iptables fu,所以现在应该已经足够了):

 ______________________________________________
|  __________________________           Host   |
| |   Docker DNS container   |                 |
|  ``````````````````````|```                  |
|                        |                     |
|     ,----------,---( private n. interface )  |
|     |          |                             |
|     |          |   ( public  n. interface )---
|     |          |                             |
|     |          |   ( loopbck n. interface )  |
|     |          |                             |
|     |          |                             |
|     |        __|_______________________      |
|     |       | Docker service container |     |
|     |        ``````````````````````````      |
|     |                                        |
|     |                                        |
| [ Local host service using DNS. ]            |
|                                              |
|______________________________________________|

  private (host) network interface: eth1 (10.129.0.0/16)
  Docker network interface: docker0 (172.17.0.0/16)

我搜索、阅读并应用了不同的 Iptables 配置示例,但是我对更“高级”的 Iptables 规则了解甚少,无法理解发生了什么,从而无法获得期望的结果。

输出iptables -t nat -nL

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0

Chain DOCKER (2 references)
target     prot opt source               destination

输出cat /proc/sys/net/ipv4/ip_forward

1

答案1

容器使用docker0接口与主机通信。要允许来自容器的流量,请添加:

-A INPUT -i docker0 -j ACCEPT

答案2

我遇到过非常类似的情况,但添加-A INPUT -i docker0 -j ACCEPT将打开通过 docker 主机的 eth0 接口对容器的所有访问,这绝对不是我想要的。

而且由于我注意到我的容器对主机接口的访问受限(例如仅端口 22),而不是完全关闭主机网络,因此我检查了我的 iptables 规则,并在链 IN_public_allow 中找到了一条规则,该规则应该对此负责。规则是-A IN_public_allow -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT。因此,我添加了类似的规则以允许我的容器访问所需的其他主机端口,我认为这可能是打开主机网络访问容器的更精确的方法。

相关内容