当主机使用 dnsmasq 并且 Google 的 DNS 服务器有防火墙时,DNS 在 docker 容器中不起作用?

新手上路,请多包涵

症状是:宿主机有正常的网络访问权限,但是在容器中运行的程序却无法解析 DNS 名称(在进一步调查之前可能看起来是“无法访问网络”)。

 $ sudo docker run -ti mmoy/ubuntu-netutils /bin/bash
root@082bd4ead733:/# ping www.example.com
... nothing happens (timeout) ... ^C
root@082bd4ead733:/# host www.example.com
... nothing happens (timeout) ... ^C

(docker 镜像 mmoy/ubuntu-netutils 是一个基于 Ubuntu 的简单镜像,包含 pinghost ,在这里很方便,因为网络中断,我们不能 apt install 这些工具)

问题在于 docker 自动将 Google 的公共 DNS 配置为容器内的 DNS 服务器:

 root@082bd4ead733:/# cat /etc/resolv.conf
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN

nameserver 8.8.8.8
nameserver 8.8.4.4

这仅适用于许多配置,但当主机运行在 Google 的公共 DNS 被某些防火墙规则过滤的网络上时,显然不起作用。

发生这种情况的原因是:

  • Docker 首先尝试在主机和容器内配置相同的 DNS 服务器。
  • 主机运行 dnsmasq ,一种 DNS 缓存服务。 dnsmasq 充当 DNS 请求的代理,因此主机的 /etc/resolve.conf 中的明显 DNS 服务器是 nameserver 127.0.1.1 ,即 localhost。
  • 主机的 dnsmasq 仅侦听来自 localhost 的请求并阻止来自 docker 容器的请求。
  • 由于在 docker 中使用 127.0.1.1 不起作用,docker 退回到 Google 的公共 DNS,这也不起作用。

Docker 容器中的 DNS 损坏可能有多种原因。这个问题(和答案)涵盖了以下情况:

  • 使用 dnsmasq。要检查是否是这种情况:
  • Google 的公共 DNS 已被过滤。运行 host www.example.com 8.8.8.8 。如果它失败或超时,那么你就处于这种情况。

在此配置中获得正确 DNS 配置的解决方案是什么?

原文由 Matthieu Moy 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 817
2 个回答

一个干净的解决方案是配置 docker+dnsmasq,以便将来自 docker 容器的 DNS 请求转发到主机上运行的 dnsmasq 守护程序。

为此,您需要通过添加文件 /etc/NetworkManager/dnsmasq.d/docker-bridge.conf配置 dnsmasq 以监听 docker 使用的网络接口

 $ cat /etc/NetworkManager/dnsmasq.d/docker-bridge.conf
listen-address=172.17.0.1

然后重新启动网络管理器以考虑配置文件:

 sudo service network-manager restart

完成此操作后,您可以将 172.17.0.1 (即 docker 中的主机 IP 地址)添加到 DNS 服务器列表中。这可以使用命令行来完成:

 $ sudo docker run -ti --dns 172.17.0.1 mmoy/ubuntu-netutils bash
root@7805c7d153cc:/# ping www.example.com
PING www.example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34: icmp_seq=1 ttl=54 time=86.6 ms

…或通过docker的配置文件 /etc/docker/daemon.json (如果不存在则创建):

 $ cat /etc/docker/daemon.json
{
  "dns": [
    "172.17.0.1",
        "8.8.8.8",
        "8.8.4.4"
  ]
}

(如果 dnsmasq 失败,这将退回到 Google 的公共 DNS)

您需要重新启动 docker 以考虑配置文件:

 sudo service docker restart

然后你可以像往常一样使用docker:

 $ sudo docker run -ti mmoy/ubuntu-netutils bash
root@344a983908cb:/# ping www.example.com
PING www.example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34: icmp_seq=1 ttl=54 time=86.3 ms

原文由 Matthieu Moy 发布,翻译遵循 CC BY-SA 3.0 许可协议

一个残酷且不安全的解决方案是避免网络容器化,并在主机和容器上使用相同的网络。这是不安全的,因为这使容器可以访问主机的所有网络资源,但是如果您不需要这种隔离,这可能是可以接受的。

为此,只需将 --network host 添加到命令行,例如

$ sudo docker run -ti --network host mmoy/ubuntu-netutils /bin/bash
root@ubuntu1604:/# ping www.example.com
PING www.example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34: icmp_seq=1 ttl=55 time=86.5 ms
64 bytes from 93.184.216.34: icmp_seq=2 ttl=55 time=86.5 ms

原文由 Matthieu Moy 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题