症状是:主机具有适当的网络访问权限,但在容器内运行的程序无法解析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
(泊坞窗图片mmoy/ubuntu-netutils是基于Ubuntu的简单图片,其中包含ping
和host
,因为网络已损坏而且我们无法{{1}这些工具)
问题来自于docker自动将Google的公共DNS配置为容器内的DNS服务器:
apt install
这只适用于多种配置,但显然不适用于主机在某些防火墙规则过滤Google公共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
中明显的DNS服务器是/etc/resolve.conf
,即localhost。nameserver 127.0.1.1
并不起作用,因此docker会回退到Google的公共DNS,这也不起作用。可能有几个原因导致DNS在docker容器中被破坏。这个问题(和答案)涵盖了以下情况:
127.0.1.1
。如果输出为空,则表示您没有运行dnsmasq。ps -e | grep dnsmasq
之类的条目。如果它包含nameserver 127.0.1.1
,则您可能正在运行nameserver 127.0.0.53
而不是dnsmasq。如果是这样,您将无法使用解决方案将DNS请求转发到dnsmasq(使用systemd-resolved
的DNS请求)。 systemd-resolved hardcodes the fact that it listens only on the 'lo' interface hence there's no easy way to adapt this solution。以下其他答案适用于systemd-resolved。listen-address=172.17.0.1
。如果它失败或超时,那么你处于这种情况。在此配置中获得正确DNS配置的解决方案是什么?
答案 0 :(得分:16)
一个干净的解决方案是配置docker + dnsmasq,以便来自docker容器的DNS请求转发到主机上运行的dnsmasq守护程序。
为此,您需要configure dnsmasq to listen to the network interface used by docker添加文件/etc/NetworkManager/dnsmasq.d/docker-bridge.conf
:
$ 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
答案 1 :(得分:1)
残酷且不安全的解决方案是避免网络容器化,并在主机和容器上使用相同的网络。这是不安全的,因为这可以访问容器的主机的所有网络资源,但如果您不需要这种隔离,这可能是可以接受的。
为此,只需将host www.example.com 8.8.8.8
添加到命令行,例如
--network host
答案 2 :(得分:1)
由于此处自动DNS发现有罪,您可以覆盖泊坞窗配置中的默认设置。
首先,获取dnsmasq正在使用的DNS服务器的IP,例如:
$ sudo kill -USR1 `pidof dnsmasq`
$ sudo tail /var/log/syslog
[...]
Apr 24 13:20:19 host dnsmasq[2537]: server xx.yy.zz.tt1#53: queries sent 0, retried or failed 0
Apr 24 13:20:19 host dnsmasq[2537]: server xx.yy.zz.tt2#53: queries sent 0, retried or failed 0
IP地址对应于上面的xx.yy.zz.tt
占位符。
您可以使用docker run
选项在--dns
时间设置DNS:
$ sudo docker run --dns xx.yy.zz.tt1 --dns xx.yy.zz.tt2 -ti mmoy/ubuntu-netutils bash
root@6c5d08df5dfd:/# 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
64 bytes from 93.184.216.34: icmp_seq=2 ttl=54 time=86.6 ms
此解决方案的一个优点是没有涉及配置文件,因此没有因为特定配置而忘记配置并在以后遇到麻烦的风险:当且仅当您获得此DNS配置时输入--dns
选项。
或者,您可以将它永久地设置在Docker的配置文件/etc/docker/daemon.json
中(在主机上创建它,如果它不存在的话):
$ cat /etc/docker/daemon.json
{
"dns": ["xx.yy.zz.tt1", "xx.yy.zz.tt2"]
}
您需要重新启动docker守护程序才能将daemon.json
文件考虑在内:
sudo service docker restart
然后你可以查看配置:
$ sudo docker run -ti mmoy/ubuntu-netutils bash
root@56c74d3bd94b:/# cat /etc/resolv.conf
nameserver xx.yy.zz.tt1
nameserver xx.yy.zz.tt2
root@56c74d3bd94b:/# 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.5 ms
请注意,这会对配置文件中的DNS IP进行硬编码。如果您的计算机是连接到不同网络的笔记本电脑,则强烈建议不要这样做,如果您的互联网服务提供商更改了DNS服务器的IP,则可能会出现问题。
答案 3 :(得分:1)
一种方法是对容器使用user defined network。在这种情况下,容器的/etc/resolv.conf
将具有名称服务器127.0.0.11
(也就是Docker的embedded DNS server),它可以将DNS请求正确转发到主机的环回地址。
$ cat /etc/resolv.conf
nameserver 127.0.0.1
$ docker run --rm alpine cat /etc/resolv.conf
nameserver 8.8.8.8
nameserver 8.8.4.4
$ docker network create demo
557079c79ddf6be7d6def935fa0c1c3c8290a0db4649c4679b84f6363e3dd9a0
$ docker run --rm --net demo alpine cat /etc/resolv.conf
nameserver 127.0.0.11
options ndots:0
如果使用docker-compose
,它将自动为您的服务设置自定义网络(文件格式为v2+)。但是请注意,尽管docker-compose
在用户定义的网络中运行容器,但仍会在默认网络中构建容器。要将自定义网络用于构建,可以在build configuration中指定network
参数(需要文件格式v3.4+)。
答案 4 :(得分:0)
由于dnsmasq
是问题,因此一个选项是在主机上禁用它。这可行,但会禁用主机上运行的所有应用程序的DNS缓存,因此如果主机用于docker以外的应用程序,这是一个非常糟糕的主意。
如果您确定要采用这种方式,请卸载dnsmasq
,例如在像Ubuntu这样的基于Debian的系统上,运行apt remove dnsmasq
。
然后,您可以检查容器中的/etc/resolv.conf
是否指向主机使用的DNS服务器。
答案 5 :(得分:0)
我只需要昨晚处理这个问题,最终想起了docker run有一系列处理它的选项。我使用--dns来指定我要容器使用的DNS服务器。像冠军一样工作,无需黑客我的Docker主机。域名和搜索后缀还有其他选项。
答案 6 :(得分:0)
我在我们的 docker 容器中遇到了 DNS 解析器的问题。我尝试了很多不同的东西,最后我发现我在Hostgator 中的 VPS 没有安装默认 NetworkManager-tui (nmtui),我只是安装并重新启动它。
sudo yum install NetworkManager-tui
并使用默认 DNS 将我的 resolv.conf
重新配置为 8.8.8.8
。
nano /etc/resolv.conf