我无法从 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
。因此,我添加了类似的规则以允许我的容器访问所需的其他主机端口,我认为这可能是打开主机网络访问容器的更精确的方法。