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

Dyn*_*nom 22 iptables docker

我无法从 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
Run Code Online (Sandbox Code Playgroud)

我的(相关)主机接口:

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
Run Code Online (Sandbox Code Playgroud)

我运行一个 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.
Run Code Online (Sandbox Code Playgroud)

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

$ ping google.com
^C
$ ping user.skydns.local
^C
Run Code Online (Sandbox Code Playgroud)

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

$ 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
Run Code Online (Sandbox Code Playgroud)

我的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
Run Code Online (Sandbox Code Playgroud)

这里的重点不是访问公共主机,而是内部主机,使用主机上可用的本地 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)
Run Code Online (Sandbox Code Playgroud)

我搜索、阅读并应用了不同的示例 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
Run Code Online (Sandbox Code Playgroud)

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

1
Run Code Online (Sandbox Code Playgroud)

Lau*_*scu 17

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

-A INPUT -i docker0 -j ACCEPT
Run Code Online (Sandbox Code Playgroud)

  • 对于使用 UFW 的人,这是我为允许从 Docker 容器到主机的所有通信所做的操作: ufw allow in on docker0 (6认同)
  • Dynom,你可能想从中吸取的教训是记录你所有的拒绝是有用的,例如`iptables -A INPUT -j LOG`。“IN=docker0”标记对于确定需要进行哪些规则调整非常有用。不要剥夺 Laurentiu 的工作,这很棒 - 我的 +1! (2认同)
  • 我必须使用以下规则才能使 docker compose 正常工作:`-A INPUT !-i eth0 -s 172.16.0.0/12 -j 接受` (2认同)