Docker容器无法解析localhost

时间:2016-10-10 19:30:45

标签: docker dns hosts

我有一个Docker镜像,我是从头开始构建的,而不是基于现有的图像,如centos或ubuntu。计算机上的进程似乎无法解析localhost或计算机主机名,即使/etc/hosts中存在两者的映射。这是容器上的/etc/hosts文件(由docker生成)的样子:

127.0.0.1   localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3  39b50fcb603a

让我们举个例子,我想使用telnet(其他命令同样失败)连接到端口80.

$ telnet 127.0.0.1 80
Trying 127.0.0.1...
telnet: connect to address 127.0.0.1: Connection refused

这没关系,因为我没有在端口80上运行任何东西。但是,我们假设我使用localhost代替:

$ telnet localhost 80
telnet: localhost: Name or service not known
localhost: Unknown host

这没有意义,因为127.0.0.1localhost的映射是在/etc/hosts中设置的。同样,使用容器的主机名(由docker设置)也会失败:

$ telnet $(hostname) 80
telnet: 39b50fcb603a: Name or service not known
39b50fcb603a: Unknown host

为什么/etc/hosts文件似乎无效?

1 个答案:

答案 0 :(得分:0)

来晚了,但是可以/可以复制:

getent hosts localhost(或getent hosts <dns name>)?

(您还需要在暂存映像中安装getent以及所有运行时依赖项(请检查ldd getent

我在细节上并不强,但AFAIU glibc的gethostbyname将使用NSS作为解析名称的实现(至少在我的操作系统RHEL7上)。即使没有nsswitch.conf,NSS'plugins'libnss_files.solibnss_dns.so仍是默认设置,因此将尝试在运行时动态加载这些共享对象。如果无法在运行时加载这些共享库(因为它们未安装在您的暂存映像中),则名称解析将失败。

因此,从本质上讲,您还需要在映像中安装这些共享库(我也需要libresolv.so,因为libnss_dns.conf是动态链接的依赖项)。有关各操作系统之间差异的详细信息,所以要立即描述准确的过程对我来说并不容易。

您可以使用strace(使用docker run --cap-add SYS_PTRACE <image> strace <command>来专门跟踪正在尝试加载哪些共享对象。

最终备注: 不要与以上问题混淆,后者是运行时动态加载的共享对象丢失。但是,如果要将动态链接的可执行文件安装到容器中,则this blog post描述了一种自动确定/安装链接时间依赖性的方法(它实际上使用正则表达式来解析ldd的输出)