我有一个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.1
到localhost
的映射是在/etc/hosts
中设置的。同样,使用容器的主机名(由docker设置)也会失败:
$ telnet $(hostname) 80
telnet: 39b50fcb603a: Name or service not known
39b50fcb603a: Unknown host
为什么/etc/hosts
文件似乎无效?
答案 0 :(得分:0)
来晚了,但是可以/可以复制:
getent hosts localhost
(或getent hosts <dns name>
)?
(您还需要在暂存映像中安装getent
以及所有运行时依赖项(请检查ldd getent
)
我在细节上并不强,但AFAIU glibc的gethostbyname
将使用NSS作为解析名称的实现(至少在我的操作系统RHEL7上)。即使没有nsswitch.conf
,NSS'plugins'libnss_files.so
和libnss_dns.so
仍是默认设置,因此将尝试在运行时动态加载这些共享对象。如果无法在运行时加载这些共享库(因为它们未安装在您的暂存映像中),则名称解析将失败。
因此,从本质上讲,您还需要在映像中安装这些共享库(我也需要libresolv.so
,因为libnss_dns.conf
是动态链接的依赖项)。有关各操作系统之间差异的详细信息,所以要立即描述准确的过程对我来说并不容易。
您可以使用strace
(使用docker run --cap-add SYS_PTRACE <image> strace <command>
来专门跟踪正在尝试加载哪些共享对象。
最终备注:
不要与以上问题混淆,后者是运行时动态加载的共享对象丢失。但是,如果要将动态链接的可执行文件安装到容器中,则this blog post描述了一种自动确定/安装链接时间依赖性的方法(它实际上使用正则表达式来解析ldd
的输出)