使用internal:在默认docker-compose网络上为true会导致DNS超时缓慢

时间:2019-01-17 10:54:40

标签: docker docker-compose

背景

我们正在尝试在docker-compose设置中针对相当复杂的应用程序堆栈运行测试套件。到目前为止,一切工作正常。但是,我们想确保我们不会丢失任何外部依赖关系,也不会意外戳入我们不应该存在的任何内容(例如生产系统)。

这似乎是internal网络选项的基本用途。

问题

在撰写网络上使用internal: true时,容器无法按预期访问任何外部主机。到目前为止,一切都很好。问题在于,尝试解析组成的网络中不存在的主机名会花费很长时间。 gethostbyname()调用最多可能需要40秒才能失败,这会以各种方式破坏应用程序堆栈。

我希望能够在网络中配置DNS设置,以便为网络中不是容器的任何名称简单地立即给我NXDOMAIN,但到目前为止我还没有找到有任何迹象表明这是可能的。这似乎是一个显而易见的用例,我很难相信我是第一个遇到这个问题的人。

我在谷歌上搜索了很多东西,但到目前为止,还没有运气。

最小测试设置

给出一个docker-compose.yml

version: '3'

networks:
  default:
    internal: true

services:
  foo:
    image: debian:latest
    command: /bin/sleep 1000000000

  bar:
    build:
      context: ./bar
    command: /bin/true

还有bar/Dockerfile

FROM debian:latest
RUN apt-get update && apt-get install -y dnsutils bind9-host netcat-openbsd

然后:

$ docker-compose up -d
Creating network "foo_default" with the default driver
Creating foo_bar_1 ... done
Creating foo_foo_1 ... done
$ docker-compose run bar bash
root@f7f6bf6b65d4:/# time nslookup foo
Server:     127.0.0.11
Address:    127.0.0.11#53

Non-authoritative answer:
Name:   foo
Address: 192.168.96.3

real    0m0.010s
user    0m0.004s
sys 0m0.000s
root@f7f6bf6b65d4:/#

即时答案。到目前为止,一切都很好。

但是:

root@f7f6bf6b65d4:/# time nslookup foo.example.com 127.0.0.11
;; connection timed out; no servers could be reached

real    0m15.009s
user    0m0.004s
sys 0m0.004s
root@f7f6bf6b65d4:/#

不好。希望得到即时的NXDOMAIN响应。

更糟糕的是:

root@f7f6bf6b65d4:/# time getent hosts foo.example.com

real    0m40.034s
user    0m0.000s
sys 0m0.000s
root@f7f6bf6b65d4:/#

如前所述,这以多种方式破坏了我们的堆栈,并且大大降低了测试运行的速度。

作为参考,容器的/etc/resolv.conf为:

nameserver 127.0.0.11
options ndots:0

/etc/nssswitch.conf是:

passwd:         compat
group:          compat
shadow:         compat
gshadow:        files
hosts:          files dns
networks:       files
protocols:      db files
services:       db files
ethers:         db files
rpc:            db files
netgroup:       nis

2 个答案:

答案 0 :(得分:0)

我已经在Ubuntu 18.04 LTS上测试了此设置,但无法重现您的问题。

我得到:

root@cedfc68cfa30:/# time nslookup foo.example.com 127.0.0.11
Server:     127.0.0.11
Address:    127.0.0.11#53

** server can't find foo.example.com: NXDOMAIN


real    0m0.025s
user    0m0.008s
sys     0m0.016s

经过一些测试,结果证明systemd-resolved可以完成这项工作。

如果停止systemd-resolved并使用外部DNS解析器,则docker将发送源IP损坏的DNS查询,因为docker网络的iptables中没有MASQUERADE规则,然后您必须等待超时。 / p>

答案 1 :(得分:0)

我能够重现这些症状。对我来说,修复是两件事。

  1. 将 Docker 引擎从 19.x 升级到 20.10.3。升级到此版本后,我的 celery 容器能够连接到同一内部网络上的其他容器。但是,它无法连接到外部服务器,例如 google.com。

  2. 为有问题的容器添加了一个开放端口,因此在 docker-compose.yaml 中,我将以下内容添加到我的 celery 容器(又名服务):

ports:
    - "65123:65123"

将这个看似不需要的端口添加到我的 celery 容器后,它现在可以连接到外部服务器。

想法

我知道这是一个hacky的解决方法,但在我的情况下它有效并且打开一个没有任何监听的端口似乎比将整个网络设为外部更安全。我会重视有关此解决方法可能或可能不安全的任何想法。