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

Las*_*sse 5 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
Run Code Online (Sandbox Code Playgroud)

bar/Dockerfile

FROM debian:latest
RUN apt-get update && apt-get install -y dnsutils bind9-host netcat-openbsd
Run Code Online (Sandbox Code Playgroud)

然后:

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

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

但:

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

坏的。希望立即得到NXDOMAIN答复。

更糟糕:

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

real    0m40.034s
user    0m0.000s
sys 0m0.000s
root@f7f6bf6b65d4:/#
Run Code Online (Sandbox Code Playgroud)

如前所述,这会以多种方式破坏我们的堆栈,并大大减慢测试运行速度。

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

nameserver 127.0.0.11
options ndots:0
Run Code Online (Sandbox Code Playgroud)

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

Jac*_*unk 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
Run Code Online (Sandbox Code Playgroud)

经过一些测试后发现,systemd-resolved 具有完成这项工作所需的魔力。

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